Saturday, November 18, 2017

Coordinate System Conversion Between Unity And A Java Game Server

Requirement from game

For the purpose of FPS attack predication I have to synchronized Hitboxs/BoxColliders between Unity Client And Java Game Server
enter image description here
To be more specific:
  • Each game character is exported to a DAE file for Server and to a FBX file for Client. These files contain geometry, joint and animation information.
  • HitBox information is manually defined and stored as a XML file and shared between Client&Server. Each Hitbox is attached to a Joint/Bone of the corresponding character.
  • When a player shoot a gun, both client and server will need to calculate the hit information. The server do so because it’s the arbitrator. The client do so to predicate the result and response immediately to the player.
The problem becomes complicated when:
  • For some reason we can’t ask unity to do the ray tracing. However there is a shared library between client and server that can calculate whether a bullet ( ray ) has hit a character and the bone being hit if so.
  • Client and server have different Coordinate Systems.
  • When imported to unity, character’s coordinate system is also changed.

Defining Problem

However, if we think about it, we can find the the problem is actually as simple as following:
For each hit box, given the transform (denoted as ) of the joint it attached to in Unity’s coordinate system, we need to find a matrix (denonated as ) that can transform it to the same state in server’s coordinate system.
In the game a character is rotated and translated after animated. Suppose a point has the hierarchy of the following:
- Translate Node
    - Rotate Node 
        - Character Pivot Node
            - Joint1 Node
                - Joint2 Node
                    - Joint3 Node
                        - P
Then in Unity can be defined as:

Where:
  • corresponds to translation
  • corresponds to rotation
  • corresponds to extra rotation introduced while imported by Unity
  • corresponds joint transform
Given we can transform the point from its local space coordinate to its world space coordinate :

Equally, in server we have :

And can use it to transform :

Note that there is a on Unity side, but no on server side. This will be explained latter.
We can easily convert between and and between and , because we know how two coordinate systems are defined. The unknown part is:

That is what Unity do when importing fbx files.

Coordinate Systems

The following image shows two coordinate systems:
enter image description here
Server’s on the left, Unity’s on the right. We can see that Unity’s left handed while server’s right handed. A point in server will be in Unity. The transform matrix would be:


What unity do when importing

After importing a FBX file, we can find that characters has the following changes:
  • If it is originally facing +X axis, it is now facing -X axis. This effectively changes it’s handness
  • It’s pivot is rotated around +x axis for +90 degrees. This step makes it head pointing to up direction again. Here is where the above mentioned comes from.
Given a point , if we change the character from binding pose to another pose, say run, we first transform from its model space to joint local space:

Where:
- is ’s coordinate in character’s binding pose.
- transform a point in joint1’s local space to joint1’s parent’s local space. So will have the reverse effect.
Then we transform to a new model space coordinate.

But if unity negates all model’s x axis. becomes . Suppose there is a matrix does the transform, that is: .
So we have:

Replacing with and with , we have:
$$

$$
For both of the above equations to be true. We can:

That way, the following equation also is true:

Here, stands for a matrix that can transform a point from jointX’s local coordinate to it’s parent’s local coordinate at posture posX.
Having the above information, we can now finish our task. Below is a code snippet of what I have written in our game:
public static Matrix3D Unity2SSJJ(Matrix4x4 result)
    {
        double[] data = new double[16];
        data[4 * 0 + 0] = result.m00;
        data[4 * 1 + 0] = result.m10;
        data[4 * 2 + 0] = result.m20;
        data[4 * 3 + 0] = result.m30;

        data[4 * 0 + 1] = result.m01;
        data[4 * 1 + 1] = result.m11;
        data[4 * 2 + 1] = result.m21;
        data[4 * 3 + 1] = result.m31;

        data[4 * 0 + 2] = result.m02;
        data[4 * 1 + 2] = result.m12;
        data[4 * 2 + 2] = result.m22;
        data[4 * 3 + 2] = result.m32;

        data[4 * 0 + 3] = result.m03;
        data[4 * 1 + 3] = result.m13;
        data[4 * 2 + 3] = result.m23;
        data[4 * 3 + 3] = result.m33;
        return new Matrix3D(data);
    }
    public static Matrix3D TransformToMatrix3D(Transform boneTransform, Matrix4x4 pivotWorldToLoal, PlayerEntity player)
    {
        Matrix4x4 mImportNegX = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1));
        Matrix3D m  = Unity2SSJJ(mImportNegX * pivotWorldToLoal * boneTransform.localToWorldMatrix * mImportNegX);
        m.AppendRotation(player.orientation.ViewYaw, Vector3D.Z_AXIS);
        m.AppendTranslation(player.position.Origin.x, player.position.Origin.y, player.position.Origin.z);
        return m;

    }

Saturday, November 04, 2017

Sharing code between CSharp and Java

There are many ways we can share code between C# and Java, for example:

  • Write the shared code in a lightweight scripting language, and run a VM in C# and Java. Lua is one of this type.
  • Write the shared code in a language than can translate both to C# and java, such as Haxe.
  • Write the shared code in Java and use tools to translate to C#.
Sometimes, we already has some existing code in Java, so we are only left with the third option. Besides, even if there is no existing code, Java to C# is an attractive option thanks to Java's rich & friendly development environment.

Recently, I have to share some common logic between Java and C# . To be more specific, there is a Java based game server which are connected by an existing Flash client, what we want to do is to add another Unity client while preserving both Java and AS3's logic.  After a lot of discussion, we decided to adopt the following strategy:

  • First, refactor and extract the shared logic in the Java server to a standalone module which shouldn't be depend on any other java library except Java's buildin library.
  • Second, translated the extracted module from java to C# use a tool such as sharpen.
We choose sharpen as our translating tool, because:
  • first of all, it's open source and can be modified if necessary
  • then, there are some successful application of it already, such as ngit.
There are lots of sharpen version on the internet, and I used the mono version with some multi dimension array fixed from anders9ustafsson's version, and pushed final result to my folk.

The document is very hard to find, so I made a backup in sharpen-doc

Here are some other resources I found usefull:
  • Build help: https://github.com/mono/sharpen
  • Example configuration: https://github.com/ydanila/sharpen_imazen_config
  • Sharpen C# utility classes: https://github.com/mono/ngit/tree/master/Sharpen/Sharpen
  • Another sharpen blog: http://pauldb-blog.tumblr.com/post/14916717048/a-guide-to-sharpen-a-great-tool-for-converting
When running sharpen,do set -Dfile.encoding=UTF-8 option, or some file won't compile successfully.

Command line Arguments:

ArgumentUsage
-pascalCaseConvert Java identifiers to Pascal case
-pascalCase+Convert Java indentifiers and package names (namespaces) to Pascal case
-cpAdds a new entry to classpath:

-srcFolderAdds a new source folder for sharpening
-nativeTypeSystemMap java classes to .NET classes with a similar functionality. For example: java.lang.Class - System.Type
-nativeInterfacesAdds an "I" in front of the interface name
-organizeUsingsAdds "using" for the types used
-fullyQualifyConverts to a fully-qualified name:
-fullyQualify File
-namespaceMappingMaps a java package name to a .NET namespace. For example:
-namespaceMapping com.db4o Db4objects.Db4o
-methodMappingMaps a java method name to a .NET method (can be method in another class). For example:
-methodMapping java.util.Date.getTime Sharpen.Runtime.ToJavaMilliseconds
-typeMappingMaps a java class to .NET type:
-typeMapping com.db4o.Db4o Db4objects.Db4o.Db4oFactory
-propertyMappingMaps a java method to .NET property:
-propertyMapping com.db4odoc.structured.Car.getPilot Pilot
-runtimeTypeNameName of the runtime class. The runtime class provides implementation for methods that don't have a direct mapping or that are simpler to map at the language level than at the sharpen level. For instance: String.substring, String.valueOf, Exception.printStackTrace, etc.
For a complete list of all the method that can be mapped to the runtime class see Configuration#runtimeMethod call hierarchy.
-headerHeader comment to be added to all converted files.
-header config/copyright_comment.txt
-xmldocSpecifies an xml-overlay file, which overrides javadoc documentation for specific classes:
-xmldoc config/sharpen/ApiOverlay.xml
-eventMappingConverts the methods to an event.
-eventAddMappingMarks the method as an event subscription method. Invocations to the method in the form .method() will be replaced by the c# event subscription idiom: +=
-conditionalCompilation
Add a condition when to translate the Java code
- -conditionalCompilation com.db4o.db4ounit.common.cs !SILVERLIGHT
-configurationClassChange the configuration class. The default is 'sharpen.core.DefaultConfiguration'


Annotation Reference:

AnnotationMeaning
@sharpen.enumMark java class to be processed as a .NET enum
@sharpen.renameSpecifies a different name for the converted type, takes a single name argument. For example:
@sharpen.rename Db4oFactory
@sharpen.privateSpecifies that the element must be declared private in the converted file, though it can be not private in the java source:
/*
* @sharpen.private
*/
public List4 _first;
@sharpen.internalSpecifies that the element must be declared internal in the converted file:
/**
 * @sharpen.internal
*/
public abstract int size();
@sharpen.protectedSpecifies that the element must be declared protected in the converted file:
/**
 * @sharpen.protected
*/
public abstract int size();
@sharpen.newAdds the C#-'new' modifier to the translated code.
@sharpen.eventLinks an event to its arguments. For example:
Java:
/**
* @sharpen.event com.db4o.events.QueryEventArgs
*/
public Event4 queryStarted();
is converted to:
public delegate void QueryEventHandler(
  object sender,
  Db4objects.Db4o.Events.QueryEventArgs args);
.......
event Db4objects.Db4o.Events.QueryEventHandler QueryStarted;
@sharpen.event.addMarks the method as an event subscription method. Invocations to the method in the form .method() will be replaced by the c# event subscription idiom: +=
@sharpen.event.onAddValid for event declaration only (SHARPEN_EVENT). Configures the method to be invoked whenever a new event handler is subscribed to the event.
@sharpen.ifAdd #if #endif declaration:
@sharpen.if
@sharpen.propertyConvert a java method as a property:
/**
 * @sharpen.property
*/
public abstract int size();
@sharpen.indexerMarks an element as an indexer property
@sharpen.ignoreSkip the element while converting
@sharpen.ignore.extendsIgnore the extends clause in Java class definition
@sharpen.ignore.implementsIgnore the implements clause in Java class definition
@sharpen.extendsAdds an extends clause to the converted class definition. For example:
Java:
/**
* @sharpen.extends System.Collections.IList
*/
public interface ObjectSet {...
converts to
public interface IObjectSet : System.Collections.IList
@sharpen.partialMarks the converted class as partial
@sharpen.removeMarks a method invocation that should be removed
@sharpen.remove.first
Removes the first line of the method/constructor when converting to C#:
/**
* @sharpen.remove.first
*/
public void doSomething(){
    System.out.println("Java");
    NextMethod();
}
converts to:
public void DoSomething(){
    NextMethod();
}
@sharpen.structMarks class to be converted as c# struct
@sharpen.unwrap
When a method is marked with this annotation
all method calls are removed. This is useful for removing conversion methods when their aren't required in C#.
/*
* @sharpen.unwrap
*/
public Iterable toIterable(Object[] array){
   return Arrays.asList(array);
}
public void doSomething(Object[] objs){
  Iterable iterable = toIterable(objs);
  // do something with the iterable
}
Is converted to:
public IEnumerable ToIterable(object[] array){
    return Arrays.AsList(array);
}
public void doSomething(object[] objs){
   Iterable iterable = objs;
   // do something with the iterable
}
@sharpen.attribute
Adds an attribute to the converted code:
/*
* @sharpen.attribute TheAttribute
*/
public void doSomething(){}
Will be converted to:
[TheAttribute]
public void DoSomething(){}
@sharpen.macroAdd a replace-pattern macro to your code.



Refactoring Legacy Systems

In his book Working Effectively with Legacy Code (Robert C. Martin Series) Robert C. Martin defined legacy systems as systems with no unit testing code.

I have many experiences working with and refactoring legacy systems. Usually, the moment the word "refactoring" pops up in our head, is when the system is too messy and not just without unit testing:

  • The whole system is monolithic. It only can be divided into modules conceptually, but not physically. That is you can never successfully compile part of it separately. 
  • Modules boundaries are blur. No clear responsibility is defined and followed.
  • Dependencies are complex. Singletons are defined and referenced everywhere.  No only they are depended, themselves are dependent on our singletons.
  • ...
In my experience, to successfully refactor a legacy system, I usually go though the following steps:

Refactor building scripts to allow build modules separately. I usually refactor module by module: that is by extracting a cohesive collection of responsibilities into a sub module once at a time. The may depend on other refactored modules, but they should never depend on the monolithic chunk they are originally extracted from. Building modules separately is a good sign of dependency decoupling.

Setup testing environment. The most significant obstacle in refactoring is not that we don't know what's the right thing to do, but that we are afraid that bugs may be introduced. Martin suggest that characterization test code that define existing behavior should be written first. After that we can be more confident when modifying code.

Define and refactor out modules one at a time.  I define modules by their responsibilities. Cohesive responsibilities can be put into one module. Then the real job of code modification begins. Both Robert C. Martin's book and  Martin Fowler and Kent Beck's book gives lots of techniques to show you how to do this.

Write demo programs if unit testing is hard. To be honest, some modules are very hard to unit test, such as 3d rendering related modules. But we can always write some demo programs that uses the module we have just refactored to show that it's self functions is complete and correct.

Some more advice are:
  • Choose a good IDE differs a lot. To be more specific, I strongly recommend Intellij IDEA which I think is a must have tool for me when refactoring.
  •  Decoupling dependency is the most important job. Even if it may introduce some ugly code during the process, you should finish decoupling first. After that, more refactoring is very easy, and that's when you can fix these ugly code introduced earlier.
  • Read Robert C. Martin's book first before you do any refactoring job. It's very practical.

Finding memory leaks in Actionscript programs

It is true that Adobe Flash is dying. In its official blog FLASH & THE FUTURE OF INTERACTIVE CONTENT, Adobe said it will "stop updating and distributing the Flash Player at the end of 2020". But before that happens, we still need to find a way to support our existing AS3 game because millions of players are playing it.

In my experience, AS3 is not a nice programming language. More sadly, it doesn't have very friendly tools to help developing. Flash Builder is buggy when project structure is getting complicated.

And there is no good tool to help find memory leaks in AS3 programs, neither scout nor flash builder. But AS3 is a language that can easy end up with memory leak bugs, due to it's event registration mechanism.

In the end, we have to spend a few weaks to build our own AS3 memory profiling tool.

It has three parts:

  • A apparat based code injection tool named "apparat profiler", which captures all objects that are instantiated.
  • A AS3 library named "profiler.swc" that we can record object when "object instantation" is captured by "apparat profiler". It also is responsible of sending out recorded objects after requested.
  • A MAT based tool we can receive and analysis recorded objects.



There are conditions we need be carefully of:
  • Not all objects are created via AS3 code, so they can't be captured. The walk around is  to run though all recorded objects and see if they have reference to any objects that aren't captured yet.
  • The whole process is slow. But it's ok since finding a memory leak is very hard and more time consuming then without it.

Drawing Git Branch Graphs with gitgraphjs

Recently I have to write a PPT to share with colleages about how to use beyond compare to assist merging. To tell things clearly, I want to draw lots of git branch graphs. Using tools such as Microsoft Visio is one option, but I want a more easy way.

After some searching, I found this amazing tool: http://gitgraphjs.com/. With a few lines of javascript code, it can easily draw the following graph:

It almost satisfies all my needs, except that I want add some identification notes to the nodes, so that I can refer them clearly when presenting.

After some code modification, I successfully added a number to each node, as ire.n the following picture.

The final code is checkin to https://github.com/shawn11ZX/gitgraph.js  and the PPT is shared at slideshare