A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Post here your suggestions for new possible features in SmartFoxServer 2X.

Moderators: Lapo, Bax

User avatar
Zenith
Posts: 55
Joined: 09 Oct 2017, 09:57

A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Zenith » 20 Mar 2018, 19:19

Hi,

First of all. Thanks a lot for making Smartfoxserver and keeping affordable for indie devs like me to use it.
The documentation and example Projects are awesome.

One thing I miss is you have mentioned that for checking collision on 3d terrain or environment in Unity we can either import a data file or use a unity client which provides collision information to the SFS server with negligible lag as they are on same server or something?

Can we have a tutorial on this. An example project would be great.

Again hugely thankful for SmartFoxServer. Many concepts like MMO API, Area Of Interest , Lag compensation seems like breeze now after working with SFS. Hope you are earning a hell lot of money with this and would keep updating it.

Regards,
Zenithin
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Lapo » 22 Mar 2018, 09:29

Hi,
thanks for your feedback.

As you said there can be multiple approaches to porting the world data to the server side.
The idea of extracting some kind of world data from the Unity map and importing it in SFS2X is feasible but requires some sort of middle-man software that does the conversion job. Depending on the complexity of the map this approach might or might not work as it can get pretty tricky for large and complex maps (e.g. outdoors landscapes with lots of trees, rocks, complex terrain etc...)

Another way would be to run an headless Unity client on the server side and using it as a "simulator". In other words the server would receive the client position changes, send them to the Unity instance which would perform the movement and collision checks and validate the data. Then the Unity instance sends data back to the Server which updates the clients.

I think this last approach is the most flexible, and I agre that a tutorial on this would be pretty interesting.
We'll think about it.

Cheers
Lapo
--
gotoAndPlay()
...addicted to flash games
ojuergen
Posts: 8
Joined: 23 Feb 2017, 18:11

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby ojuergen » 14 Apr 2018, 15:31

Hi guys,

concerning the approach with a server-side headless unity client, I have made good experiences with it. In my current project, rooms are created by the client and the SFS will spin up the same unity game that the client uses, but with an admin configuration (via runtime parameter). All requests the client makes are basically just forwarded to the unity server. This way, I can code my entire game in one unity project and almost never have to touch the extension code. Just Unity.
I have built some utils to allow for remote procedure calls using reflection. Also, I have abstracted the standard pattern for networked actions that are confirmed or denied by the server. The flow always goes
1. Client sends request (and maybe optimistically already executes it)
2. Server validates the action. Either sends denial to client, or info to all
3. Clients apply or roll back the action
Once you have this, it basically feels like coding with UNet, but with all the advantages that come with SFS. I could probably post some code snippets...

I have a question, by the way, that seems to fit here. When I send remote procedure calls via SFS, I serialize all method parameters in an SFSArray. Nested classes, structs and value types, enums, scriptable objects - those things need to be serialized by recursively going through all their fields and properties with reflection somehow. I could use JSON, but would increase my traffic significantly. I could use SFSObject.PutClass, but that only works if I have all the classes in the java extension, but I only want to get the stuff from Unity to Unity without touching extension code. Is there a way to do that? My code for this kind of works but feels messy and error prone (recursive, full of reflection, probably slow)...

Overall I gotta say that SFS is quite amazing in how it lets me do all this magic. Thanks a lot!

Best regards
Ole
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Lapo » 16 Apr 2018, 07:28

Hi,
this is interesting, we'd be glad if you could share some snippets to show how you have set up your project.
Do you spawn a new Unity "server" for each game Room? Or do you send all requests (from all games) to a single Unity "server"?

As regards the serialization I think you could look into native .Net serialization as it is probably the most convenient system.
You could convert your objects to binary data via the in-built .Net serialization and then wrap it in an SFSObject from both ends of the communication.

Makes sense?
Lapo

--

gotoAndPlay()

...addicted to flash games
ojuergen
Posts: 8
Joined: 23 Feb 2017, 18:11

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby ojuergen » 16 Apr 2018, 18:36

Hi,
thanks for your reply! The serialization approach is probably exactly what I am going to end up doing. Thanks :)
Currently my approach is to start a Unity instance for every Game, which will encompass roughly 2 to 10 players. One instance consumes 250 mb and 10% CPU on an AWS t2.micro machine. So I guess, that is feasible. At some point I will have to look into horizontal scaling, but since most of the stuff is in the Unity Code, it will be doable, I think. Concerning latency, I guess the penalty for using the unity server is not too bad as it runs on the same machine as the SFS. But with the micro machine, I cannot really make a meaningful test.

I'll try to summarize part of the architecture with some snippets stripped of all the null checks and deodorant ;)

When a client creates a new room the server goes

Code: Select all

final InstanceId instanceId = InstanceId.create(); // some UUID
// start admin unity process. Pass it the instance id so it can identify as admin
final Process adminProcess;
if (isWindowsSystem()) {
   adminProcess = new ProcessBuilder("Path/to/Game.exe",
   "-admin", "-batchmode", "-localhost", "-instanceId", instanceId.getValue()).start();
} else if (isLinuxSystem()) {
   adminProcess = new ProcessBuilder("Path/to/Game.x86_64",
   "-admin", "-batchmode", "-localhost", "-instanceId", instanceId.getValue()).start();
}
final Room room = instanceRoomManager.createInstanceRoom(roomName, instanceId);
// keep reference to admin process so we can shut it down and handle RPC
final Instance instance = Instance.create(instanceId, ImmutableList.of(), null, adminProcess, room);
instances.putIfAbsent(instanceId, instance);


A client that wants to call SomeSingleon.Instance.Foo(Bar bar) on the admin goes

Code: Select all

var parameters = new SFSObject();
parameters.PutUtfString("[Type]", SomeSingleton.Instance.GetType().FullName);
parameters.PutUtfString("[Method]", nameof(SomeSingleon.Instance.Foo));
parameters.PutUtfString("[InstanceId"], instanceId);
parameters.PutSFSArray("[Parameters]", bar.SFSSerialize()); // ugly extension method that serializes parameters
sfs.Send("AdminRPC", parameters);


SFS will use the instanceId to find the admin and send it to him. The admin will use reflection to call the method. Something along the lines of

Code: Select all

Type type = Type.GetType(parameters.GetUtfString("[Type]");
object instance = baseType.GetProperty("Instance"); // type must be a singleton
MethodInfo method = type.GetMethod(parameters.GetUtfString("[Method]"), BindingFlags.NonPublic | BindingFlags.Instance);
object[] args = parameters.GetSFSArray("[Parameters]").SFSDeserialize(); // ugly extension method for deserialization
method.Invoke(instance, args);


Well, the devil's in the details, of course and the dressed code is a tad more complex. I am currently working on remote prefab instantiation where every object is registered with a unique id, so that RPCs work not only on singletons. For an MMO, I could represent each object with an MMOItem. That would be so cool :)

What do you think? I hope that sometime all this can be some helpful package for the comunity :)

Best regards
Ole
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Lapo » 17 Apr 2018, 09:07

Thanks,
this is very interesting. It is generic enough to work in many different game types. Well done :)

If you want, keep us updated: we're interested in integrating something like this (at least in terms of "scaffolding") in SFS2X, to simplify this kind of work for Unity devs.

Cheers
Lapo

--

gotoAndPlay()

...addicted to flash games
ojuergen
Posts: 8
Joined: 23 Feb 2017, 18:11

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby ojuergen » 17 Apr 2018, 11:26

I will try to extract the stuff into a GIT project with extension and Unity demo scene. I will keep you up to date, of course.

By the way, native byte serialization works like a charm. Some of Unitys types (like Vector3 and Quaternion) need some extra code, though. Also every custom MonoBehaviour and ScriptableObject will need a serialization surrogate, if you want to send it over the ether. It's managable, but not optimal from a usability perspective. Maybe I can find a way around this, somehow.

Thank you so much for your support throughout this forum over the years. It's been very motivating!
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Lapo » 17 Apr 2018, 12:29

ojuergen wrote:I will try to extract the stuff into a GIT project with extension and Unity demo scene. I will keep you up to date, of course.

Cool thanks. We'll be glad to take a look when it's available. Maybe we could make a tutorial about it, or something along those lines.

By the way, native byte serialization works like a charm. Some of Unitys types (like Vector3 and Quaternion) need some extra code, though. Also every custom MonoBehaviour and ScriptableObject will need a serialization surrogate, if you want to send it over the ether.

What do you mean by serialization surrogate? An alternative?
One way to do serialization is to add the ToSFSObject() and FromSFSObject() methods to customize which fields you want to export. It's a bit of manual work but it also optimizes the amount of data sent.

Thank you so much for your support throughout this forum over the years. It's been very motivating!

No problem and good luck :)
Lapo

--

gotoAndPlay()

...addicted to flash games
ojuergen
Posts: 8
Joined: 23 Feb 2017, 18:11

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby ojuergen » 17 Apr 2018, 17:17

Lapo wrote:Maybe we could make a tutorial about it, or something along those lines

Absolutely! I have seen questions in this direction in the forum a few times, so I guess people could use it.

Lapo wrote:One way to do serialization is to add the ToSFSObject() and FromSFSObject()

Right, I could do that, but I try to shield all network related code from the remaining project. So I try to avoid SFS references in the game code. Not that I intend to, but that would allow to exchange the network solution to a different one. It's also good for testing.

ojuergen wrote:What do you mean by serialization surrogate

Well, I am using System.Runtime.Serialization.Formatters.Binary.BinaryFormatter and it can only handle classes annotated with [System.Serializable], which unfortunately, Vector3 & co. are not. For this, you can provide something called an ISerializationSurrogate , which does the same as your suggested ToSFSObject() methods, only for byte[]. You would have to provide this for every class that inherits from Unity MonoBehaviour and add it to the BinaryFormatter. And again, I want to shield all network related stuff from the project, so I can ship this as a package that integrates well into an arbitrary project. But I guess one of these things will be necessary.
User avatar
Lapo
Site Admin
Posts: 23008
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: A tutorial on importing Unity Terrain or Talking to Unity Client for Collision Information

Postby Lapo » 18 Apr 2018, 08:20

ojuergen wrote:Well, I am using System.Runtime.Serialization.Formatters.Binary.BinaryFormatter and it can only handle classes annotated with [System.Serializable], which unfortunately, Vector3 & co. are not. For this, you can provide something called an ISerializationSurrogate , which does the same as your suggested ToSFSObject() methods, only for byte[]. You would have to provide this for every class that inherits from Unity MonoBehaviour and add it to the BinaryFormatter. And again, I want to shield all network related stuff from the project, so I can ship this as a package that integrates well into an arbitrary project. But I guess one of these things will be necessary.

Ah, I see.
Maybe you've already seen this?
https://answers.unity.com/questions/185 ... lized.html

It discusses similar ideas.
Cheers
Lapo

--

gotoAndPlay()

...addicted to flash games

Return to “2X Features Wish List”

Who is online

Users browsing this forum: No registered users and 14 guests