My project - Action FPG FPS

I don’t know if there were any tutorials for the old API or not. Some of that stuff still holds if so.



The new API is only like two weeks old at this point so the documentation is lagging. I was going to integrate SpiderMonkey into Mythruna before I tackled updating the docs just to be sure the API didn’t get any last minute changes. Since Mythruna is networked now with another test build release scheduled for Monday… hopefully I’ll be able to make some doc updates shortly after that.



The best example so far might be the chat test… it’s pretty basic but shows sending and receiving both UDP and TCP messages. I don’t think there’s anything like a list of things like “Make sure you messages have no-arg constructors” or stuff like that. But… at least the latest nightly will tell you that particular error more plainly. :slight_smile:

For reference:

TestChatClient.java

TestChatServer.java



Small… but sometimes a working example is everything.

An update:



Got it nearly working I think. What I’m having a problem with now is Class Not Found exceptions occurring on the client side, when the server sends its response. What confuses me is that the server is able to send the message okay, so it has no problem serializing it. What could cause a problem with deserialization?



The other problem I had is that the default maximum message size was too small. Somehow my level patterns come in at over 32k. They include a 3 dimensional array of objects, each with a number of properties, so perhaps thats not surprising. Perhaps there is something I am doing wrong though. In any case, I had to change the MessageProtocol code, and I think one other file but I cant remember which, so that it uses larger buffers. I use 8388608 bytes as the maximum, which of course it never reaches.

ancalagon said:
An update:
Got it nearly working I think. What I'm having a problem with now is Class Not Found exceptions occurring on the client side, when the server sends its response. What confuses me is that the server is able to send the message okay, so it has no problem serializing it. What could cause a problem with deserialization?
The other problem I had is that the default maximum message size was too small. Somehow my level patterns come in at over 32k. They include a 3 dimensional array of objects, each with a number of properties, so perhaps thats not surprising. Perhaps there is something I am doing wrong though. In any case, I had to change the MessageProtocol code, and I think one other file but I cant remember which, so that it uses larger buffers. I use 8388608 bytes as the maximum, which of course it never reaches.

I can strongly say you are doing something wrong if your message is that large. Udp max is 65535 bytes or something like that. You may want to look into some code which compresses your data into bytes before sending also. (maybe spidermonkey is already doing that). For my game ive sent over messages which include all playerdata (location, rotation,scale, name, etc) and it was only a total of 400 bytes to 0.390625 kilobytes

Yeah, definitely break up your data or compress it… that’s a huge amount of data to be sending around.



re: the class not found exception… the message class needs to be in the classpath on both the client and the server… and registered on both the client and the server. Since I don’t know what the exact error was, I don’t know if it was a java ClassNotFoundException or SpiderMonkey telling you it doesn’t know how to deserialize the class.



The “painful” part of the current serialization is that all classes must always be registered on both client and server… and if you don’t explicitly give them IDs then they must be registered in the same order, too.

pspeed said:
The "painful" part of the current serialization is that all classes must always be registered on both client and server... and if you don't explicitly give them IDs then they must be registered in the same order, too.

Thanks, that clears up much things. I have read the docs, and heard somewhere else, that if you dont assign IDs for the serializer, the messages may come out-of-order. What does that mean exactly? Could the message A, which you send before message B, arrive after messageB on the other end? Is this also the case for TCP connection?
pspeed said:
The "painful" part of the current serialization is that all classes must always be registered on both client and server... and if you don't explicitly give them IDs then they must be registered in the same order, too.


I don't know if you have rewritten the old spidermonkey serialization but I know it wasn't using the default java serialization. I know java's implementation doesn't provide the best performance but is there a way to mimic how they require the user to implement the interface serialization. So if there was an interface lets say called IspidermonkeySerailizer (awesome name I know) then in your networking code when a message comes through pull the non transient through reflection and accept that type to be serialized?

I probably will have to end up explaining this again but im in a rush out the door. Please let me know if im making sense

If you don’t assign IDs when registering the serializer then you just need to make extra-super-special sure that you always register them in EXACTLY the same order on client and server since the class IDs are assigned in order.



At some point, I do want to rewrite the serializer to be more flexible. The issue with Java’s serialization is it’s not very compact. It sends a bunch of data across to identify the class (and any of its static data) to the other end… even in the smallest case this is the full class name. That’s not so great if you are trying to get your serialized size down to minimum.



On paper, I’ve designed a newer version that’s based on bit streams instead of ByteBuffers (though obviously can be trivially adapted to ByteBuffers) that allows inline classes as well as preregistration. Preregistration in that case would just be an an optimization step. The spider monkey internals would then take care of automatically registering classes the first time they go over the wire.



But what’s there works and I’m a few weeks behind on working on my game. Though I end up wishing for a bit stream every couple days. :slight_smile:

1 Like

re: messages being delivered out of order… that’s the nature of UDP. You just have to deal with that possibility in some way when sending UDP messages. Either indexing your messages, giving them a time, or whatever. Ignore anything that’s old.

1 Like
pspeed said:
If you don't assign IDs when registering the serializer then you just need to make extra-super-special sure that you always register them in _EXACTLY_ the same order on client and server since the class IDs are assigned in order.

Ah, now i get it, either you assign these IDs manually, or they get assigned by the order you register the serializers.
pspeed said:
re: messages being delivered out of order... that's the nature of UDP. You just have to deal with that possibility in some way when sending UDP messages. Either indexing your messages, giving them a time, or whatever. Ignore anything that's old.

Thanks, i was worried that messages could land out-of-order using TCPs.

I copied the code that does the registration, so its in the same order. I think I’m going to add some logging to the serialization and deserialization, to see what is happening. Which class corresponds to which ID, and what the ID of the class that it cant deserialize is.



More than likely its one of the classes that a LevelPattern uses that I have not registered. I’m not sure if all of the default data structures, ie ArrayLists, are registered? Anyway, what confuses me is that the serialization seems to work okay. Surely if that works, and the code on the client (in terms of registering classes) is a mirror of the server code, it should work?



If I make my classes extend GZIPCompressedMessage, is there anything else I need to enable registration?

They still need to be registered.



Can you tell me what error you are getting?



Note: if you don’t register a class then it tries to do a default registration anyway… so it will send but won’t be readable on the other end as I recall. I improved the error message on the receiving end because it used to just silently drop messages that it didn’t understand. And that’s a real pain to debug.



…so I’m curious what the error you see is.

Its a serializer.SerializingException: Class Not Found for buffer data. I’ll enable some logging to figure out what it is.

I know I am stating the obvious here so apologies but have you ensured that you have done a clean build of the project? In my experience, if you are using the default jmonkey ide and build script, this is the most likely cause of a ClassNotFound error.



As pspeed says, not registering a class will not give this error (or doesn’t with the old spidemonkey anyway), you will just bang your head against the desk for ages trying to debug until you go ahhhhhhh, so thats why they never appear. I do the same whenever I forget to listen for them as well…

As for the order of registration, the simplest thing to ensure consistency, if you don’t use ids, is stuff them in some static method somewhere that both client and server use.



Edit: sorry, posted before your last message, different error so a lot of what is said above just sounds plain wrong now, my apologies!

Yep… so the class isn’t registered. Serializer used to silently ignore these issues… that was fun. :slight_smile:



I should add a strict mode to serializer where it won’t auto regster classes just because you’re writing them… then you’ll get an exception on the sending side.

Done. The next nightly will get it or you can go directly to subversion if you are in a hurry…



With the change, if you try to write an object of a class that hasn’t been registered (or doesn’t have an explicit ID) then you will get an exception.



…and there was much rejoicing. :wink:

Great! will update and rebuild now. Thanks.



I refactored the code so that the data structures used in building the level, stacks etc, are in a separate class, the LevelPatternHelper. Meaning, the LevelPattern itself is much leaner and strictly holds data now. Lets hope that has slimmed it down enough. I’ll revert the changes I made to support larger messages (in my local jMonkeyEngine3 code of course) and see if it works.

Strange - I got it to print the name of the offending class out, apparently its my LevelPatternMessage, which is impossible, its the second class I register. Its marked serializable and extends GZIPCompressedMessage. Is there anything else I should need to do for it?

No really to do with your error but with anything big that is not user dependent, like the levels, it is best to build them on both the client and server in the same way to prevent sending over unneeded data. For example, if the levels are random, just pass over the random key and build the level in the same way. The only data the sever should be sending to the clients is stuff the client cannot possibly figure out for itself - normally the result of other user actions.



Matt

I’ll have to test whether that would give identical results.