#[WIP] LobbyCompatibility

1 messages · Page 2 of 1

lament perch
#

okay, still can't really tell, but I think there may be a lot more instances of "LCChallengeFile" than I thought

#

Imma be doing a lot of multitargeting lol

cyan flame
#

okay i got the resouce sprite loading thing

lament perch
#

neat

sonic arrow
#

big ass triangle with an exclamation mark in it

lament perch
#

time to figure out how to clean this up

[HarmonyTranspiler]
[HarmonyPatch(typeof(MenuManager), nameof(MenuManager.SetIfChallengeMoonHasBeenCompleted)), HarmonyPatch(typeof(MenuManager), nameof(MenuManager.EnableLeaderboardDisplay))]
[HarmonyPatch(typeof(SaveFileUISlot), nameof(SaveFileUISlot.Awake)), HarmonyPatch(typeof(SaveFileUISlot), nameof(SaveFileUISlot.SetChallengeFileSettings))]
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.Start)), HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.SetLobbyJoinable)), HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.SaveGameValues))]
[HarmonyPatch(typeof(StartOfRound), nameof(StartOfRound.SetTimeAndPlanetToSavedSettings))]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
sonic arrow
#

uhh what the fuck

#

you know what, if it works it works

lament perch
#

8 different methods need to run through the same transpiler Shrug

#

(technically 10, but two are ran through it elsewhere)

sonic arrow
#

then split it into 1 method for each transpiler

lament perch
#

like have 8 instances for the same transpiler or 8 transpilers that call the same method?

cyan flame
#

is that everywhere the string is hardcoded

lament perch
#

yep

#

other than two constants

#

that aren't ever used

cyan flame
#

probably no way around the MegaMethod then

lament perch
#

this is a cleaned up version

[HarmonyTranspiler]
// Normal Menu Manager methods to patch
[HarmonyPatch(typeof(MenuManager), nameof(MenuManager.SetIfChallengeMoonHasBeenCompleted))]
[HarmonyPatch(typeof(MenuManager), nameof(MenuManager.EnableLeaderboardDisplay))]
// Save File UI Slot methods to patch
[HarmonyPatch(typeof(SaveFileUISlot), nameof(SaveFileUISlot.Awake))]
[HarmonyPatch(typeof(SaveFileUISlot), nameof(SaveFileUISlot.SetChallengeFileSettings))]
// Game Network Manager methods to patch
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.Start))]
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.SetLobbyJoinable))]
[HarmonyPatch(typeof(GameNetworkManager), nameof(GameNetworkManager.SaveGameValues))]
// Start of Round method to patch
[HarmonyPatch(typeof(StartOfRound), nameof(StartOfRound.SetTimeAndPlanetToSavedSettings))]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
#

and then I can't really see if the leaderboard patch works correctly

#

also unsure if this can be unpatched

#

likely to cause errors

cyan flame
#

could you patch ES3?

lament perch
#

for some

cyan flame
#

just a hardcoded string check on the save/load methods

lament perch
#

unless I just turn it so anytime it tries to set/retrieve LCChallengeFile, give it LCModdedChallengeFile

#

then it probably would work

#

lemme see rq

cyan flame
#

you could probably do that, just like

#

if (ref path == "LCChallengeFile")
path = MyReplacementMethod()

MyReplacementMethod() =>
return ModsEnabled ? "ModdedLCChallengeFile" : "LCChallengeFile";

lament perch
#

that probably would have been easier...

cyan flame
#

now you've gained newfound transpiler knowledge, all part of the journey

lament perch
#

* * * I can patch async methods now * * *

#

yay :(

cyan flame
#

i will need that tech once i start messing with lobby filtering

#

or whoever does

lament perch
#

I'll leave the method in

#

currently just in the plugin class

cyan flame
sonic arrow
lament perch
#

a few really aren't necessary, more to just separate up the code to make it easier to read (while providing info if you somehow don't understand some of the code)

sonic arrow
cyan flame
#

i might crunch them, they don't fit super stylistically

#

and the checkmark should either not be there or be something else

lament perch
#

how well does harmony deal with overloads?

cyan flame
#

wdym

lament perch
cyan flame
#

those should be fine, you might just have to specify a type array for each overload

#

generics might be a little weird but i'm sure it's possible

#

i think most of the trouble for generics is when you only want to patch a specific value of T but it won't matter here

lament perch
#

wait I might be able to patch a lower level

cyan flame
#

yeah if they're all just calling one method at the base

#

you can probably just patch that

#

how are we feeling about a layout like this chat

lament perch
#

what about a similar color scheme to what the game has

#

as in a darker background and lighter text

cyan flame
#

yeah, it could probably look more like the game's alert panel

#

the actual structure of displaying mods is going to take some thinking

#

because people WILL have like hundred-mod-long diffs

lament perch
#

how hard is it to create a scrollbar?

cyan flame
#

shouldn't be too hard, i have some code for it already in lethalrebinding

#

the UX implications of putting a scrollbar into a hover modal is kind of weird tho

#

maybe a more details option or something? idk
i would like a quick, at-a-glance way to check other people's mods

#

max posted this, I think it'd work great on a disconnect #1194412635932856440 message

#

need to do some thinking for something easily digestible though

lament perch
#

maybe display how many mods are incompatable, and display the first 6/8?

cyan flame
#

perhaps, maybe you get the small list on hover
but if you want the full disconnect screen you would click the icon

lament perch
#

okay yeah

#

was about to suggest the icon thing

cyan flame
#

i would love some way to integrate with r2modman profile codes but

#

probably out of scope for now

lament perch
#

yeah that would be a nice feature to add at some point, but not rn

#

just a quick thought I want to write down for future reference on that topic:
should we only have the mods that are necessary, or all mods the server host has?

cyan flame
#

I think all mods should be displayed somewhere

#

but in the "at-a-glance" modal, probably just necessary ones

lament perch
#

okay I have the leaderboard patches down to two ~17 line files

cyan flame
#

terrible realization chat

#

the game's lobby text spacing is very inconsistent

lament perch
#

it's anti-aliasing I think?

cyan flame
#

could be

lament perch
#

that and it being on sub-pixels

cyan flame
#

there's a lot of subpixel fuckery, some bits are 2-3 pixels off

#

i think I like this spot for the icon but i'll have to play with it more

lament perch
#

yeah that looks good

lament perch
#

@sharp ridge are we going to use Lord's GameLibs, or a user file directing to a dependencies folder/managed folder

#

just so I know which to use for the PR for leaderboards

sharp ridge
#

Lord's seems fine imo?

lament perch
#

kk

sharp ridge
#

The user thing was moreso for me personally / I wanted to know how to do it

#

Lord's seems more long-term maintainable though

lament perch
#

hmm I think I need at least a publicized assembly for facepunch.steamworks

#

or some weird c# shenanigans to get it anyways

#

lemme try something

sharp ridge
#

That's part of Lord's, no?

lament perch
#

it's not publicized

sharp ridge
#

I'm using it in my patches and only using Lord's

#

Ah

#

I'm personally not super iffy about having some patches not use nameof tbh

lament perch
#

I can't even access the class without publicizing it lol

#

if need be I can easily manually patch it

cyan flame
#

maybe just slap some reflection in for now

lament perch
#

can I use that in an attribute or just through manual patching?

cyan flame
#

you could use [TargetMethod]

lament perch
#

ah yeah

cyan flame
#

like up here

lament perch
#

has anyone used the challenge thing yet?

cyan flame
#

i haven't tried it

#

is it pushed? i can try a run later tonight

lament perch
#

the save files should be separate so I should be able to try both rq

#

I'll push it in a little

#

okay yeah it's not too competitive just seeing it rn

#

you can continously restart

cyan flame
#

i thought you just got one shot

#

is it only one submission

lament perch
#

I'll check again, but I don't think so

#

didn't see any checks to make sure you only submit once

#

also wtf is the insanity noises now

#

heard a loud ass laugh

#

works

cyan flame
#

good stuff

#

i might add a (Modded) somewhere in the top text

lament perch
#

making pr

cyan flame
#

so people know it's a different leaderboard

lament perch
#

ayy

#

PR's up

cyan flame
#

does this compile you for locally

#

oh, i probably don't have the c#12 feature

#

any chance you could change it to new Type[]{x,y} just for older net sdk compatibility lol

lament perch
#

sure thing

#

pretty sure adding <LangVersion>preview</LangVersion> would also allow it for at least net 7 sdk lol

#

but I changed it to new Type[] { /*...*/ }

cyan flame
#

seems to work

#

took a while to not get immediately stomped by that giant

lament perch
#

I just jumped off the ship before it landed

cyan flame
#

fair

cyan flame
#

it's meant to just be tried as many times

#

so you can get the best possible score

lament perch
#

learn the layout, have a team of 50 people each grab 1 scrap

#

then kill 49 of them and collect their bodies

cyan flame
#

insane strats

#

maybe not now, but do you think it'd be worth separating the leaderboards even more in the future

lament perch
#

I was thinking about it

#

but how much is too much?

#

we could add a leaderboard attribute to the thing and allow mod devs to decide if they want a separate leaderboard

cyan flame
#

maybe, i just don't want it to be overkill

#

should the lobby expansion mods have separate leaderboards? maybe!

#

but every mod that changes gameplay in any way would probably be too much

lament perch
#

lets boil it down to the top 10 mods that change gameplay dramatically

#

if that even

cyan flame
#

10 is so many permutations

#

even like 5 would probably feel a bit too empty

#

might be better to just keep it simple

lament perch
#

I think just 2 then

#

(normal) modded and 5+ modded

#

as in 5 or more people

cyan flame
#

yeah that might work

lament perch
#

would be cool if we could tack on people's r2 profile codes/modlist, but that's likely not possible

cyan flame
#

you could have it be user-inputted into a new box here

#

but, it would introduce other problems

#

including people putting fake data, or r2 codes with malware hidden somewhere

lament perch
#

yeah

#

should be something we look into at somepoint

#

cause it would be cool to have like osu!'s leaderboard thing where it shows what mods they use

cyan flame
#

oh explicitly saying "this leaderboard score used these mods" would go pretty hard
i don't think we should spend time on that for now tho

lament perch
#

yeah

#

later thing

#

I'll make issues for the two "for the future" things just so we can more easily track it

#

theoretically, it should be possible to generate the r2 profile code based off the mod list, no?

cyan flame
#

theoretically

#

i would be worried about pummeling thunderstore too hard though

lament perch
#

true

cyan flame
#

could always talk to mythic if we end up wanting to do that though

lament perch
#

though thunderstore also has their own api on github no?

sharp ridge
cyan flame
#

yeah maybe not

#

although if there's demand it might be handy to provide an attribute or something

sharp ridge
sharp ridge
#

Let's keep the focus of this on reducing conflicts between vanilla & modded lobbies and gameplay.

#

No scope creep

cyan flame
#

fair

lament perch
#

okay yeah

cyan flame
#

after that I don't think there's a ton to do

sharp ridge
#

I'll finish my patches today or tomorrow, and then we can do some testing

lament perch
#

I'll try and figure out some github workflow stuff (cause I need it for my api too)

#

just to make releasing easier

cyan flame
#

nuget support is gonna be a godsend, i would look into hooking that up through CI if you have some time

#

i don't remember if I linked trombloader before but it has all the fancy thunderstore package/nuget CI seutp

sonic arrow
restive radish
#

you could try using the thunderstore api so you can just click on the mod name and it opens the page

#

or even click a button and it installs it if you have the app

lament perch
#

#1194412635932856440 message

sharp ridge
#

Do we want to add a compatibility level that is ClientOnly, but only for modded lobbies?

#

Basically for modders to flag any mods that technically are client only, but might be considered cheating/overpowered in vanilla?

#

So it essentially requires a modded lobby (even if only using this mod)

#

I'm kind of on the fence

dusty root
#

People just wouldn't use it

#

If someone's making a cheat-y mod, they're not gonna mark it as cheaty

#

such that people are unable to use it

lament perch
#

if the default behavior is just no checks, I think adding the modded lobbies check to ClientOnly would work

#

though what lord's saying is true

dusty root
#

I'm a bit confused about what this discussion is about because the behaviour of compatabilty levels on jotunn's docs are really well documented

dusty root
dusty root
sharp ridge
sharp ridge
#

Though it's a niche case regardless

It mostly stems from some debate on the unofficial community where some people draw the line between what is considered "vanilla" / allowed in vanilla advertised lobbies, and what warrants a modded lobby.

sharp ridge
# dusty root wait what? but you are providing the Networkcompatability attribute right?

That discussion was regarding an attribute for custom / mod-defined modded leaderboards. That definitely does not fall inside of the scope of something like this.

We do have a modded leaderboard patch to prevent modded users from interacting with the vanilla leaderboard. But anything more than that is definitely out of scope / should be a separate API/mod.

#

A discussion related to that, as well as other points, can be found further up in chat.

dusty root
#

yeye

dusty root
#

So jotunn, being well-established and loved, makes a very good template

sharp ridge
#

Right, that's cool. And we've definitely taken some inspiration from it (as mentioned at some points in this thread). The modding landscape and game are fairly different though, so some critical thinking and discussing rather than carbon copying is probably a good thing.

sharp ridge
#

E.g. the minimap mod would be a good example. It could be considered a huge advantage over vanilla, but not a traditional "cheat" mod.

#

And as far as I'm aware, it's entirely client-side

#

There's a case to be made that one might want to flag such a mod as "modded lobby only"

#

Though such decisions are obviously up to the modder

#

And providing the option, even if it's a niche case, isn't harmful, imo.

lament perch
#

what about an attribute to force the modded lobby check?

sharp ridge
#

I was considering that as well

#

That might be a good one, rather than adding an enum

#

@cyan flame thoughts?

cyan flame
#

Idk, that's basically what LC-API does right now and people fucking hate that feature specifically

sharp ridge
#

It'd be up to the modder to declare it

dusty root
dusty root
sharp ridge
#

How would vanilla hosts toggle that, though

#

At best we could do a lobby name check and spread the word

#

E.g. "[Vanilla]"

#

Which is somewhat clunky, ngl

dusty root
#

so it is 'not enforced' in all cases

#

ie check disabled

lament perch
#

the client does the enforcement, no?

sharp ridge
#

Well, yeah, obviously. That's the point to providing modders an option to flag a potentially vanilla-intrusive/cheaty mod as modded-only

dusty root
sharp ridge
#

There have been a lot of complaints from vanilla players about modded players joining their games. Even just "QoL" mods.

dusty root
#

it should be both client- and (optionally) server-enforced

dusty root
#

because those people will just not install your mod

#

and continue joining vanilla lobbies

sharp ridge
#

If it's an attribute the mod uses, they can't use the mod, so that... fixes that?

#

Taking cheaters / mod modifiers into account is pointless for this argument for hopefully obvious reasons.

#

This would be about the common / general case

dusty root
#

it's not an argument, it's a discussion

sharp ridge
#

The argument is pointless for the discussion as well 😅

#

@lament perch, were you onboard with the idea, or do you think it's something we shouldn't chase?

#

It's fairly simple to add to the currently implemented check / system.

cyan flame
#

I don't think it's a bad idea to have some clientside mods marked as "cheaty", but actual implementation wise I'm not sure the best way

because all the following use cases should (ideally) be supported:

  • people in private lobbies playing with friends who allow it
  • people hosting modded public lobbies who don't allow it
  • people hosting low-stakes public lobbies who do allow it
  • people in vanilla who don't allow it
  • people in modded (without LobbyCompatibility installed) who do allow it
sharp ridge
#

I can see the argument about it being annoying (aka how LC_API has it), though at the same time - if a modder wants to flag their mod like that (which seems to be the case - considering the usage of the LC_API feature) I feel like the option should be provided?

lament perch
#

this may be getting too complex but what about the attribute for mods and a tag for lobbies that can override it

sharp ridge
#

That might be annoying as well, though.

cyan flame
#

Yeah idk

#

I wish there was a way to differentiate between vanilla lobbies and people without the mod

sharp ridge
#

There is

#

Lobby metadata

#

I already add a "modded" field to lobbies using this mod

#

Oh, whoops

#

Misread

cyan flame
#

fair

sharp ridge
#

To my knowledge, there's no real way of checking it?

cyan flame
#

like 98% sure there isn't

sharp ridge
#

You might be able to guess based on the connection erroring out

#

Though that's not a guarantee

#

The best thing we can hope for is mass adoption of this mod ✨

#

Which would be fairly easy for the majority of cases if most APIs add it as thunderstore dependency tbh

cyan flame
#

if we wanted an easy in-between solution, we could just have:

  • cheaty attribute
  • host has an "allow cheaty mod" toggle when creating a lobby
  • follow LobbyCompatibility cheatymod settings
  • make no attempt to disallow cheaty mods in vanilla/old mod lobbies to minimize the amount of things that break
sharp ridge
#

Might veer into too niche / vague of a terrain tbh

cyan flame
#

I think we should worry about it later

sharp ridge
#

Agreed

lament perch
#

yeah

cyan flame
#

Same with the specifics of the enums, I'd rather just make Something that works and have a discussion before a proper release

sharp ridge
#

The enums are simple enough to change anyway

lament perch
sharp ridge
#

I can toss out a poll on the unofficial community before release

cyan flame
#

once it's out they're probably stuck that way tho

lament perch
#

yeah

sharp ridge
#

Yeah, needs a community poll for sure

cyan flame
#

i'm curious what the jotunn devs would think

#

if there's anything they would change with a do-over, or if they'd just pick the same enum they've been using

lament perch
#

would be intersting to know what they think

cyan flame
#

i also got that an unpolished version of that thing working, i just need to clean it up a bit and add an "on click" modal

#

we still need a diff/result datatype or something for display, whenever you get around to those patches @sharp ridge

#

i think the working idea is to display the first 6-8 incompatible/different mods in the hover
then show the full list in a bigger window if you click the button

dusty root
#

but it seems you might have changed your mind

#

To some degree

dusty root
#

Yes, I get where you're coming from when talking about vanilla hosts

sharp ridge
#

There's no way to detect this in any case. It's a moot point

dusty root
#

I think most of those people aren't clever enough to do anything more than install the extra mod 😅 but I agree with you in those cases you listed

sharp ridge
#

Anyway, let's move on / back on track

dusty root
#

I'm saying I think mitigation for the case where extra (cheaty) mods are blatantly added would be good

lament perch
#

how does the harmony priority system work?

#

want to make sure any leaderboard mod can override the leaderboard & challenge save file patches

#

(specifcally letting other prefix patches override the changing of parameters)

#

like do other prefix patches with lower priority get the original parameter or the modified parameter?

dense forum
#

It uses priorities then whichever was first loaded for that priority afaik

lament perch
#

say a mod has normal priority, if I want it to change the parameter before this mod's patch attempts to change it, would I want the patch to be higher or lower priority

#

specifically this patch checks a string to see if it either starts with a certain string or is equal to another string before modifying it

dense forum
#

higher priority is ran sooner

lament perch
#

I'll set it to the lowest priority then

sharp ridge
#

I've most of my patches set to run last

lament perch
#

yeah I was reading on the harmony priority system and it seems sorta finnicy in terms of what priority you want to allow other mods to have actual impact in the game

#

like changing the result of a function, you want the mod that impacts the game to run last

#

unless you only modify it slightly, then maybe you don't

#

though I think I understand it now

sharp ridge
#

Hey, sorry for the delay. My rabbit was showing some concerning signs, and I spent the day watching her to make sure everything is okay. @lament perch @cyan flame

lament perch
#

np

#

she doing okay?

cyan flame
#

no rush, hope she's doing alright

lament perch
#

btw, added a draft pr for github workflows courtesy of @dusty root

#

probably got some stuff wrong, hence a draft pr

cyan flame
lament perch
#

ye that looks good

cyan flame
#

it should work with challenge moons too but nobody is hosting one

lament perch
#

is it that

#

or that no one is hosting a modded one

cyan flame
#

nah it's that i found one

lament perch
#

wait no you don't have that

cyan flame
#

the join button being orange is very bothering

lament perch
#

you can't change?

cyan flame
#

i could, idk if it's in scope

#

since it's a base game "bug"

lament perch
#

oh is it?

cyan flame
#

think so

lament perch
#

oh wait

#

I understand

#

you didn't change the color of challenge servers

#

(I haven't seen them yet)

cyan flame
#

yeah, just made the button go along with the theme

#

which the join button does not do

lament perch
#

lol

#

btw do you have any specific assembilies you are using?

cyan flame
#

i didn't add any, but i had to add some embeddedresources

lament perch
#

oh okay

#

ye no prob

sharp ridge
lament perch
#

that's great!

dusty root
#

there's only one I!!

sharp ridge
sharp ridge
#

But yeah, assuming she remains alright, tomorrow I should have most of the day for working on this.

cyan flame
#

sounds good, hopefully it turns out to be nothing

cyan flame
sharp ridge
#

I hope so 😅

#

You'll have done your part damn well

#

I ain't taking any credit for that excellent UI work

cyan flame
#

the question remains if I will actually figure out a way that makes sense to display the diff lmao

sharp ridge
#

I'd suggest experimenting with line-by-line colouring

#

Green / Yellow / Red

lament perch
sharp ridge
#

That'll be useful for a proper diff

cyan flame
#

could definitely try line-by-line coloring, might experiment with some icons too

#

scrollrect is probably going to be a must because some people install like 140 mods

sharp ridge
#

Yup

#

Or a note that the full diff can be found in a specific file or the logs

cyan flame
#

it would be really cool to generate like, a modpack or r2modman profile code based on a lobby's diff

#

but there's a lot of problems that come with that, definitely not for release

cyan flame
#

oh no

#

i forgot how terrible scrollrects are to set up through code

lament perch
#

just increase the resolution of the game to fit the ui

cyan flame
#

i should have just used an assetbundle Clueless

#

actually i can probably just steal the lobby list's scrollrect

#

we're so back

#

damn I barely have to make any adjustments too

lament perch
#

thats nice that zeekerss programmed the mod for you

cyan flame
#

he did all the heavy lifting really

#

i just toggled a few booleans

sharp ridge
#

Bobbie, you're doing the lord's work right now

cyan flame
lament perch
#

that looks good

cyan flame
#

tomorrow I just need to:

  • hook up the hover modlist
  • probably discuss better category names / way of presenting them
  • restructure things to be a bit less messy, and easier to hook into the real impl

not sure how much time ill have the rest of the week, need to get ready for a trip on the 20th-27th

lament perch
#

I feel like I'm not pulling my weight here xd

#

but it looks good

cyan flame
#

i'm just trying to get something out before i go MIA for like ten days probably lol

#

the best thing I made is the random mod name generator for sure

lament perch
#

slight critique, but it would be nice to have an incompatible mod count at the top of the modal

cyan flame
#

agreed, it needs some counters

#

honestly even a "total server mods"/"total incompatible mods" counter somewhere next to the player count could be nice

#

but i'm not sure how much space there is to add more stuff, it's pretty clean right now

lament perch
#

either next to the player count or on the hover thing

cyan flame
#

oh true

#

we could probably cram both of those counts on the hover thing

lament perch
#

off topic, but the bug reports here really need reorganizing

#

like what are you supposed to do with that

cyan flame
#

idk man

#

you should really be required to provide a log

#

if you have 120 mods either there's an exception that makes it obvious, or you're narrowing that down yourself

lament perch
#

ye

#

luckily the dude found the issue himself

#

but still

#

I make great icons /s

cyan flame
#

the L, H, and the W really make that icon

lament perch
#

I tried to do it with (slightly) nicer handwriting

#

but it's hard to do that with a mouse

sharp ridge
lament perch
lament perch
#

forgot to remove the NetcodePatch depend target from the pack thunderstore conditions -_-
will fix when I get back to my pc

dusty root
#

I've opened a GitHub review

lament perch
#

kk thanks

lament perch
cyan flame
#

idk, i just want something that ideally at least 2 people would have access to

#

ideally something we could add people to without worrying about other packages

#

could just use LethalAPI maybe
LobbyLobbers, LobbyLovers, CompatibilityCrew, something short and utilitarian like LCTeam

#

BMX would be funny as an acronym of our names but idk if that's too self-indulgent
i also dunno if it's like, trademarked or taken

lament perch
#

doesn't trademark only apply to things in the same economy, as in like dirt bikes?

#

also it wasn't taken

#

wanna go with BMX? lol

cyan flame
#

i actually don't even think it's trademarked for dirt bikes i think it's a generic term

cyan flame
lament perch
#

@sharp ridge ^

sharp ridge
lament perch
#

bmx it is

#

I'm assuming usernames are MaxWasUnavailable & Bobbie?

cyan flame
#

ye

lament perch
cyan flame
#

probably a future thing, it could be worth looking into adding translation

#

i don't expect there to be like

#

more than 10 strings of text

sharp ridge
#

Should be simple enough

lament perch
#

that would be nice

#

honestly would be cool to have a localization api

#

but that's a whole 'nother project

cyan flame
#

agreed

sharp ridge
#

Someone tried that at some point - never finished it though afaik?

#

I might very well be wrong

#

LocalCompany?

cyan flame
#

good name

#

i don't think i've heard of any localization API for mods at least

#

the subtitles API is probably the closest thing

#

which does have mandarin localization iirc

lament perch
#

yeah that's what I was thinking of

#

but yeah shouldn't be too hard, just a lot of transpiling

#

and stuff with terminal commands

cyan flame
#

XUnity.AutoTranslator is already pretty good for game localization tbh

#

i'm not sure what all it works with (mod strings might not be translated?), i haven't used it recently

#

even just something mod authors can use would be nice tho

something like cs LocalizationString { EN: "X" FR: "Y" CZ: "Z" };

that helps handle switching language/autosetting based on system settings

#

for the mods that have very few strings (most of them tbh) and can find people for translating

lament perch
#

A json file or something that could be read could be cool

#

so all translators have to do is make that file

dusty root
#

and also uhhhhhh intelliJ platform plugins

#

I think langfiles being JSON is kind of widespread

lament perch
#

you saying my idea isn't original? aware

dusty root
dense forum
#

lol

lament perch
#

your... thing?

dusty root
dense forum
#

our thing, yeah

#

the thing we have

lament perch
sharp ridge
#

What's the thing?

dusty root
#

we haven't really told anyone about it yet

dense forum
#

That's the question, ain't it

cyan flame
#

the thing AmeliaWhat

dense forum
#

I mean technically it's not too hard to find

#

lol

lament perch
#

what journey do I have to depart on to locate this marvelous thing?

dusty root
lament perch
#

shouldn't have told me

#

now I'll see your thing

dusty root
#

just don't go shouting it to the heavens pls 🤣

dense forum
#

WIP

lament perch
#

oh huh

#

a new one?

#

try and go away from the bad vibes?

dusty root
#

yea

lament perch
#

I feel ya

dense forum
#

it's also impossible to fix the other one

lament perch
#

can I contribute to your... thing?

dusty root
lament perch
#

honestly don't even know what to contribute lol

dense forum
#

just make note of the current draft PR

#

which has quite big changes

lament perch
#

will say, like the name

dusty root
lament perch
#

(btw recommend OdinSerializer, it's amazing)

dusty root
lament perch
#

ye I remember

dusty root
#

Speaking of that @dense forum I think the best thing for now is to have odinserializer DLL in the repo

#

which we are allowed to do

dense forum
#

base dir?

dusty root
#

in root dir

#

and the ref should be like

#

$(ProjectDir)../libs/OdinSerializer.dll

#

^ hint path

sharp ridge
#

Guys, maybe move this elsewhere

dusty root
#

(sure)

#

idk where tho

#

so we'll continue this another time lmao

cyan flame
#

oh yeah, i'm fine with LGPL if y'all are @sharp ridge @lament perch

cyan flame
#

btw, any thoughts on making errors a bit brighter so it's easier to tell them apart? i do kind of like the cleaner first look

#

something like the second is probably more useful tho

cyan flame
#

hmm, i was racking my head trying to think of a way to like

#

add a filtering option that ONLY filters compatible lobbies
without destroying the steam servers, and ideally doing it all in one query of SteamMatchmaking.LobbyList.WithKeyValue(x)
so it can get as many lobbies as possible in the filtering phase, instead of just getting 50, 45 of which are invalid

#

and it's kind of stupid, but I think you could just add a key/value with all installed required mods?
specifically lowered to the lowest compatible version, and sorted alphabetically
as an additional lobbydata field to the normal modlist

#

eg, say you have the following required mods installed

LethalLib-2.0.0
LethalThings-1.0.0
MoreScreams-1.2.0
LateCompany-1.5.1
#

you could, from the side of both the client and lobby:

  • get all required mods
  • sort that list alphabetically
  • truncate the version to the OLDEST compatible version
lobby.SetData("LethalLib-2.0.0,LethalThings-1.0.0,MoreScreams-1.2.0,LateCompany-1.50", "Dummy");```
#

so in theory, if you do WithKeyValue with your modlist, it will always only return valid lobbies
with the single key check

#

the max key/value limit is 255 (i think, not sure about value)
which isn't a ton, but like

#

instead of passing the entire plugin names directly, what if you hash everything (so it's consistent between clients)
you don't need a long hash either, just something "good enough" to avoid most collisions and it would work in 99.9% of cases

LateCompany-1.5.1 => LateCompany-1.5.0 // Truncate to lowest compatible version so all compatible versions will match
LateCompany-1.5.0 => ba271d80  // Convert to some hash - CRC32, for example
// Sort all hashes
a87abcde, ba271d80, c82ab7312
// Convert into one big string we can publish 
lobby.SetData("a87abcdeba271d80c82ab7312", "Dummy");
// This key should be present for anybody who has EXACTLY those required mods, as they've gone through the same process
// Should be able to just add the following to clients matchmaking
LobbyList.WithKeyValue("a87abcdeba271d80c82ab7312", "Dummy");
#

obviously it's kind of flawed, but I think it would work well enough?
i don't think you even need 8 characters per hash too, it might be fine with less

#

6 characters would be support for checking up to 42 required mods within the character limit

#

and realistically, most people will be running like 1-20 required mods
instead of showing 50 (almost certainly all) incompatible lobbies, it would give a chance to find exact matches first, then fallback to normal matchmaking

#

i guess you could also just hash the entire required mods list at once, idk why i didn't think of that first lmfao

cyan flame
#

anyways, weird backwards 2am thought process disregarded, we should just do something like this

private string GetModsHash(List<PluginInfoRecord> plugins)
{
    using SHA256 sha256 = SHA256.Create();
    string mods = "";

    // Use only mods 100% required by both server and client
    foreach (var plugin in plugins.Where(x => x.CompatibilityLevel == CompatibilityLevel.Everyone).OrderBy(x => x.GUID))
    {
        mods += plugin.GUID;
        mods += plugin.MinimumVersion; // Calculate minimum required version
    }

    return sha256.ComputeHash(Encoding.UTF8.GetBytes(mods)).ToString();
}

private void DoMatchmaking()
{
    string hash = GetModsHash(plugins);
    SteamMatchmaking.LobbyList.FilterDistanceWorldwide().WithKeyValue("JoinableModded", "true").WithKeyValue("ModsHash", hash);

    // First, attempt to load lobbies from this first query
    // If there's more than 50 returned, great! Just use those
    // We still need to run all the normal compatibility checks with the real modlist, but this should drastically reduce the amount of invalid lobbies returned
    // Namely sorting ServerOnly/ClientOptional

    // If zero or few lobbies remain, get the normal list and append that.
    // These will likely not be as compatible, but some people WILL have zero exact lobby matches
    // In base game, normally up to 50(?) lobbies can be shown 
    SteamMatchmaking.LobbyList.FilterDistanceWorldwide().WithKeyValue("JoinableModded", "true");
}```
we'll still need the modlist networked normally ofc, but this will SIGNIFICANTLY improve amounts of compatible lobbies in the matchmaking filter phase
dusty root
cyan flame
#

ye, sha-256 should work just fine

dusty root
#

sha256 in utf8 encoding should be exactly 32 characters actually haha

sharp ridge
sharp ridge
#

Actually, nvm, I see the flaw in that

cyan flame
#

Nah that would work fine I think

dusty root
sharp ridge
#

I feel like there's other cases I might be missing

cyan flame
#

Oh yeah it's not perfect at all

dusty root
cyan flame
#

It would just be a loose first filter though
I wouldn't be surprised if there's hundreds or thousands of modded lobbies, and as-is the compatibility stuff will be great

But it's still randomly picking 50

#

so it would remove a little bit of randomness

sharp ridge
#

That's fair. I'll add a method to the PluginHelper to get a hash of all mods required by everyone?

#

I'll disregard the 4th type for this check

dusty root
cyan flame
#

sounds good, I would only add mods that are 100% guaranteed to be both required on server and every client

sharp ridge
#

Hm

cyan flame
#

so just everyone would work

sharp ridge
#

Yeah, sounds like a safe bet

undone mesa
#

Are there any plans for config syncing or some sort of config difference checking? Like when you have all the required mods and try to join the lobby it will display all the differences in the configs and then there could be a button "Sync & Restart" (since it would probably require a full game restart to work properly), maybe there could be a checkbox on each mod/setting to allow them to ignore specific settings (if something is client side only, like keybinds).

For my own personal plugin I run with my friends I have a code on the main menu (e.g CODE: leaf weather invite) which is a checksum for 1. plugin names and versions, 2. plugin config key values, 3. hash of the DLL files (the plan was to include AssetBundles in this but I didn't get around to it, the only reason I didn't do all files is because UnityExplorer had log files in it so I don't know what other mods might put there). It's based on the BIP39 word list so I am only using the first 11 bits (2048) of the hash for each of the words but I think it's significant enough for our use-case.

I just did something like this for the config (to give you an example of how to get the config values)

private static string GetConfigString()
{
    StringBuilder result = new StringBuilder();

    foreach (BepInEx.PluginInfo pluginInfo in Chainloader.PluginInfos.Values)
    {
        result.Append($"{pluginInfo.Metadata.GUID}@{pluginInfo.Metadata.Version}\n");

        ConfigFile config = pluginInfo.Instance.Config;
        foreach (ConfigDefinition configDefinition in config.Keys)
        {
            ConfigEntryBase configEntry = config[configDefinition];
            result.Append($"\t[{configDefinition.Section}] [{configEntry.SettingType}] {configDefinition.Key}={configEntry.BoxedValue}\n");
        }
    }

    return result.ToString();
}

Sorry if this has been discussed before or if there's some limitation which makes this problematic, I only noticed this thread yesterday and Discord doesn't let me search messages in specific threads

cyan flame
#

at least for now

#

It would be a ton more data to network, and I think defining specific configs/config entries that need to be synced would be a little more complicated

#

I don't wanna make things too complicated to start, because it'll probably take another two months if I added everything I wanted

dusty root
#

I have an idea of how to do it

#

that would be much more useful than the existing config syncing solutions

sharp ridge
#
[Info   :   BepInEx] Loading [LobbyCompatibility 0.0.1]
[Debug  :LobbyCompatibility] Patching...
[Debug  :LobbyCompatibility] Patched!
[Info   :LobbyCompatibility] Plugin LobbyCompatibility is loaded!
[Info   :   BepInEx] Loading [LobbyCompatibilityTest 0.0.1]
[Info   :LobbyCompatibilityTest] Plugin LobbyCompatibilityTest is loaded!
[Message:   BepInEx] Chainloader startup complete
[Debug  :LobbyCompatibility] Plugin metadata: [{"GUID":"LobbyCompatibilityTest","Version":"0.0.1","CompatibilityLevel":2,"VersionStrictness":1}]
[Debug  :LobbyCompatibility] Lobby plugins: [{"GUID":"LobbyCompatibilityTest","Version":"0.0.1","CompatibilityLevel":2,"VersionStrictness":1}]
[Warning:LobbyCompatibility] You are hosting a lobby with required plugins. Disabling vanilla clients from joining.
#

@cyan flame @lament perch

#

Patches work 👌

cyan flame
lament perch
#

so, I think I'm gonna (try and) change the target framework to both netstandard2.1 and net4.7.2 specifically for the nuget package

#

to increase support

sharp ridge
#

Am I good to PR these patches?

#

Or do we want to change anything

#

Still need to verify vanilla blocking & modded joining works, if someone can help me test that tomorrow (or if you two can run a couple of tests rq on that branch)

#

@lament perch @cyan flame

#

I'm at the fitness rn, and will then be out of the house for the rest of the day

#

So I can test tomorrow at the earliest

cyan flame
#

Go for it

#

idk if I'll have the opportunity to test until I'm back from my trip on the 27th

lament perch
#

I'll be on tomorrow

cyan flame
#

might be worth wrangling some other folk from #dev-general

sharp ridge
lament perch
#

just @ me when you're on tomorrow

sharp ridge
#

Will do

#

Should hopefully just be testing 5 scenarios.
Vanilla x Modded
Modded x Modded (not matching mods)
Modded x Modded (not matching mod versions)
Modded x Modded (matching)
Modded x Vanilla

sharp ridge
#

@lament perch

#

(Ping me when you're available)

lament perch
#

I'll be on in a little

lament perch
#

okay I'm on @sharp ridge

sharp ridge
#

@cyan flame just tested with @lament perch. Confirmed it works in all of the above cases

#

Please review

cyan flame
#

if anything needs to change lmk, i will probably be unavailable for the next ~10 days

sharp ridge
#

Sounds good!

#

I'll see about bridging with the diff

cyan flame
#

Hoping to be ready for release by the end of the month, I don't think there's much left to be done besides the diff bridging
and a basic implementation of that hashing & lobby type filtering

#

right before release, i think we have the following to do also:

  • take a second look at the enum names (i'm honestly fine just 1:1 matching jotunn, we should talk to the devs of that and see if they'd make any changes if they had a do-over)
  • take a second look at the final name (is LobbyCompatibility good? or do we want to make it more generic/expandible)
  • somebody will need to write a snippet (to put on the README/wiki/announcements) going over how to add support to your mod
#

i'll make a few issues of things i've been wanting to fix, incase any of y'all have time to work on them (and so they don't get wiped from my memory)
once the leaderboard and UI changes are merged, most of them should be very simple fixes

sharp ridge
dusty root
cyan flame
#

can somebody get in contact with the jotunn devs while i'm gone

#

ideally slap em in here and see if they have opinions on the enums / the idea of just using the ones directly from jotunn

sharp ridge
#

@lament perch

#

Good luck

lament perch
#

lmao

#

okay I'll look into it

gleaming ice
#

Margmas

I think the names are better than in Jotunn, at least the shorter names feel nicer. Although ServerOnly implies it can't be installed on the client and vice versa, maybe something like ServerManaged would fit better?
Otherwise I don't see any mayor cases missing, they are a bit different arranged but somehow the 4 have nearly the same effect than the 5 in Jotunn. Well guess VersionCheckOnly isn't there, but that's rarely used anyway
I'm not sure how lethal company networking is playing out tho, I guess it's not as bad as in Valheim? Rather the host manages all behaviour?
hmm, are there even servers? Host might be a better name if that's not the case

Nah. Server is fine
But the enum is rather flexible anyway, adding a case or even renaming existing levels is easy like it was done in Jotunn

Overall I think it's a good system. For example ServerSync has implemented it a bit different with a minimum required version but that isn't as nice, since you have to keep updating the minimum version separately when only the minor version is synced etc. Or build some concatinated strings, where your version is split into multiple variables 
binding version strictness to the semantic versioning feels natural
#

(all the text is from him)

#

@lament perch Margmas answered (MSchmoecker)

lament perch
#

tell them thanks!

sharp ridge
#

Ey, we did a good job 😄

#

@lament perch @cyan flame

Thoughts on what format is best?

- MyMod—1.0.0 (Need 1.1.0)
- MyMod-1.0.0 (Need 1.1.0)
- MyMod (1.0.0 — need 1.1.0)
- MyMod (1.0.0 — 1.1.0)
- MyMod (1.0.0) — need 1.1.0
- MyMod (1.0.0) — 1.1.0
#

Note the difference between em dashes & normal hyphens

lament perch
#

hmm

#

what about

- MyMod-1.0.0 — v1.1.0 Required
- MyMod-1.0.0 — v1.1.0 is Required
sharp ridge
#

I like that last one

#

Perhaps changing "is" to "was"?

#

Since it might imply less of a "global" requirement

#

Some users might get confused otherwise

lament perch
#

maybe yeah

sharp ridge
#

Minor semantics

#

But gotta keep in mind the very not tech-savvy users

lament perch
#

yep

#

it'd be even better to show

- MyMod-1.0.0 — v1.1.0 is Required to Connect

but that gets too long I think

sharp ridge
#
- MyMod-1.0.0 — v1.0.0 was required

How's this?

lament perch
#

I think that works

sharp ridge
#

We can always change it after some testing. It's just a string after all.

#

Currently refactoring some of Bobbie's code

lament perch
#

ye

sharp ridge
#

Changed the models to records, moving some behaviour out of it

lament perch
#

if there's anything that needs to be done, just lmk

sharp ridge
#

Adding docstrings

#

Hm

#

You could start writing up a wiki article?

#

The basic concept / guide should remain the same, regardless of pre-release changes

#

Modders add the attribute

#

Users can see the diff & whether a lobby is compatible or not

lament perch
#

ye

#

I'll writeup the readme then we can go from there

sharp ridge
#

New PluginDiff version 🙏

using System;
using LobbyCompatibility.Enums;
using UnityEngine;

// ReSharper disable InconsistentNaming

namespace LobbyCompatibility.Models;

/// <summary>
///     Diff between two plugins.
/// </summary>
/// <param name="PluginDiffResult"> The compatibility result of the plugin. </param>
/// <param name="GUID"> The GUID of the plugin. </param>
/// <param name="Version"> The version of the plugin. </param>
/// <param name="RequiredVersion"> The required version of the plugin (null if not required) </param>
public record PluginDiff(
    PluginDiffResult PluginDiffResult,
    string GUID,
    Version Version,
    Version? RequiredVersion)
{
    /// <summary>
    ///     The color of the text to display for this plugin.
    /// </summary>
    public Color TextColor
    {
        get
        {
            return PluginDiffResult switch
            {
                PluginDiffResult.Compatible => Color.green,
                PluginDiffResult.ClientMissingMod or PluginDiffResult.ServerMissingMod => Color.red,
                PluginDiffResult.ClientModOutdated or PluginDiffResult.ServerModOutdated => Color.yellow,
                _ => Color.gray
            };
        }
    }

    /// <summary>
    ///     The text to display for this plugin in the UI.
    /// </summary>
    public string DisplayText
    {
        get
        {
            var name = $"{GUID}-{Version}";

            if (RequiredVersion != null)
                name += $" — v{RequiredVersion} was required";

            return name;
        }
    }
}
#

Old:

#
using LobbyCompatibility.Enums;
using System;
using UnityEngine;

namespace LobbyCompatibility.Models
{
    // just my temporarily implementation of how a diff *could* look 
    // done to get UI logic in place
    // should be easy to swap out with a new/better impl if needed
    public class PluginDiff
    {
        public CompatibilityResult CompatibilityResult { get; }
        public bool Required { get; }
        public string Name { get; }
        public Version Version { get; }
        public Version? RequiredVersion { get; } // only applicable when ServerModOutdated / ClientModOutdated
        public string NameAndVersion => $"{Name}-{Version}";

        // Used for compatibility colors in modlist UI
        public Color TextColor
        {
            get
            {
                // Nice and bright green if we're compatible
                if (CompatibilityResult == CompatibilityResult.Compatible)
                    return Color.green;

                // Red if we're required and not compatible
                if (Required)
                    return Color.red;

                // Gray if it's not required, but also not compatible
                return Color.gray;
            }
        }

        // Display a "Need (version)" prompt for version conflicts in proper full modlist
        public string DisplayName 
        {
            get
            {
                var name = $"{Name}-{Version}";

                // Add the required version to version-based conflicts
                if ((CompatibilityResult == CompatibilityResult.ServerModOutdated || CompatibilityResult == CompatibilityResult.ClientModOutdated) && RequiredVersion != null)
                {
                    name += $" (Need {RequiredVersion})";
                }
                return name;
            }
        }

        public PluginDiff(CompatibilityResult compatibilityResult, bool required, string name, Version version, Version? requiredVersion = null) 
        {
            CompatibilityResult = compatibilityResult;
            Required = required;
            Name = name;
            Version = version;
            RequiredVersion = requiredVersion;
        }
    }
}
#

Whoops, gotta finish the params

#

I added yellow as outdated plugin colour, compared to red for missing plugins

#

Figure it's easier on the eyes to skim through what mods you're missing vs what mods just need an update, rather than both of those cases having the same colour

sharp ridge
#

Thoughts? @lament perch

lament perch
#

I don't really see the point in switching, but if you think it looks cleaner go ahead

#

I do think the colors should be configurable for colorblind people though

#

like a config with Outdated, Missing, and Compatible as color options

sharp ridge
#

That's a good call

#

Could you create an issue for that?

lament perch
sonic arrow
sharp ridge
sonic arrow
#

ah

sharp ridge
#

Rather than that version being required, period

sonic arrow
#

yeah okay with that context that makes sense

#

thank you for clarifying 🙏

sharp ridge
#

Since some lobbies might run different plugin versions, in some rare instances. Less tech-savvy users might think that specific version would be required universally or whatnot

#

It's minor semantics, but I think it might help prevent situations where a user gets confused tbh

sharp ridge
lament perch
#

yk how the check was skipped on prs

#

this fixes that

sharp ridge
#

Ah, neat

#

Approved

lament perch
#

what does the current attribute look like?

sharp ridge
#
using System;
using LobbyCompatibility.Enums;

namespace LobbyCompatibility.Attributes;

/// <summary>
///     Specifies the compatibility of a plugin.
/// </summary>
[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, VersionStrictness versionStrictness)
    {
        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; }
}
lament perch
#

kk thanks

sharp ridge
#

(Removed the example tag, so Discord's formatting doesn't break)

#

An example would be

#
[LobbyCompatibilityAttribute(CompatibilityLevel.ServerOnly, VersionStrictness.Minor)]
class MyPlugin : BaseUnityPlugin
{
}
lament perch
#

so, are we going with CompatibilityLevel.Everyone or CompatibilityLevel.EveryoneMustHave?

lament perch
dusty root
#

examples of Forge's display (the 2nd isn't a good example since they should be compatible according to semver)

sharp ridge
sharp ridge
#

@lament perch Could you document the lobby metadata format as well?

#

Just in case other libraries decide they want to do their own thing, at least they'll hopefully follow our standard - so multiple implementations can remain compatible

sharp ridge
#

Nearly done with the refactor & tying the diff calculation to the system 🙏

astral lava
#

Will this mod require the host to have it too or just me?

lament perch
#

to get mod info from the lobby, the host will need it, but otherwise, it's entirely client-side

sharp ridge
#

Quick update: mod appears to be functional. We're in the polish & testing phase.

upper thorn
#

I'm fairly sure the loadLobbyListAndFilter patch is incompatible with MoreCompany (since MoreCompany overwrites LoadServerList which results in the loadLobbyListAndFilter enumerator never being ran)

lament perch
#

that mod is just a neverending pain of incompatibility

#

the github for it hasn't even been updated since v1.7.2 (it's on v1.7.6 now)

upper thorn
#

There's a few things BiggerLobby patches that literally has 0 changes to the base game code too 😂

#

But yeah morecompany will likely conflict with the current version of the lobby compatibility mod

lament perch
#

I think we'd have to patch the method he uses

#

to add the coroutine

#

do not look at what I've said in dev general

upper thorn
#

Tbf I might just dm him and ask him to update the GitHub

upper thorn
# lament perch to add the coroutine

Tbf I'll probably just do a PR to fix it when/if he updates the repo since it's also the cause for one of my mods being incompatible with MoreCompany

astral lava
#

so you are saying it's compatible with biggerlobbies? as that's what I use

cyan flame
#

so it'll probably have to be overridden

#

yeah, it's before the tag system

#

i don't think that patch changes a ton right now. so we could probably just disable it
and re-add the "add increased max player amount to UI" bit ourselves

or just ask them to change the patch

upper thorn
cyan flame
#

did you switch it to use transpilers ooc

upper thorn
#

ye

cyan flame
#

nice

sharp ridge
#

@cyan flame time to rename this thread, I think bob_lul

cyan flame
#

[WIP] LobbyCompatibility

sharp ridge
#

Much appreciated! 😄

astral lava
#

Does anyone know when this mod will be released? This will be by far the best mod for the game

lament perch
#

It still currently is being worked on, but we are nearing private testing & then release soon after if all goes well

earnest pilot
earnest pilot
#

the compiler is prob doing some wonky op::implicit bs to make this happen

lament perch
#

👀 did I fuck up again?

earnest pilot
# lament perch wait wdym?

When I yoinked the code here somehow the argument for private static void InitializeLobbySlot(LobbySlot lobbySlot, Transform levelListContainer) LobbySlot lobbySlot was returning the steamlobbymanager

#

since Ldloc_1 isn't the lobby slot

#

its the steamlobbymanager

lament perch
#

well yeah

#

lobby slot is the dup earlier in the transpiler

earnest pilot
#

But isnt that what gets passed into InitializeLobbySlots first arg

lament perch
#

the lobby slot from the dup?

earnest pilot
#

Ohh wait I think I may have misunderstood..?
does

new CodeInstruction(OpCodes.Ldloc_1),
new CodeInstruction(OpCodes.Ldfld, levelListContainerField),```
complete `SteamLobbyManager.levelListContainer`?

On my code I removed `new CodeInstruction(OpCodes.Ldfld, levelListContainerField)` since I had no need for it. Causing SteamLobbyManager to be passed in as `InitializeLobbySlot(SteamLobbyManager_var)` instead of `InitializeLobbySlot(LobbySlot_var)`
#

hold on let me load up dnspy lol

lament perch
#

the ldfld uses up the ldloc_1

earnest pilot
#

That would make so much sense lol

lament perch
#

removing ldfld would then mean the localvar at index 1 is passed instead of the container

#

(which the localvar is steamLobbyManager)

earnest pilot
#

My mistake lol, mb for the false report

#

Yeah that clears it up. I honestly thought the stack for levelListContainerField would already be completed

#

transpilers 🗿

lament perch
#

(since the field isn't static)

#

I've spent so much time in transpilers recently I'm getting pretty well-versed in them

fallow galleon
lament perch
#

We are just about in the demo/testing phase now before official roll-out. I (and others) will be pinging people we believe would be interested in being part of this phase - as well as those we'd be interested in having be part of this phase. If you aren't interested, no problem!

If you are not part of these mentions but are interested, feel free to reach out! We will gladly include those interested in participating in this initial "closed" test.

We just want to start getting this out there being tested to make sure any potential quirks are ironed out before releasing to the public, as well as have a smooth roll-out.

We'd also be glad to answer any questions you may have, and we ideally will have a 24/7 server up soon that you can test against with your mod. We will also have the pre-release NuGet package up that you can use to reference.

README for Usage Reference:
https://github.com/MaxWasUnavailable/LobbyCompatibility?tab=readme-ov-file#for-developers

GitHub

Towards a future with fewer lobby incompatibility errors. - MaxWasUnavailable/LobbyCompatibility

versed inlet
lament perch
#

lmao got timed out with that silent ping xd

fallow galleon
#

@lament perch sprung ya from jail

lament perch
#

🙏

sonic arrow
#

send him to the stairs instead

lusty linden
fallow galleon
#

Five's the limit btw

lament perch
#

just people that I believe would be interested or are interested in getting them into testing phase @lusty linden

I (and others) will be pinging people we believe would be interested in being part of this phase - as well as those we'd be interested in having be part of this phase. If you aren't interested, no problem!

lament perch
#

@dusty root @bright tinsel @coarse grove @tame hill

#

@atomic sentinel @silver flicker

coarse grove
#

refresh me a little

bright tinsel
#

what attributes do I have to throw in my plugin

silver flicker
bright tinsel
#

also the random ping without a big explanation paragraph was probably a bad idea :P

lament perch
lament perch
# coarse grove refresh me a little

Essentially is an attribute or register method modders can use to mark their mod as whether only clients need, only server needs (but clients are allowed), everyone needs, or server needs it if the client has it

#

as well as version strictness

#

The mod/lib will then take that and allow/prevent the client from joining servers based off that information.

#

It'll only block joining if the server has a mod everyone needs while the client doesn't or if there are version mismatches outside of any mod's allowed strictness - specific to that mod, as well as a few other cases - but not any that would prevent mass adoption (there's more to that, I'll explain at another point).

lament perch
# silver flicker ?

thought you were interested (I hope I got the right person) #1202702876930220122 message

atomic sentinel
#

So I take it you pinged us so we can test it?

silver flicker
#

I'm still interested in testing it.

lament perch
coarse grove
#

Down to implement this but

  1. All LLL dev is on hold given the current situation going on

  2. For it to be useful for LLL, I think I would need some sort of function to register AssetBundles to compare against.
    (AssetBundles should probably be directly supported anyway but also might be cool in the future for mods to somehow optionally create a data structure of a provided type and implement a function that's meant to populate them for comparison)

lament perch
coarse grove
#

Forsure and no rush, Just explaining why I might not test this just yet 👍

lament perch
#

yeye no worries

coarse grove
#

in a perfect world ig it would be nice if i could do something like

LobbyCompatability.RegisterComparableDataSet<T[] dataSet>(); or something

then for example it would be generic enough for to use this to check if client and host both have the same moons and dungeons loaded and their set to be registered in their configs (cuz in LLL you can potentially have content installed but not enabled)

#

Also worth noting if necessary I could totally work with just value types and atleast for my usecase it would just be determining if the two datasets are identical, no other further details

lament perch
#

It honestly shouldn't be too hard to at least provide the dataset in the lobby metadata - though we likely will look into doing a bit more than that

dusty root
#

odin serializer

#

/j

lament perch
#

(newtonsoft.json works fine in this case)

dusty root
#

'hee har these bytes are a string'

#

like, as long as 'encode' it with an encoding that has 256 codepoints, each codepoint being 1 byte

#
MyType whatever = null!;
var someBytes = SerializationUtility.SerializeValue(whatever, DataFormat.Binary);
var muahahaIsString = Encoding.Latin1.GetString(someBytes);
var notStringAnyMore = Encoding.Latin1.GetBytes(muahahaIsString);
MyType whateverAgain = SerializationUtility.DeserializeValue<MyType>(notStringAnyMore, DataFormat.Binary);
#

@lament perch Checkmate

#

(Latin1 refers to ISO-8859-1, which is an 8-bit = 1-byte encoding using exactly 256 codepoints)

lament perch
#

you got me 💀 (but people will complain about additional deps & Newtonsoft.Json works just fine so Shrug)

dusty root
#

yeah hehe

lament perch
#

nice to know tho

dusty root
#

yeah i think it's worth considering for the dataset thing

#

but as is

#

not needed

lament perch
#

we already have a checksum, shouldn't be too hard to add to that/replicate that

dusty root
#

don't do the whole dataset thing

#

let modders register content hashes

#

then the modder is free to use whatever they want to generate the hashcode for their mod's content

#

serialize to bytes with [insert library of choice] then MD5sum? plain HashCode implementations? they can do whatever they want

#

you don't need to care

coarse grove
dusty root
#

all they are going to do for you is hash the dataset and compare the hashes

#

you can hash it yourself and they can compare the hashes for you

lament perch
dusty root
#

it's infinitely more flexible

dusty root
dusty root
coarse grove
#

It wasn't a complaint. I think having the option to directly provide the hash makes a lot of sense for people who want to do that, But I (and I think a lot of people who may have fairly light experience in C#) find it a lot easier and readable to just pass in a data set and let LobbyCompatability do the work if were not picky on how the sausage is being made.

dusty root
#

the only people who are going to be using the feature are content-registration API authors

#

that is an extreme minority

#

it doesn't make sense for them to waste time implementing a dataset comparator

lament perch
dusty root
#

it would take you 3 minutes to google 'how to make a checksum for a list in c#' and implement it

coarse grove
#

Not to be rude but like, I kinda was asking Xilo. If they don't wanna implement it they don't have to.

dusty root
lament perch
dusty root
#

but yeah either or

dusty root
#

either be rude straight up, or don't say it

lament perch
dusty root
#

Aye I get you

tame hill
#

[ong?

#

ping

lament perch
#

#1194412635932856440 message

tame hill
#

oh, nice

#

i'll toss it on some of my mods that players might want to know about

dusty root
#

also @coarse grove i gotta make sure you know i didn't mean it when i said you're being braindead, you're a smart guy & i love your ideas

coarse grove
# dusty root if you're saying 'not to be rude' you should probably just not say it at all lma...

Ok? don't aggressively answer questions on behalf of someone else. Xilo @'d me for testing so I gave my thoughts on the matter, They can do whatever they want with those thoughts. It's really weird to call me braindead and tell me I can just google how to do it myself when i'm just the giving feedback I thought I was meant to be giving. I know I can do it myself, that's not the point of the feedback.

dusty root
#

i'm sorry you misinterpreted my enthusiasm as aggression, it's a pretty common thing

#

i'm not good at making it obvious which i'm being

coarse grove
#

I know we chill

tame hill
#

i certainly have asked before, adding the attribute means that whoever has the mod needs lobby compat as well, right?

lusty linden
#

im glad you guys reconciled before i had to kill everyone

#

🙂

static mica
dusty root
lament perch
tame hill
#

ah, sweet

dusty root
tame hill
#

i might put it on my freecammer mod since that seems like something people may want to know if the lobby host is using

coarse grove
#

you guys are getting clients?

lament perch
#

also weird question @dusty root, if you add an attribute but the runtime doesn't have the reference to the assembly where the attribute comes from, does it error?

dusty root
#

I was about to say that - i'm pretty sure the attribute way is actually the softdep way

#

the RegisterPlugin would require you to do some dynamic stuff i think

#

because that's how uhhh

#

Willis' config mod

#

supports softdeps

#

(attributes )

lament perch
#

lmao cool

tame hill
#

mfw #if has assembly LobbyCompat B)

lament perch
#

register method is still cool for registering multiple things (say for content libs)

versed inlet
#

[BepInDependency("com.willis.lc.lethalsettings", BepInDependency.DependencyFlags.SoftDependency)]?

tame hill
#

so in order to use it as a soft dep, it'd be the attribute or the method?

#

want to be sure

dusty root
#

tentatively

#

the attribute

tame hill
#

alright

dusty root
#

Yeah actually

#

I think it must be the attribute

#

because

#

i can use CodeAnalysis attributes

#

and the runtime doesn't care

#

I think

lament perch
#

you sure? currently seems like it does:

[Info   :   BepInEx] Loading [LethalCompanyHarmonyModTemplate1 1.0.0]
[Error  : Unity Log] Couldn't extract exception string from exception of type FileNotFoundException (another exception of class 'FileNotFoundException' was thrown while processing the stack trace)
[Error  : Unity Log] 
Stack trace:

[Error  : Unity Log] Couldn't extract exception string from exception of type NullReferenceException (another exception of class 'FileNotFoundException' was thrown while processing the stack trace)
[Error  : Unity Log] 
Stack trace:
#

(works with the assembly in question being loaded, doesn't when it isn't)

tame hill
#

i could do a check to see if the user has the assembly, right?

#

e.g a #if thing

lament perch
versed inlet
lament perch
#

it is afaik

versed inlet
#

like #if CPU x86

tame hill
#

really? :(

dusty root
#

it is yah

#

they're called pre-processor directives

lament perch
#

@dusty root you lied to me about attributes

dusty root
#

okay what the heck

#

i don't understand this shit man

lament perch
#

:(

dusty root
#

always need to reference

#

is not the same as 'always need to be present at runtime'

#

or have i read the wrong part

#

I just don't understand how my mods are working with annotations from CodeAnalysis and stuff

#

at runtime

lament perch
#

well I tried it with lobby compat and it didn't work

versed inlet
#
[BepInDependency("lobby company oibnlit or whatever the modguuid is", BepInDependency.DependencyFlags.SoftDependency)]
class MyMod : BaseUnity Plugin {
// ...
if(BepInEx.Bootstrap.Chainloader.PluginInfos.ContainsKey("modguid")) {
  // register it here
}
}

would this not work? its what ive been doing for soft dependeencies is there a better way?

lament perch
#

maybe CodeAnalysis is auto-loaded from dotnet (if I got that right)

dusty root
#

because you'll get a TypeLoadException

lament perch
dusty root
lament perch
#

essentially you need

[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
public static void SomeMethodThatRequireTheDependencyToBeHere()
{
  // stuff that require the dependency to be loaded
}
#

afaik

dusty root
#

I like that it's cleaner than dynamic

tame hill
#

me omw to repackage lobbycompat in all of my mods:

versed inlet
#

this has worked for me for ages?

dusty root
#

Is that function in your plugin class too?

#

or a separate type?

versed inlet
#

the second two are in my config class

dusty root
#

yeahhhhhh

#

so it's basically what Xilo linked

#

Which is a good way of doing it

#

just.. long

#

@lament perch I wonder whether putting the attribute on a type unrelated to Plugin works

#

cos bepinex is gonna try and load the Plugin class right

lament perch
dusty root
#

Yeah i know

#

but like, that's how Willis' config works

lament perch
#

maybe...

dusty root
#

something like uhh

#

wait would assembly attributes work

#

ugh that would be a pain to investigate holy shit

#

I think this would definitely work

#
[Compatibility(typeof(Plugin), ...)]
public static class PluginCompatibility { }
#

but obvs it would be cleaner if the class could be omitted

#

so just

#
[assembly:Compatibility(typeof(Plugin), ...)]
lament perch
#

that would be interesting

#

lemme see

#

(using odin assembly att)

atomic sentinel
#

@lament perch I'd love to test the mod rn but I just finished doing some stuff for my mod and it's 3 am for me, I'll do it later when I wake up. I'll let you know how it goes through here

lament perch
#

np at all, it'll be a few days at least until offical release

lament perch
# dusty root ```cs [assembly:Compatibility(typeof(Plugin), ...)] ```
[Info   :   BepInEx] Loading [LethalNetworkAPI 2.1.7]
[Warning:  HarmonyX] AccessTools.GetTypesFromAssembly: assembly LethalNetworkAPI, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null => System.Reflection.ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
Could not load file or assembly 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
Could not load file or assembly 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
  at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool)
  at System.Reflection.Assembly.GetTypes () [0x00000] in <787acc3c9a4c471ba7d971300105af24>:0 
  at HarmonyLib.AccessTools.GetTypesFromAssembly (System.Reflection.Assembly assembly) [0x0000d] in <474744d65d8e460fa08cd5fd82b5d65f>:0 
System.IO.FileNotFoundException: Could not load file or assembly 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
File name: 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null'
System.IO.FileNotFoundException: Could not load file or assembly 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
File name: 'OdinSerializer, Version=2022.0.0.0, Culture=neutral, PublicKeyToken=null'
[Info   :LethalNetworkAPI] LethalNetworkAPI v2.1.7 has Loaded.

warning, but works

#

though that may be unrelated xd

dusty root
#

maybe a fresh project to be sure?

#

cos yeah, those errors could just be cos your network api does actually use odin 😂

lament perch
#

fine ಥ_ಥ

dusty root
dusty root
lament perch
dusty root
#

i almost didn't suggest it (testing on fresh project)

#

and then i thought 'nah, he'll love the chance to use his template'

#

😂

lament perch
#

already did it once

lament perch
#

does in fact seem to work

[Info   :   BepInEx] Loading [LethalCompanyHarmonyModTemplate1 1.0.0]
[Debug  :LethalCompanyHarmonyModTemplate1] Patching...
[Debug  :LethalCompanyHarmonyModTemplate1] Finished patching!
[Info   :LethalCompanyHarmonyModTemplate1] LethalCompanyHarmonyModTemplate1 v1.0.0 has loaded!
#
[assembly: RegisterFormatter(typeof(LethalCompanyHarmonyModTemplate1.LethalCompanyHarmonyModTemplate1))]

namespace LethalCompanyHarmonyModTemplate1;

[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
public class LethalCompanyHarmonyModTemplate1 : BaseUnityPlugin
dusty root
#

okay awesome

#

I think that'd be the way to go

#

to provide a softdep way to do it

lament perch
#

(will still keep the register method as it's still useful in some cases ahem content libs ahem)

dusty root
#

aye agreed

#

altho i have to say i am still not a fan of it registering a 'mod'

#

😂

lament perch
#

ahem harmony ahem

#

oh

#

you mean that

#

technically a new dungeon/moon would be a mod imo

#

but I see the reasoning in other cases

sharp ridge
#

What?

#

Also, yeah, if anyone has feedback / questions / etc... - you can also ping me ✨

lament perch
sharp ridge
#

Bobbie too, technically, but they're recovering from being dead

#

While I have almost recovered

lament perch
sharp ridge
#

And Xilo still has no excuse for not testing the ModData library bruh_intense (/j)

dusty root
# sharp ridge *What?*

the point of it is that that (assembly) attribute will not prevent a Plugin type from being loaded by BepInEx if the lobby compat DLL is not present

#

It still contains the info you need in the typeof(Plugin) parameter

sharp ridge
#

Interesting

lament perch
#

ye the reason it fails currently is cause the class/type is loaded in

dusty root
#

The confusing part there is that RegisterFormatter is an odin serializer one

#

that xilo was using for quick testing

lament perch
dusty root
dusty root
#

Compatibility was just cos i forgor the correct name

lament perch
#

honestly we could have it without the type and use reflection shit on our end to find the plugin class

#

but eh

dusty root
#

because multi-plugin .DLLs

#

so you'd have no way to correlate them

lament perch
#

true

lament perch
#

Okay, the beta release on GitHub is out! We are currently sorting out issues with the NuGet package ID - which may take a while - so as a temporary measure, you can follow these instructions:

The NuGet package is not currently up due to issues with the package id, so the following will not work. To reference the mod temporarily, use the .dll - available under the zip - as a reference, or download the .nupkg, add that package as a NuGet source in your IDE, and use the following reference:

<PackageReference Include="BMX.LobbyCompatibility" Version="0.1.0-beta" PrivateAssets="all" />

Link to the GitHub release here:
https://github.com/MaxWasUnavailable/LobbyCompatibility/releases/tag/v0.1.0-beta

GitHub

Preface
This is the initial, open beta release of the mod. See the readme for usage.
Note that the NuGet package is not yet v1.0.0, so to reference the beta version, use the following:
The NuGet pa...

#

We will be looking into providing a much easier and cleaner method to soft-depend on the mod. Thank you for helping us smooth out the quirks in this testing phase!

atomic sentinel
#

For some reason I can't access the Features namespace

#

nvm it just let me

#

dunno what happened lol

lament perch
#

huh

#

VS things ig

atomic sentinel
lament perch
#

oh whoops

tame hill
#

mf when publicizer:

lament perch
#

@sharp ridge we want the helper class to be accessible to the public, right? or do we want to make a "wrapper" class that just references the lobby helper class

sharp ridge
lament perch
#

kk, just thought we were already doing so hence the documentation. I'll make a pr with those changes, unless you want to refactor (if you're well) tomorrow

#

also think I have an implementation for the assembly attributes, currently trying to test but my laptop is slow and decided to present me with a black screen

lament perch
#
[assembly: SoftLobbyCompatibility(typeof(TestMod.TestMod), CompatibilityLevel.Everyone, VersionStrictness.Major)]
#

no error when lobby compat is missing either