#archived-networking
1 messages ยท Page 52 of 1
I think everyone is on the same page, just talking about slightly different things here
@jade glacier yeah, i mean protobuf and cap'n'proto are probably close enough to micro-managing your own networking serialization infrastructure, that probably what you lose in bytes you gain by actually shipping ๐
but it's just food for thought
please don't use protobuf for game networking ๐
I mean, you can
but there are bitpackers and such galore to borrow and use
hearthstone could send its updates via email server though, its a card game
Bitstreams are more efficient and faster than capnproto
And you can automate them just as easily
There's no reason to use capnproto or anything alike for network serialization
i think one of the challenges, for example
It's a bad idea
is that your protocol, it will eventually look like cap'n'proto
if you do something something bitstream
all of this matter very little, that layer should be abstracted enough that it should be easy to go in and rethink your serializaiton choices later without breaking anything
All that matters is that you HAVE an OnSerialize and OnDeserialize and that they match up
Yes, for local data storage probably
i know for starcraft it can be controlled via a protobuf API, in real time
What it should be used for
SC2
There are cases if you don't need fast and light data to make things a bit more human readable
Yes, business applications
yeah
Where people use json mostly
But I am very sure Overwatch is not sending human readable anything
hmm
Still no protobufs or alike
thats going to all be bitpacked to the bone
Which btw, isn't readable
but do you think protobuf isn't bitpacked? or cap'n'proto?
proto is bytepacked from what I know of it
It has a pretty decent amount of overhead due to their "encoding"
As per their own documentation
yeah
I don't use any of them, but the point is that you can do what they are doing much tighter if you just get in and implement your own Write()
i mean ultimately, how many Unity real time multiplayer games are comparable to an SC2 custom map, or overwatch
they have a standardized replication system, it has overhead, i think my point is that it ends up looking like cap'n'proto
I make assets, so I don't deal with any one off stuff - so I can't comment
they don't write Write(...) and Read(...)
You don't have to
but making networking assets, I have to bias toward worst case - so I pack everything as tight as I can
they don't annotate or weave
Anyway, I think we have beat this horse. ๐
yeah
If it works, it works
it would be nice to hear from the Unity folks, every now and then, like what the angle is
If it doesn't, replace it with something better
The Unity folks as in, the people that work at Unity?
yes
Unity on the networking front is going get you a lot of silence
The Photon/Exit guys are generally the leaders on these topics
as far as actually implementing usable networking that is in usage
We are all doing similar work, and these topics come up often
This isn't a new conversation ๐
I can guarantee you that people who make high-end network layers aren't going to use some pre-made serializer with overhead
Why would I buy your product if I can slap this on myself for the same result
i suppose the hearthstone people don't count then
it's an interesting conclusion for sure
So, the people that made heathstone are selling their networking api?
Can you show me where please?
its hard to say anything generally, since games can vary from 2 people playing cards to 100 people in a BR
it's probably the biggest unity client multiplayer game
2 people playing cards you could use json
Hearthstone?
yeah i think so
its still 2 people playing turn based cards
yeah...
Not the pinnacle of networking
but the sheer scale of the game...
And besides, saying "game x did it so it must be good" is a pretty damn poor argument
the scale though is all in the backend
yeah, you're right about how important the backend is. like they're not using C# runtime unity servers
yeah, going to agree with @weak plinth - the point of talking in these channels is to come up with best practices.. not all agree on the shitty ones that are popular being good enough
it's like, in order to achieve their scaling needs, they needed a cross-runtime, cross-boundary representation of data that was efficient and flexible
Yes, you can literally make networking with JSON or email...
i'm definitely advocating for a best practice
i suppose though, why didn't they? i mean i think they have the same concerns, conserving bandwidth and all
for a mobile game that works well on LTE
anyway
Hearthstone?
Then you shouldn't advocate for slapping protobufs on a network and calling it a day
it's just stuff to think about
The demands of hearthstone are nill
That's obviously not best practice
its likely a TCP packet like once a second
but surely, the per-server user count
and user facing animations and such
Have you ever worked in business?
yeah i like this backend idea
but the actual conversation is "User did nothing... user did nothing....... user played this card..... user tapped on this house"
With webservers or apps?
The network traffic is also quite low
And has more concurrent users than most games
Uses almost always some bloated format like json
but the backend, you see, is it practical to trade around a specification for what a message looks like as a series of Writes and Reads
If they need more perf, they rather slap some more hardware in the server or put up another server
Than mess about with high-end coding
yeah...
If I were doing hearthston, I would probably start with JSON actually
just so I could debug my traffic easily
is it practical to trade around a specification for what a message looks like as a series of Writes and Reads
Yes, because literally every serializer does this
How do you think JSON works? With magic?
i don't think a protobufs schema looks like a bunch of writes and reads
I'm afraid you are wrong then
It has to be
Memory doesn't magically float to a buffer
maybe we're not sure what a schema means
all networking is a bunch of reads and writes
like a file, that says, this is an int here, etc.
as opposed to a file that says Write and Read
yeah, its going to do all of that internally
Who cares? It's still using a bunch of reads and writes
but its still the same concept
like the difference between a protoc file and a cs file
yeah, i guess who cares
it's all very interesting
I think you need to look up how a system handles memory. That probably clears a lot up
and if it stops working, move to something better. done.
You can't magically get one piece of memory to a buffer without write operations
Even if your library doesn't expicitely say "write"
It's still copying
And I also think we shouldn't forget about work vs profit
Even if hearthstone uses a horribly inefficient network layer, it uses very little for a lot of users
They can easily make enough money to slap some new servers down
@amber trench what are you making?
Definitely not worth the effort in a game like that to make the most efficient networking, for a game that essentially can run on a REST API
Also the case for business applications this
The extra effort to make a fast network layer isn't paid back when the thing is in operation
They rather slap some ready to go networking framework on there and not even bother with it
Performance isn't needed, and if it is, more servers are cheaper than hundreds of hours for developers to develop some propietary solution
Which then no-one knows how to upkeep
Which is also a problem in live-service games
Many propietary solutions that have to live for years on end
Maybe I'll finish a first version of my serializer tomorrow. It's a crude solution, with not top-of-the-line performance. But it's the best tradeoff between performance and ease of use without using codegen or ILWeaving
Haven't run any benchmarks yet, though. So maybe the performance loss will be alright over writing direct writes/reads
@jade glacier When will your project be done?
And are you selling it for ๐ต ?
Which one LOL
Codegen serializer
that's just likely going to end up in with the stuff I am doing for Exit
So, nothing opensource?
Will be hard to stop anyone from just stealing it - but technically won't be open
I don't care if it gets into peoples games, I just don't want to ever be competing with my own code is all
What do you mean competing with your own code?
Like I don't want to see it in Mirror next week LOL
Right now I am just coding in Limbo, since all of the drag and drop networking stuff I have made is slated to become part of PUN2
So its really going to be up to them
But what I am doing is along the same lines as what you are doing
the only hangup is that Unity offers crap for callbacks
And it can handle objects
Finding the right moment to generate code is tricky
I won't get equal to your perf unless I use Cecil
Using Cecil might even be faster. But like I said yesterday, I probably won't be using that
So it's wasted effort on my side
It sounded like you were producing fairly parallel work, outside of the codegen part
The only reason I'd make it is to make it, and have it on git to show off I guess
I was, with ILWeaving. But that's a no-go in IL2CPP
All of the codegen is just to wire up the packing delegates
Need Cecil for that
I'm building something similar to what Wobes' is using
It's a more manual, static approach
But it works too
I never know what madness that guy is up to LOL
but I think we are all doing similar stuff, just slight differences for our usages
he is going way more ECS with his stuff
like doing shadow copies and all of that
I think Wobes is just finding out how he can break his CPU with DOTS
My stuff all originates from the problem of "how do I make stuff that looks like Unet's weaver attributes, but actually can do bitpacking, and is still fast without weaving"
so very different requirements
Why without weaving?
I guess that's a fair point
And there are the dangling questions about IL2CPP I just don't know
The main restriction is I am a mediocre programmer
yeah, that probably is the ideal answer - and someday may revist that part of the codegen
This is with Reflection.Emit for a writer function
It's not too bad if you ask me
It makes exactly one delegate to serialize your entire type
I was able to use generics too
The writer function is just a Write<T>
So technically, you can plug in your own writer implementation in there
As long as it inherits that interface
what's the resulting code you are getting from this?
The IL code?
I suppose you don't just have an example of it hanging around for cut and paste LOL
I need to set aside a weekend to just play with weaving
My main reason for not using it is that I just don't have any experience with it.
static void Main(string[] args)
{
TestWriter writer = new TestWriter();
var wFunc = WriterFuncs.GenerateWriterFunction<TestOBject, TestWriter>();
TestOBject to = new TestOBject();
wFunc(ref to, ref writer);
Console.ReadLine();
}
private class TestWriter : IWriter
{
public void WriteValue<T>(T value)
{
Console.Write(typeof(T));
Console.Write(" -> ");
Console.WriteLine(value);
}
}
This is the bit I used to run it
The IL calls the Writer<T> method, for every field
But uses the actual type instead of the generic
The other thing I don't have my head around is when does this happen in the build process?
This?
It doesn't
That's why it doesn't work in IL2CPP
This is Reflection.Emit and it happens on runtime
That's also why it works a whole lot easier than Cecil.
Reflection knows the current assembly and all of its types
oooh, thought you were saying that this does work
With Cecil you have to "manually" load all the assemblies and containing types
Even the system types
But the IL weaving is the same
The setup just really sucks (and that's why I didn't bother with it)
yeah, that was what I was doing the other day - and tore my hair out with it.
Me too lmao
I thought I could be smart and use .Emit
But turns out it doesn't work
I had it working, but I can't be letting it constantly parse the entire assembly every time someone compiles
Cecil modifies the managed assemblies
https://hatebin.com/qlbuodkvcl
Currently this is being generated
You literally cannot IL weave any later
It works, and I used something similar
But I personally don't like codegen
Maybe if it's really hidden away well, and it gens on build time
Yeah, I am not in love with it, but the alternatives were all running into walls
Gen at buildtime is the problem
Because ORMs use codegen as well
And you don't really notice that, because it's gen on build time
If you gen in OnPreProcessBuild... it doesn't get into the buld
And the genned code is hidden away in your project really well
You could always look at the mirror weaver btw
Since they do cecil weaving
Mine is all hidden away, because its abstracted into that database
but the issue is the timing of it
It's a big damned mess though Cx
That weaver is constantly rerunning, not a fan of that.
They've thrown stuff all over the place and are weaving massive IL functions that they aren't even using
Wait what
the price of invisibility is that its always having to recheck things every compile
Oh shit
That's true
It needs to weave everytime you build
Well, for codegen it's the same
But at least there you can check if it's up to date
And just skip it
check what though?
That was the problem I had
you think "I'll just check if its current"
then you realize that files aren't associated with types
Is there a way to quickly test for changes to types?
No
like a type having been created, or destroyed? or its interfaces and attributes changing?
But maybe hash the type file?
As soon as you make edits you can see the hashes are different
But if they just created a new one?
I mean you end up with a monolith thing trying to monitor stuff
just to avoid a rescan of the asm
Yeah. Well perhaps Entityframework has this
Not familiar, if so yay - I want that
But you know, years and years of development by large teams
I am not aware of any callbacks available in Unity to tell you what changed after a recompile
The first one
It's common in business applications
Java uses Hibernate
Does exactly the same
if its not available to me for this, then its dead to me
These are extremely big frameworks used to communicate with databases
My choices currently are rescan after every compile... or have the users trigger a build
Nothing you can use ๐
The big Unity letdown is that OnPreProcessBuild is too late for codegen
That is where I need to do it
Haven't read this yet
But maybe it's in here
If it works for cecil, it should work for you as well
I'll poke around - need to know what they trigger off of for a callback or something
Damn though
All I am aware of is OnPreProcessBuild
Having to rerun the weaver at every build
which fails
I think that is why it does that
You are making me reconsider making this
there may be literally no other way
If you find a way to code gen or inject at build time... PLEASE let me know
Maybe not. But literally every compile action will get slowed down even more due to reweaving of assemblies
I am just skipping that part for now
I had a tough time dealing with this as well with T4's
Ended up moving them to a specific folder and copying them by hand ๐ฆ
https://docs.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?redirectedfrom=MSDN&view=netframework-4.8 ? @jade glacier
Even with that though... how do you know which types are in that file? and what their attributes/interfaces are?
I would need to know that a file changed that contained a type with my attribute
The latter doesn't matter
and I don't want to regex files for that shit
You're going to have to scan the assembly anyway for types with that attribute
But if you can link the type to a file ๐ค
The goal is to avoid the scan unless you have reason to believe there has been a change that mattered
I did come up with that as a possible
The scan isn't the problem though
The genning is what's going to take the longest time
limit rebuilding to if altered files have an attribute of mine
I'm sure the scan won't take long at all
If the file doesn't have my attribute... I just ignore it
Though scanning a file for a text string... probably not much worse than just rescanning
Didn't think about that ๐ฆ
You NEED to rescan anyway
I don't see any other way to avoid that
Where I will likely land is a full rescan, but maintain a catalogue of types
Time it. I'm sure it won't even take 100ms
and just check for changes relative to my catalogue vs the ASMs
That works
The rescan I think will be unavoidable
You need a rescan for new attributes anyway
You still have to loop the whole thing
all ASMs and ALL types to know what has been added/deleted
I might be able to reduce the number of asms checked, that is stuff I don't know enough about though
I had an editor only SO that was doing that
and I deleted it, so will have to find that in my git and bring it back
Maybe far fetched
But Git knows when files have been updated
But then again
A file =/= a type
You can define multiple types in one file
I think you're going to have to rescan, and compare for changes
Store the current version somewhere as soon as the gen is finished?
Some easy to process information that tells you which types/fields/members you've generated for
Scan again and compare the 2
No good for me, I have no certainty of that. This will by used by god knows who god knows how
Doesn't matter
If they delete the file, regen everything
If they mess up the file, discard and regen everything
you can capture that with Unity calls, they are limited but they exist
you can even stop people from deleting and such with them
You can't expect to make some library that's 100% fool proof
BUT, its all through the editor
so stuff outside of the editor... its dumb
I mean, you can store this version file as an asset, no?
The answer I need is the answer I can't have. I want to generate at build time.
Same as you are storing your genned classes now
I could database the text files yeah
You only need 1 for the current version
The thing for me though is that filewatch has to be faster than Unity on the draw
because if unity gets to the recompile first... it can throw errors since my codegen may now be invalid
Currently I have my codegen capture error messages and it triggers a file delete if they originate in one of my generated files
The process that generates the code should not be the same process that runs the code
But its after the fact, Unity already has thrown a red error to the log, and it stays there for a second
It doesn't run it, it just generates it
Can't you make some editor script shenanigans for this?
But that code contains hard references to fields and such in other classes
So if those classes change, its going to throw errors
I have not found ANY way to beat the Unity processing
and it offers no callbacks I have found that lets you intercede
you can only react to the things after the fact
Well what I mean is
If the process that runs the codegen is separated from the genned code
Compile time errors don't matter
You can just still run the code gen
Unity cares though, unless I misunderstand you
if at any point there are files with invalid references, Unity is going to raise a stink
Uness you mean build time?
Its been my whole week
The problem what you have, and I had
every path I have tried, ended in Unity not giving me a callback I needed
yeah
I had this same problem
I manually deleted files
I capture the errors in the callback
But I wasn't making some public api
and auto delete on that
It works, but it does show that error in the log for about 1 second
Maybe find out how these ORM are doing it
They don't gen code from already existing code, but they gen code from a database schema
The issue I have is that if there is a compile error, Unity is the first to know about it - and I don't get informed until AFTER the log has the error already
Hmm nevermind. ORM's work the other way around
the database won't change much, it just lets you check for changes before making a new file
Code IN the ORM can't ever be faulty
the database has value for that... you can just check to see if the type existed before, and if it matches up on fields, attributes etc.
Saves the codegen step
Or if OnPreProcessBuild let you codegen and compile in time
they need another sooner callback for when builds are started
@gleaming prawn Was talking about something they wrote
Codegen also, but something completely different
Maybe he can help you
they have some luxuries
Why can't you have those?
since they are TOTALLY outside of Mono and such
IL2CPP though?
Not sure, I only was half following that convo
I believe they rely heavily on codegen
that is the fholm way
I mean, if you are only targetting mono (which I guess you aren't) dynamic methods solve your issue in a heartbeat
I have a "passable" option right now, that is that if give them the option to not auto generate, and require a manual hitting of the Generate somewhere... I can easily throw log warnings of "Hey, you are trying to Pack stuff that hasn't been CodeGen'd yet... Be sure to hit the Generate Button"
The other option I can give them is to just let it autogen every time, they just risk a little slower compile times and an occasional log error that clears itself.
It will WORK, its just lame.
I can imagine with lots of types
I prefer a bit more polish than that.
That can have a noticable impact
Its not the end of the world having a Generate button somewhere
Bolt DEMANDS you compile like that every time
Bolt actually has its own Build button I think
Hmm, might be a viable option for Cecil as well
just so I can do what it needs to do before building
Handy thing about Cecil
No compile time errors ๐
It's just not going to work at all
Which can be maddening
half of Gadget's job is telling people why they broke the weaver
since its not always obvious
They should fix that weaver in the first place
It's a mess
They have separated IL weaving for classes and structs for some odd reason
I am at the moment going to just leave the codegen part as is, and finish out the actual serializaiton attributes
And have a function where it passes a byte array down to it
And running some for loops in IL
I mean, comon
It works, so going to just revisit it later
array segment*
a lot of that code came from before array segment existed
Its a step up from nothing
And going to be very hacky if you want to bitpack
But it was a patch
They should just use unmanaged memory already...
Mirror is part of Vis2K's other libs, so has a LONG caboose attached to it
And you know, maybe weaving some generic bitstream interface
So there's actually some possibility to change things
I don't think anything with that is going to be a simple fix
Rather than having to rewrite some entire IL weave method
I think a big problem with Mirror is that it's hobbyists working on it
I personally think that if they were going to tear Mirror apart and do it better, they should do what MLAPI Forge and PUN2 need to do - which is give the whole systems proper tick based timing mechanisms that are core to it all
Rather than professional network engineers
The biggest achilles heal of all of the HLAPI is that they are fully adhoc timing
I can live with questionable data packing, but making it so hard for users to properly respect a sim rate is a real problem
If that were its only problem
How about, 2 threads per connection
I just know what people complain about
Or using managed memory for buffers
the tech guys like NX have bones to pick, but they are not what the average users sees or feels
Or writing per byte to a buffer without even packing
The average user is all "Why is my stuff all jittery"
The average user doesn't even know what they are getting in to
Because your networking has no concept of your sim... you are boned.
Mirror is advertised as some magic solution that makes networking magically happen
And people that don't know any better take this at face value
They all are, but only Bolt and Quantum actually respect simulation
The rest are generally just really messaging platforms
People underestimate how difficult it is to make a game
And infinitely more underestimate networking
Yeah, that is really my only personal beef with Mirror - that it works to keep people at that level
I wanted to make a multiplayer game as well 4 years ago
And here I am, still not having made a single thing
The things Mirror does magically, are things no one should be doing if they want to progress in networking
I've spend 4 years actually (trying) to learn how this all works
And I still don't know anything if I compare myself to the people at NCoders
I started my first game 3 years ago, and a year later I had instead made an Asset Store asset for networking
After that first year I was like "holy shit, no one should have to go through this - I'm making an asset for others"
That's why I'm throwing that blittable serializer on git
I literally can't find an implementation of something like that on the web
And it's something to vital
I share some of my lower level stuff, and I did share NST - because its old and full of bad choices LOL
I'm sure a lot of people can benefit
NST for as bloated as it is - STILL is smoother than anything any of the HLAPIs can do on their own
I find it weird to put something that small on the asset store
(Talking about my stuff)
I think it has a better place on git
Not looking to make any money either
What would I ask, 3 bucks for like a collection of 5 classes
And besides, I don't want that shit that if someone finds an issue I "have" to fix it
its supportable, and obvious in what it does - and needed enough that people who look for it know what it is
I know myself. I will move on eventually and don't want to bother anymore with the past
Yeah, the Asset Store is not a fun place
If people have issues on git, fork it and make it better yourself ๐
You know what I need? For someone to extend Net Sockets to allow send/receive with IntPtr
It's such an immense disapointment to see that it's literally 1 layer abstracted away
No one in the NCoders circle has done that?
It's just literally there in the source code, abstracted under one layer of byte[]
Not that I know of
They use enet or just udp sockets (from C?)
But you currently can't use the net sockets without using byte[]
Could probably make a dll and import the winsock (and the other platform specific ones)
Ugh, I have to go to bed
1.45am and I need to work tomorrow
I'm going to come in so late tomorrow ๐ฆ
I need to get after some house stuff here and get back to coding, im off as well
@jade glacier > since they are TOTALLY outside of Mono and such
The thing is: what we use is 100% compliant, safe and robust to work under Unity IL2CPP (Unity is the target platform of choice, of course).
I don't think we have "luxuries", it's quite the opposite: we need to design stuff with the IL2CPP restrictions, and that is cross platform deterministic also when running from non-unity Microsoft .net (including .net core).
So the question is valid, I thinK: why can't you use similar approaches? I think you can and should...:)
When do you codegen then? @gleaming prawn
We codegen on a visual studio solution, even before the code is inside unity (but also works adding the solution to the unity one)
So we do all this before the unity build with IL2CPP
We codegen as pre-steps (we have our own compiler to do that)
Do you though create serialization out of users mono fields?
This is done automatically as part of the VS toolchain on our customers projects, etc
Do you though create serialization out of users mono fields?
I like to talk C# (or IL), we're agnostic to whereas this is Mono or MS compiler.
That is just one example, trying to get a sense of where your codegen is thing itself to.
What we have is:
- lots of serialization utils (ByteStream, BitStream, similar to what Complex showed here);
- we CodeGen the user fileds (from our DSL), so we also codeGen the serialization for those (super convenient for them);
- we add user callbacks if they need to serialize custom data that they could not express with the DSL (this is very very rare)
We codegen as a pre-step, that's it
The code that's compiled by VS/Mono/Rider/Unity (whatever) is just normal valid C#...
We don't do anything crazy at runtime (runtime is sacred for performance)
Interesting, so you codegen though as people are typing?
The headaches we are having is depending on Unity to trigger the codegen based on the results of its recompiles
The two choices are to constantly re-check the ASMs with reflection whenever something triggers a compile in Unity, or to try to codegen right before building. It sounds like you have avoided that?
@gleaming prawn
Interesting, so you codegen though as people are typing?
No, pre-build event
Standard VS stuff
Where are you capturing that event though?
We're not... By default our users write the simulation code outside the Unity project, on a separate VS solution
In Unity land I haven't been able to isolate how to get that... if the player in Unity hits build or play
No fancy automation on change...
AND, we only need to CodeGen when you change the DSL
So this is not frequnt
I am not familiar with Domain SL in this particular case, I have only ever heard the term loosely a few times before. My lack of programming depth here.
I am assuming you are creating your own workflow in there for creating what becomes Unity code, you aren't "scraping" code for what they have done in their classes, structs and monoB types?
When I was referring to luxuries, didn't mean to make it sound like you have it easy at all - I was more referring to that you have your own workflow, which sounds like what applies in this case. Unless I misunderstand?
In our cases, the worst case example is trying to generate code based on user fields on the fly, or at build time. Like for my stuff I specifically have to be able to generate serialization code based on users fields in MonoBs
Understood
Has anyone used SpacialIOS / have much luck using it?
Hey fellas. figured i'd pop in to ask if any of you know what networking solution i should use for an "mmo" type game (hate using that comparison), but essentially I'm looking to have a persistent world.
To put it simply, I'd like to implement a persistent world. I want to be able to start a server, then all the game data (player positions, inventories, stats, etc) gets saved before the server closes, then when you start a new server you can load the previous save to pick up where you left off.
I'm still new to networking so I'm not too sure where to start aside from trying to work it out with uNet
I wouldn't even really try anything like that right out of the gate. I would give yourself a few weeks to do tutorial on some of the libraries just to get a sense of where you are even starting, and what the language of networking is.
PUN2, Mirror, Forge, Bolt all are places to poke around for getting your toes wet.
The new netcode stuff if you want to get more llapi with things and are planning to do your entire project with DOTS, but its not really ready for new users by any measure.
Gotcha thanks. I've heard good things about PUN2 and it seems like the best free option (just looking to use this game to learn and play with friends so i'd rather keep it simple/free for now). Do you reckon I could convert my simple project from uNet to PUN without much hassle or would it be best to start fresh with PUN?
PUN is an all relay environment, so it has some real perks and real downsides, which would take me 30,000 to explain al the ins and outs of... which is why its best to do tutorials on some of the engines, so that you can even make sense of the nonsense I would type now to explain it all to you.
I would do tutorials for a few of them
PUN2, Mirror and Bolt would give a pretty good indication of the three very different kinds of setups
PUN is relay, no server auth at all
Mirror is Unet, same as MLAPI and to a degree Forge is similar
Bolt is a full stack. It is fantastic IF it matches your game type needs, restrictive if not.
Anyone managed to get Lidgren working in any version of unity 2019?
@dapper spindle https://github.com/lidgren/lidgren-network-gen3/wiki/Unity3D - not used it myself
Yeah latest version of the UnityEngine no longer has certain features that lidgren requires
Ah okay
It has literally just killed our project as I cant find another networking solution that I actually like
Sounds like your stuff is pretty close to transport level if its using lingren currently, shouldn't be hard to swap in transport replacements
hello any one with used photon here need a bit of help
Does anyone know if webgl and Android has crossplatform support with Photon?
@dapper spindle take a look at LiteNetLib, the author actually made it cause he had issues with Lidgren
Making an mmo in unity where the main source of communication will be a mix between tcp/udp and was wondering if there are any tools that are good for this in unity already or if I should just build it from scratch? Mainly from a security or ease of use standpoint.
@weak plinth AFAIK it does support that (if you are talking about PUN or Photon Realtime), as both platforms are support to connect to the servers, and if that works, the communication between them is intermediated fine.
As for Quantum, it doesn't support WebGL at all, as that platform lacks standardized support for native memcpy (which is a requirement for Quantum).
Lidgren has pretty bad perf. There are better options out there, like ENet
@dapper spindle i got lidgren working
its still very usable
is photon not build on it ?
I haven't looked into photon as I believe they use a CCU model, the problem is while in editor I could not get the client to connect and when built as soon as the server starts everything stops working.
i got that running smooth
sending packets and all
i had to use an older version of lidgren before they added threading
well a type of thread lock
hold on its 4:09am and im pretty wasted
See I could send and receive packets in editor as long as I was connected on my own local machine and not over LAN or WAN
Also our networking is threaded so that could be the issue.
i got wwan working
however
what stopped me was i need a global server array or something to host all my netcode
i was thinking do i get mofos to install a client or something and run "hubs"
or find some billionares daugther and make her buy me computers everywhere
many chanllenges
That shouldn't be the issue though I believe the reason for needing central servers was due to NAT Traversal which shouldnt be a problem as a simple port forward should fix the issue
I am currently trying to implement LiteNetLib instead which still isn't going well, its probably something to do with our threading but who knows
ยฏ_(ใ)_/ยฏ
lidgren says that port forwarding standards suck and his code may work and if it doesnt someone should just open a port as it up to the router owner dude... i dont know if thats a cop out
i look at other peoples systems etc like but lidgrens should be fine
im just too tight to go renting servers even if its just for lookups
TBH I want to avoid renting a server just for lookups as if the project flops then its wasted money.
exactly
im going to make more projects and if any stick and support that cause ill push out more lidgren
so many people use lidgren its a solid network layer
for many things
if unity fail us with thier netcode ill be using lidgren... even if i make like a "family lan game" without servers to introduce folks
but im sure unity will deliver eventually, networking is difficult
state sharing through packets distributed accross the world its crazy and we use it for games lol
crazy new concept man. ok its 4:20 am
im out bro
see you tmr
cya
@gleaming prawn Thanks for the answer. @silk nimbus cross platform for webgl and android is supported
Hey, having an unity server build which only loads c# modules that contains logic at runtime and not having to deal with unity editor to re-build every change sounds like a good idea?
Anyone here ever work with Unisave?
im finding very little tutorials about making your first online multiplayer game, i don't even really know what it entails compared to making an offline game. anyone have a good video overviewing how this works in the scope of unity?
In short, you need a way to synchronize everything you need to other players (via a server)
You need something (the server or client depending on the model) to actually make the decisions
And of course you'd need interpolation and such to smooth out the game instances of remote players
@weak plinth I'd suggest you start trying out some multiplayer related stuff with a really basic concept like pong
and that's the absolute minimum considerations to put into a multiplayer game
@junior moat Photon uses a highly customized version of ENET
@mellow beacon Yeah
There's a reason why so many games either don't bother with multiplayer at all, or have a horrible implementation
hm. it's so weird to me that there's like absolutely zero up to date tutorials or explanations about unity multiplayer
if I understand correctly, unity multiplayer is sorta in limbo bc they said "unet is deprecated now, please wait for new network stuff" and,,, have yet to release that?
like, surely bare bones multiplayer example, let's say Pong, couldn't be all that complicated. I watched an presumably outdated UNET tutorial and it seems to be complicated stuff, wrapped up into an easier to work with API
@gleaming prawn is photon not based on lidgren ?
No, it's Enet based.
@junior moat no, as Tobias said here. Not based on lidgren at all. It's enet
@weak plinth many high level API's have severe drawbacks
Such as lack of configurability or performance
right ok but my point is, even the nicely wrapped up APIs don't have any up to date tutorials? what gives?
UNET is dead, and as for the rest
Multiplayer isn't straight forward to make, not even with hlapi's
@gleaming prawn Maybe a silly question, but does your bitstream have functions for signed and unsigned both?
@weak plinth Mirror is the closest replacement for UNet right now. If you have any questions, please join our Discord and we'll be glad to help. UNet tutorials, while a bit dated, mostly line up with Mirror's public-facing API and components...just keep our docs handy to resolve any differences.
https://assetstore.unity.com/packages/tools/network/mirror-129321
Mirror is built and tested for MMO Scale Networking
Do you still have this on there?
I wouldn't exactly call 207 CCU on a Xeon W-2145 8 Cores x 3.7 GHz at 95% cpu "MMO Scale"
But whatever
Depends which transport one uses. Telepathy hits a Unity-imposed limit at 600CCU. Apathy can go much higher because it lives outside the Unity context, but now we're in the realm of where the game's own resource demands are the limiting factor vs. the networking.
What do you mean now we're in the realm
That should always be the case
If your game's networking is using more resources than the actual simulation, you've done something horribly wrong
ok you're nitpicking my choice of phrase now. o/
Maybe use better wording then, so it's understandable
@weak plinth yes, both unsigned and signed, separate functions.
Thanks. I'm browing around a bit which one I should use
You are using a is_writing type right? (reading/writing with the same function)
yes, makes our serializers code smaller, and we're used to this semantics
I've seen it in other projects as well
All the if statements have minimal perf impact then?
(Does make me understand why you use ref value ๐ )
It hasn't been a bottleneck for us.
Let me confirm
A few more...:)
We have our FixedPoint types as well (these are wrapped Int64s, etc)
But for streams we can also serialize strings, of course
We normally don't use strings in runtime high-frequency messages, but the streams are reused for everything, and handshake messages might include GUIDs, etc... Also some infrequent commands may use strings (although we don't recommend customers using them in this case)
Because we only use this very infrequently, we do allocate... Strings should NOT be part of regular runtime messages...:)
These are the RAW methods...
maxValue can be used as syntax sugar
Remember we're not using this to transfer STATE
No, this is just serialization
At least not regularly as a state transfer/snapshot interpolation library
Or do you mean that this entire thing is not used with states at all?
We have several different overloads and variations on top of this.
"Or do you mean that this entire thing is not used with states at all?"
In quantum we do not transfer states regularly...
And when we do, it's for a late-joiner or reconnect (full state), so we do bit compression on top of the whole stream
We don't bother with delta compression in THAT case.
For input we have different strategies for compression.
The biggest portion of data send are the inputs, no?
You don't use bitstreams for those?
we do, but we compress differently (most cases compression is not needed actually)
The meta-data has a bigger impact than the actual input data (which is minimal)
So it has been much more important to be smart with the meta in all the different use cases, etc...
We have some mobile 32-player games released (which is not something most people think is even possible with determinism - people tend to think of old lockstep issues - something we don't suffer from due to the server which has authority over the input stream).
Trying to wrap my head around all of this is pretty difficult
๐
Games are live, running with full deterministic predict-rollback and 32 players (on mobile!).
I couldn't get my head around quantum for a while either @weak plinth because I was assuming that the final word on user inputs was part of some kind of agreement between all clients, which made no sense. Once fholm pointed out there is an authority server for the final word on inputs, it all cleared up.
https://arstechnica.com/gaming/2019/10/explaining-how-fighting-games-use-delay-based-and-rollback-netcode/ this article is good, for predict rollback
came out on friday
morning/evening @graceful zephyr
o/ yo
Nice! Bookmarking this
@weak plinth https://hatebin.com/
Codegen is working nicely (other than still struggling to find the ideal timings from unity to generate/destroy it)... but the gen'd code is getting less and less human readable. It does all resolve out though to just delegates at runtime, so should be fast.
The attributes are starting to get unruly as well
Why would you use a min-max range? Rather than just a max?
for an int?
because zero isn't always the min
ints go negative
most common case will be 0-X, but no need to bake that in
Ah yes I forgot about that ๐
its an addition and subtraction away from allowing any min/max
I've been tinkering about a good API that isn't too verbose
But I think it's going to be pretty verbose
I just rely on default arguments heavily for that
behind the scenes there is a LOT of variables
but you can in this case just stick [Pack] on a field... and it will run the defaults
I'm going to serialize all by default
So basic use case, just [PackObject] on the class or struct, and [Pack] on any fields you want included
I debated that, but decided having to switch off fields is more annoying than switch on
It's a lot of extra work setting up your objects now
Rather than just nonserialized above the exclusions
Though you could make that a switch in the object attribute
[PackObject(Serialize.All)]
[PackObject(Serialize.Marked)]
something like that
@graceful zephyr I assume on the topic of Quantum, that you have variables for things like induced delay, and I assume knowing you you also have some kind of automatic delay feature that factors in the round trip times of players, to create a balance between delay and extrapolation?
hello guys
morning
America is the center of the known universe though... get on board.
๐ฉ thats a funny statement
Not in America it isn't LOL
lived in the US for 2 years... in boston, it feels like a very provincial place
also lived in new york
and visited the rest
I'm from the east coast, so I know the "vibe" well
very different from west coast usa
yeah it isn't the center of the world... more like a suburban perifery
west coast I don't know well
I was happy to leave... lot of ignorance and a very low quality of life
east coast = "Fuck you"
west coast = "Let's try to all get along"
south = "Passive aggressive niceness"
north = "Howdy"
๐
ok let's get back on topic... could ytou advice me about this two libray:
Universal binary serializer for a wide variety of scenarios https://discord.gg/FGaCX4c - rikimaru0345/Ceras
yeah, we spend as little time in the US as possible these days
I have to be back there for 4 months a year to play in my bands, and that funds my being abroad the rest of the year.
We dread going back
--- about the libs... I was doing serialization by hand but decided to try a lib supporting polymorphism and classes serialization before my project get's bigger
using new unity llapi preview
is your net serializer byte or bit based?
the datastream writer supports only standard types... no structs or classes
byte
if i use datastream writer
FSE's variation of NX's packer is a good balance of speed/features and mixing byte/bit packing
Any byte reader/writer is probably going to look about the same these days
unless its just badly written
the two libs I posted seems to be the most performing ones supporting custom classes
but ceras uses extended generated code
There is an upper limit to "performance" on them, so if its good... its good
unless you start making choices about things like pinning your byte[] at the start of serialization and passing around a pointer
could you tell me if the second supports polymorphism?
polymorphism in what context here?
Advice? What kind of advice?
You mean that you can just throw whatever object at it and it will come up with a default serialization?
yeah, don't do that
@weak plinth choosing betweent he 2 libs I posted
First thing with that is you will want to differentiate between ref types and structs
I see reflection going on in there
I mean if we re just talking about serialization... having a library that can serialize classes helps...
hopefully that is one time
in which one?
I see emit, so I assume its one shot
it is generating code at runtime.... so not much refl I guess
Seems similar to the stuff Complex was trying to make happen
maybe he could find it useful then
seeems to be a very smart implementation
we are talking about the ceras lib right ?
the first linki
I'm not looking that closely, was just poking at netserializer
I'm getting tired... there is 1000 libs doing a similar thing and is very hard to choose
but this 2 seems very interesting
Just abstract your code from any of it, pick one and refactor later if needed
that's not possible atthis level
But generally for regular tick traffic, any autoserialzation is going to be bloated
or very hard at leastr
the way I structure my data depends on it
ok thats interesting
your serialization just sit inside of the Serialize/Deserialize methods, and you should be able to revisit what goes on i n those methods later
you mean slow as hell?
nah, just uncompressed
yeah but I represent my data based on serialization
or limited in how you can compress it
if I can't make an extensive use of polymorphism then things change
why based on serializaton? serialization for networking involves a LOT of culling, packing, RLE compression and whatever else you can throw at it
I'm talking about the way I represent the data
the idea is that you take a struct/object and pack that into a byte[] as tight as you can... and on the other end reproduce that byte[] back into your object
Maybe I am just misunderstanding you
your serialization is packing stuff into a byte[]
it doesn't have to directly coincide with that stuff in your object
heading off to breakfast
if I have alibrary that automaticly sends any class I have over the net
I may just organize my data ina more confortable way
but I have to choose now
if I want to serialize by hand I would use a different data structure
good breakfast
the serialize and deserialize methods just need to match up
y
not the methods
you mean the output
I mean that I'm concerned about what to pass to them as input
because that changes the way I organize my data
and this tdepends on the library I use
that's why I needed an advice ๐
(I messed up the writing,, just tired... )
I'm busy writing something what you probably want, though it's not done yet
Also, I'd recommend using structs to represent data over the network
@weak plinth what would be the easier to serialize a struct? I ended up using this lib that allows me to easily send serialized classes or structs, but I'm not sure about the overhead
unity serializer in the new llapi doesn't serialize structs
talking about the datastreamwriter
If the struct is blittable, you can take the offset of the fields and use pointers
implementing it my way in an unsafe method? heard is not advisable to deply on multiple platforms
What's unadvisable for multiplatform?
that while compiling for multiple platform going usafe can create problems downstream... didn't further investigate
Depends what exactly it is you do
But pretty much, no
Pointers can differ in size x32 vs x64
As well as booleans
could you advise about a wide spread library that does just that?
I'm trying not to ulosse control by using something overcomplex... but I also don't want to reimplement something done 1000 times by others
netstream for example
seems to be widly used
hem.... i think was called netserializer... posted a link just up
are you trying to implement something that does exactly that?
you think isnt a good implementation?
You can't use this with Unity IL2CPP
great... I must have missed that
There's a table somewhere that tells you which platforms support mono
It's not a lot
Reflection.Emit is not usable in IL2CPP builds
The closest thing you can get to this is using mono.cecil
But that requires you to alter an existing dll and save the changes
IE, you have to run that code everytime you build (before the build)
ok, so no way, thanks you saved me sometime
this could be interesting for you
Universal binary serializer for a wide variety of scenarios https://discord.gg/FGaCX4c - rikimaru0345/Ceras
it is IL2CPP compatible
I've seen this
but it as a lot more functions, like polymorphism
But it has a lot of overhead
Well, for one it converts to byte[]
And apparently, it uses setvalue/getvalue
which is insanely slow
isn't converting to byte[] what most serializers do?
Perhaps, but you'd want to be able to get unmanaged memory preferably
So you can avoid GC allocations
Worst-case scenario, you can use a fixed byte[] buffer that floats around somewhere and lives for the lifetime of the game
Also, his serializer is a class
So everytime you create one, you have gc
what if I use it only with structs?
The serializer you have to create with his thing is a class
do I care?
I may have 2 serializer classes
in the whole project
the developer really stresses that the implementation is GC "optimized"
about the getvalue/ setvalue, I had no idea they were this heavy
And I'm not too sure about his actual write/read implementations
Not sure about the perf of this
You can always give it a try and profile it
See how much it allocates
mmmm
Or be patient and wait until I'm finished with mine ๐
you really think that allocation is so bad ๐
Yes. Especially for networking, it's easy to rack up a lot of GC
you mean here?
var value = Unsafe.As<byte, int>(ref buffer[offset]);
I'm struggling to understand here
Trying to avoid reflection at runtime is the hard part with this stuff
I'm working the same problem right now as well
And I have opted for straight up code gen, which has the headache of "when" to do it
Trying to codegen using unity callbacks pre-DOTS is painful
like you can't codgen in OnPreProcessBuild
your code will generate, but not make it into the asm
Which leaves either having users manually generate as needed, or to check the asms after each compile to see if anything that matters to your has changed.
Right now I have a wall of codegen that spits out files that look like this:
https://hatebin.com/iinjttjmyn
hey guys, in the new unity llapi this is how you send over an udp driver:
int Send(NetworkPipeline pipe, NetworkConnection id, DataStreamWriter strm)
int Send(NetworkPipeline pipe, NetworkConnection id, IntPtr data, int len)
the documentation suggests to use a disposable datastreamwriter object to prevent keeping allocating memory
using (var writer = new DataStreamWriter(200, Allocator.Temp))
__
isn't this less efficient than having a persistent allocated buffer?
this is a link to the lib
More in detail... I'm using a lib that sereializes over a byte{]
I'd say yes. But I don't know the lib in detail
now it seems stupid to having to write in a datastream buffer (thus serializing) and already serialized byte{]
but since I can only pass to a send a datastream object, how am I supposed to deal with it?
@weak plinth that's a suggestion form the guide... I can allocate the buffer in the datastream as persistent avoid the using {} part
at the end is my choice... I'm wondering what could be the problem with that
Why don't you use an IntPtr instead?
I don't know what the datastreamwriter exactly entails
could you explain me how to pass an intptr to the function?
a datastream writer is just a unity serializer, very basic, that has a pointer to a buffer
IntPtr is a type, if that's what you mean?
A platform-specific type that is used to represent a pointer or a handle.
do I get in trouble using it? what's the usage if I want it to point to my byte[] buffer?
got it
I just have to allocate heap memory to an intptr
and it becomes my buffer... thus have to use MArshal..
You shouldn't need a byte[] at all if you use IntPtr
The difference is, one is managed and the other one isn't
int Serialize<T>(T obj, ref byte[] buffer, int offset = 0)
tha't what my ceras serializer takes
can I give it the intptr somehow?
Probably not if the guy isn't using that
is there a way to go around it?
Nope. That's the way his API is
I mean, I have a serializer that you can use to serialize stuff by hand currently
That does use IntPtr
does it serialize custom struct/class?
Not automatically
@weak plinth seems this does more or lesst what the datawriter from unity new llapi does
I didn't check for performance
but very nice code, had already bounced in your lib before
I'm at the point where I'm considering using structs thus a need a lib able to deal with custom structs
I'm making that atm
I'm writing with the author of the Ceras lib I showed you
he is willing to help me bypass the byte[] thing... using directly a IntPtr
@weak plinth I'm getting a bit scheptic ... but you gave a fast look at this Ceras and there was nothing worring with using it right?
I think it uses getvalue and setvalue from Reflection
maybe not 100% the fastest.... but more than fastenough
Its quite considerably slower than a direct method call
but that's maybe forced to be able to generate code to handle custom class/structs?
I'm asking because this is beyong my understanding... I guess more at your level
or this is just a very bad implementation and I should drop the lib?
Profile it and see if it fits your use case
I'm not good enough to profile 10 libs and choose the best case for my appllication
The best case is any one that you choose and causes no bottlenecks for your application
I still think you are WAY overthinking your serialization
you know... overthinking people are rare this days... everyone is writing shitty code... I'm a bit old school ๐
that thinking goes two ways though. These networking channels are full of guys all making the same low level stuff with nothing actually finished or even to show. Its one thing to leave bad code forever un-fixed or refactored... but that is just good planning and time management.
Serialization is super compartmentalized if you code that right, and you can change your mind many times later on it.
I've refactored my serialization a bunch of times, and likely will have to do it again to change everything to IntPtrs and go pure unsafe
But not doing that up front didn't stop me from producing an entire component library
I mean, you do you - it just seems like you are buried in the same muck so many others in these networking chans get buried in
Granted, I have no clue what you are actually ultimately making.
It is a midLib for a game
basedon the new llapi
You see I already went to the IntPtr stuff... avoiding refactoring ๐
95% of game networking coding work is in the simulation creation
This serialization stuff should take like a day to pick something
Just trying to keeep the vibe positive and get out of the muck what ever it is ๐
yeah.... let's see , I'm very old school slow ๐
If this is pretty much hobby work, whatever pace suits you and is fun for sure