Sharing logic between client and server

Hi!

Folks, I’m planning an architecture for the new project which is going to be an online game. In order to avoid cheating I’m going to validate everything on the server. Basically server will execute the identical to client gameplay rules. And it looks like there going to be code duplication both on the client and the server for this logic.

I really want to avoid that and for this purpose I’m going to use Haxe. However I foresee several upcoming problems:

  1. The core of the client will be written in C#(it’s a Unity3d project). Model and validation rules will be written in Haxe. Haxe supports C# target, everything seems to be fine here.
  2. The server will be written in Go. We have strong expertise in Go, we have written several successful game servers in Go and pretty happy with it. However Haxe doesn’t support Go… I can think of at least 2 options:
    a) Generate C++ from Haxe and use generated C++ via SWIG in Go(more performant)
    b) Generate Lua code from Haxe and use that generated Lua with some existing Go interpreter (slower but simpler)
    What do you think of these options? Has anyone tried anything similar?
  3. Floats. Problem with them is that they are not deterministic. At some point the logic on the client may slightly diverge from the server. I’m thinking of using the fixed point math. Are there any decent Haxe libs for that?

Out of curiosity, did you look at the HUGS library? (Just FYI; maybe not that helpful)

It seems HUGS provides convenience ‘glue’ for Unity engine. Unfortunately it doesn’t address my issues :slight_smile: Anyway thanks for the link, it may come in handy at some point.

1 Like

I can’t really speak to your first two items, but probably the best option I can think of at present for handling fixed-point math in Haxe would be Luca Deltodesco’s excellent 32-bit fixed-point abstract class here. I’m currently using a modified version of this same code to provide fixed-point functionality in a custom 2.5D FPS engine I’m writing, and everything works great.

This is really interesting, thanks for the link.

I think I found a viable solution. It’s possible to call C# code from Go using mono C API. In this schema Haxe is not really needed…

@nadako should have the exact experience: share code between Unity C# and node.js server.

Yes, I was successfully using Haxe for shared logic. We compiled the game logic into a .NET DLL with Haxe/C#, so it doesn’t depend on Unity APIs (however at some point we did use Unity API for generating some helper functions for client, and that worked with simply -net-lib UnityEngine.dll/UnityEditor.dll).

We used the JS target for the node.js server - it worked pretty well. No problems performance-wise (thanks Haxe), but sometimes we had issues with different int overflows (because JS doesn’t really have an Int) and default values (should be mostly solved with null-safety nowadays).

I don’t have experience with Go, but I would probably try using hashlink or hxcpp targets with it. Embedded Lua/JS is a viable option too, however in all these cases (also when embedding any other VM into your server, even non-Haxe, like C#/.NET) you have to care about performance implications of data marshalling between the main server application and the logic. It was a non-issue for us, because we was just compiling to js for node.js :slight_smile:

If you’re brave and skilled enough, you can develop an in-house Go target that supports a subset of Haxe without Dynamic/Reflection - should be easier than the “proper” target. @ousado did some work in that direction.

Float errors can be an issue even within the same “platform”, just running on different machines, we didn’t really find an universal solution for that other than allowing minor differences when checking the results between client and server as well as handling particular cases by hand (adding rounding/clipping where needed).

FWIW I would use Haxe any day even with a single target, because of greater type safety and endless possibilities for code-generation. Both of these proved very useful on that project: e.g. abstracts instead of primitives and Maybe<T> abstracts caught a lof of errors, and with macros we generated a lot of boilerplate/glue code (e.g. read-only classes with reactive properties for handling data in the client, or command dispatcher for the server). Also with macros+abstracts we had a lot of validation for the static data directly from type definitions, without writing any additional schemas and code, which was super helpful. So yeah, Haxe is powerful…

3 Likes

may be we can wrap c++ api to hashlink/hxcpp to unity

https://jacksondunstan.com/articles/3938

that link already binding Unity API,between c# and c++,

and what I want how to fast binding c++ and hashlink automated?
@nadako