Sunday, January 5, 2014

Status Update: 2016 Edition

Yeah! ~2014~ My new year's resolution is the same as last year's: 1920x1080.

What's Bad in 2015?

Space, duh. Space is a bad place, don't go there. At least not if you can help it. In these last two weeks I have done things! Bad Things! I have spent the last two weeks refactoring the item system and getting basic network synchronization working. And I spent some time fixing Unity's terrible RPC thing. And I registered for nvidia's cool Registered Developer Network, and got access to some stuff (that I can't use yet).


The item system now uses inheritance instead of interfaces (because interfaces can't have virtual methods, for some reason (I mean, otherwise it would just be multiple inheritance (what I really want are mixins)). So, now all things that are items inherit from some super Item class, which also has a custom inspector that shows all sorts of cool, context sensitive stuff based on what stuff you selected.

The details (deets)  for a grabable and highlighted Item.

A lookable canister. There's a bug here. Parent should only be drawn for grabable items.

A boring canister with no deets.

In the inspector, I don't want it to draw all of Item's properties, so I call DrawEverythingExcept() and then you pass it a list of all the properties in Item, but not its derived classes. Then you use (chorus of angels) System.Reflection to spit out a list of property names and pass them in to DrawEverythingExcept. And then I do the "draw a serialized thing" for the stuff that I want. .NET reflector has been really useful here to figure out how Unity handles GUI drawing internally.

Bad Things Happen Synchronously

Networking things is hard. So far, I've got people moving around, oxygen working reliably (and also pretty much super efficiently, and in a scalable way), and also you can pick up items and drop them! Most physics based stuff is out. Basically, I only use physics for putting things places, and where it's not that important. And even that is pretty sketchy (I've probably got to set up owner switching, or some smarter prediction stuff). After doing much research, I have come to the conclusion that getting a good multiplayer experience is too much work for one person. Thusly, I will only be implementing some of valve's super informative muliplayer techniques. Namely, I will be forgoing lag compensation, because that one seems like the most difficult to implement. Also, I need to figure out some decent prediction algorithms, but that might come from inspecting the actual Source-source.

update: I have spent a lot of time in the last couple of days extensively researching networking architectures, and I will certainly (yeah...) make a post about my crazy quest involving this. (secret future bonus: this presentation)

Bad Remote Procedure Calls

So the Unity convention for remote procedure calls is to call RPC(String methodName, some, other, stuff). The big problem here is having to use a string for calling a method. If you're using a string, then you're unable to keep track of references and also you can't refactor and it's a nightmare. Thus begins the long journey of figuring out how to pull a string out of a C# method-group. A method-group is not a run-time type. It is something the compiler keeps track of so that it can either turn it into a delegate or a function call. Repeat: a method-group is not a run-time type, to pass it into a function is an error. Except in the case where it is implicitly cast into a delegate from the function call's arguments. Incredibly, this means that I can make passing a method-group work, if I create an overload for RPC that each takes the correct kind of delegate corresponding to the method-group that I'm passing in.

for example:

You can see that I only really need to create a few overloads because my RPCs only really take a few kinds of parameters. It kind of sucks but it's still better than passing strings all the time. And yes, I've tried to use covariance to create a delegate that just accepts object but that isn't allowed for reasons. Do you think my RPC syntax is a reasonable compromise? I can imagine it getting very burdensome if I have to create a lot of new overloads for all the kinds of RPCs I might want to call, but for now, there are only a few serializable types, so the number of overloads can remain small.

So, that's it for 2014.
Bring on 2015.