Can't find demo_advanced

Options
emewen
edited March 2015 in Native
I cannot find demo_advanced in the Photon-Windows-Sdk_v4-0-0-3 download. There is only:

demo_chat
demo_loadBalancing
demo_memory
demo_particle

I was told there is a c++ example of CustomTypes in the demo_advanced demo. Missing.

*EDIT*
I found it in the OnPremise SDK. But the example I am looking for is not that great. I need to know how to serialize different types. Here is the example(Foo and Bar are just nBytes)
short SampleCustomType::serialize(nByte* const pRetVal) const
{
	if(pRetVal)
	{
		pRetVal[0] = this->mFoo;
		pRetVal[1] = this->mBar;
	}
	return 2;
}

What if I have multiple types to add?
short CharacterCreateDetails::serialize(nByte* const pRetVal) const
{
	JString test1 = JString("test"); //faking CharacterCreateDetails Jstring value
	int32 test2 = 123415; //faking CharacterCreateDetails int
	short test3 = 34; //faking CharacterCreateDetails short
	bool test4 = true; //faking CharacterCreateDetails bool
	SomeOtherCustomTypeThatHasBeenDefined test5 = new SomeOtherCustomTypeThatHasBeenDefined("some string", 1234, true);

	if (pRetVal)
	{		
		pRetVal[0] = test1; //compiler error
		pRetVal[1] = test2;
		pRetVal[2] = test3;
		pRetVal[3] = test4;
		pRetVal[4] = test5; //compiler error
	}
	return ?????; //calculate length?
}

I just don't know where to start, not enough documentation.

Comments

  • Kaiserludi
    Options
    Hi emewen.

    On the serverside there are different types of applications as top layer of the server side Photon logic. One of those is Lite and another one is LoadBalancing. The Client API for those 2 is different from each other. As Lite does not provide any help for multiserver support, while LoadBalancing does, and as it is not totally trivial to switch from Lite to LoadBalancing later on, when a customer realizes, that his game is so successful that it needs multiple game servers to provide enough capacity for all users, and also as Lite can't be used with the Photon Cloud at all, anyway, we have decided to not include any Lite demos in the Client SDKs anymore from Photon 4 onwards to not encourage people any longer to use Lite.

    demo_advanced is a Lite demo and has not yet been ported to LoadBalancing. Therefor it is not currently included in the Photon 4 Client SDKs. Please download the latest Photon 3 OnPremise C++ Client SDK for the platform of your choice to get your hands on the latest version of demo_advanced.



    About how to implement serialize() for more complex custom types:

    Well, it is really up to you.
    You have to transform your class instance into a byte-array, which needs to contain all information that you need to correctly reconstruct your class instance from it later on.
    That's all. How you archive this doesn't really matter to Photon, so do it in whatever way suits you the most, as long as your implementation behaves like documented at http://doc-api.exitgames.com/en/realtim ... 531801a180:
    serialize(nByte* const pRetVal) const

    This function serializes the payload of the instance on which it has been called, into the passed nByte-array and returns the length of that array. It is legal to pass a NULL-pointer and in that case this function still calculates the length of the data, which would have been stored in a non-NULL-pointer, but does not store any data. The behavior for providing a too small array is undefined.

    Parameters
    pRetVal the nByte-array to store the serialized payload of the instance in. Has to be of at least the needed length

    Returns
    the length of the data, that has actually been stored in the passed array

    a) You could do everything yourself by using memcpy():
    [code2=cpp]short SampleCustomType::serialize(nByte* const pRetVal) const
    {
    short length = 0;
    ExitGames::Common::JString test1 = ExitGames::Common::JString(L"test"); //faking CharacterCreateDetails JString value
    int test2 = 123415; //faking CharacterCreateDetails int
    short test3 = 34; //faking CharacterCreateDetails short
    bool test4 = true; //faking CharacterCreateDetails bool
    SomeOtherCustomTypeThatHasBeenDefined test5(L"some string", 1234, true);
    const EG_CHAR* str = test1;

    length += str?(wcslen(str)+1)*sizeof(str[0]):0;
    if(pRetVal)
    memcpy(pRetVal, str, length);
    if(pRetVal)
    memcpy(pRetVal+length, reinterpret_cast<const void*>(&test2), sizeof(test2));
    length += sizeof(test2);
    if(pRetVal)
    memcpy(pRetVal+length, reinterpret_cast<const void*>(&test3), sizeof(test3));
    length += sizeof(test3);
    if(pRetVal)
    memcpy(pRetVal+length, reinterpret_cast<const void*>(&test4), sizeof(test4));
    length += sizeof(test4);
    if(pRetVal)
    {
    const nByte* pData = test5.getRawData();
    memcpy(pRetVal+length, pData, test5.getSize());
    }
    length += test5.getSize();
    return length;
    }[/code2]

    b) You could use some existing 3rd party solution that provides serialization features

    c) You could utilize the serialization tools that the Photon Client library provides:
    [code2=cpp]void SampleCustomType::deserialize(const nByte* const pData, short length)
    {
    ExitGames::Common::DeSerializer deserializer(pData, length);
    ExitGames::Common::Object obj;
    deserializer.pop(obj);
    ExitGames::Common::JString test1 = ExitGames::Common::ValueObject<ExitGames::Common::JString>(obj).getDataCopy();
    deserializer.pop(obj);
    int test2 = ExitGames::Common::ValueObject<int>(obj).getDataCopy();
    deserializer.pop(obj);
    short test3 = ExitGames::Common::ValueObject<short>(obj).getDataCopy();
    deserializer.pop(obj);
    bool test4 = ExitGames::Common::ValueObject<bool>(obj).getDataCopy();
    deserializer.pop(obj);
    SomeOtherCustomTypeThatHasBeenDefined test5;
    test5.deserialize(ExitGames::Common::ValueObject<nByte*>(obj).getDataCopy(), *ExitGames::Common::ValueObject<nByte*>(obj).getSizes());
    }

    short SampleCustomType::serialize(nByte* const pRetVal) const
    {
    ExitGames::Common::Serializer serializer;
    serializer.push(test1);
    serializer.push(test2);
    serializer.push(test3);
    serializer.push(test4);
    nByte* pRawData = new nByte[test5.serialize(NULL)];
    short size = test5.serialize(pRawData);
    serializer.push(pRawData, size);
    delete[] pRawData;

    if(pRetVal)
    memcpy(pRetVal, serializer.getData(), serializer.getSize());

    return serializer.getSize();
    }[/code2]

    Notes to variant c):
    This variant assumes that SomeOtherCustomTypeThatHasBeenDefined also inherits from the ExitGames::Common::CustomType template.
    Instead of
    [code2=cpp]nByte* pRawData = new nByte[test5.serialize(NULL)];
    short size = test5.serialize(pRawData);
    serializer.push(pRawData, size);
    delete[] pRawData;[/code2]
    and
    [code2=cpp]SomeOtherCustomTypeThatHasBeenDefined test5;
    test5.deserialize(ExitGames::Common::ValueObject<nByte*>(obj).getDataCopy(), *ExitGames::Common::ValueObject<nByte*>(obj).getSizes());[/code2]
    you should normally be able to simply write
    [code2=cpp]serializer.push(test5);[/code2]
    and
    [code2=cpp]SomeOtherCustomTypeThatHasBeenDefined test5 = ExitGames::Common::ValueObject<SomeOtherCustomTypeThatHasBeenDefined>(obj).getDataCopy();[/code2]
    However there is a bug in the current release that prevents nested custom types from working correctly, so that you currently have to use this pRawData workaround.

    Here are modified source files for demo_advanced with the code for c) (without that workaround):
    https://dl.dropboxusercontent.com/u/429 ... leCode.zip

    This will be fixed starting with version 4.0.1.0 of the Client SDK.
  • emewen
    Options
    Wow, this is great. I have decided to use your option "C" which is working out, thank you. I can send a serialized Custom Type to the server and hit the overridden Deserialize which is great.

    But...time for another question.

    So on the client side I am using Photon C++ (Unreal). On the server side I am using Photon with plain .net (Unity). I have a proxy server that handles all traffic which redirects messages to login server, chat server, region, etc. When it comes time to deserialize the message serialized in c++ I am having issues with strings. I can't seem to tell binaryReader the correct string format:

    c++ serialize:
    //should I UTFRepresentation the JString before I send it?
    short CharacterCreateDetails::serialize(nByte* const pRetVal) const
    {
    	ExitGames::Common::Serializer serializer;
    	serializer.push(this-&gt;_characterName.UTF8Representation().cstr()); //_characterName is Photon::Common::JString
    	serializer.push(this-&gt;_characterClass.UTF8Representation().cstr()); //_characterName is Photon::Common::JString
    	serializer.push(this-&gt;_sex.UTF8Representation().cstr()); //_characterName is Photon::Common::JString
    
    	if (pRetVal)
    	{		
    		memcpy(pRetVal, serializer.getData(), serializer.getSize());
    	}
    	return serializer.getSize();
    }
    


    C# deserialize:
           //I thought I would just read the byte array to buffer and get each string and advance index by length...not so much
            private static object DeserializeCharacterCreateDetails(byte&#91;&#93; bytes)
            {
                CharacterCreateDetails ccd = new CharacterCreateDetails();
                int pos = 0;
                Encoding enc = Encoding.UTF8;
    
                using (MemoryStream m = new MemoryStream(bytes))
                {
                    using (BinaryReader r = new BinaryReader(m))
                    {
                        ccd.CharacterName = r.ReadString();  //error here "System.IO.EndOfStreamException: Unable to read beyond the end of the stream"
                        pos += enc.GetByteCount(ccd.CharacterName);
                        ccd.CharacterClass = r.ReadString();
                        pos += enc.GetByteCount(ccd.CharacterClass);
                        ccd.Sex = r.ReadString();
                        pos += enc.GetByteCount(ccd.Sex);
                    }
                }
            }
    

    I am getting "System.IO.EndOfStreamException: Unable to read beyond the end of the stream. Most likely because I am not reading/checking the string identifier byte?

    I thought I could use the static ExitGames.Client.Photon.Protocol.Deserialize(out float value, byte[] source, ref int offset) as this is looked a lot like the c++ serialize/deserialize and took care of the offset nicely. The problem was that there is not "out string" so I couldn't extract the string:

    c# deserialize with Protocol.Deserialize
    private static object DeserializeCharacterCreateDetails(byte&#91;&#93; bytes)
            {
                ComplexServerCommon.MessageObjects.CharacterCreateDetails ccd = new ComplexServerCommon.MessageObjects.CharacterCreateDetails();
                int pos = 0;
    
                ExitGames.Client.Photon.Protocol.Deserialize(ccd.CharacterName, bytes, pos);  //ccd.CharacterName so this won't compile
                ExitGames.Client.Photon.Protocol.Deserialize(ccd.CharacterClass, bytes, pos); //ccd.CharacterName so this won't compile
                ExitGames.Client.Photon.Protocol.Deserialize(ccd.Sex, bytes, pos); //ccd.CharacterName so this won't compile
    }
    


    What I am looking for is a correct implementation for the above C# deserialize and a corresponding serialize method (in c#). And thank you again for the c++ help above. Very informative.
  • Kaiserludi
    Options
    Unreal Engine 4 Clients with Unity3D Servers? Interesting. Please excuse my curiosity, but would you mind telling me the reasons for your decision to use different game engines on the client and on the server side?


    //should I UTFRepresentation the JString before I send it?
    You don't need to do this as the Photon Client already does it itself under the hood during serialization.
    Converting a JString to a UTF8String yourself before passing it to Photon just adds unnecessary overhead, because passing a UTF8String to Photon will trigger an automatic conversion to JString.

    Photon C++ Clients use UCS2 (on Windows) / UCS4 (on Unix) everywhere internally and in the API for everything before serialization and after deserialization, while transferring the serialized data over the network in UTF8.

    So, if you pass something to the Photon Client API, it should preferably be a JString, a wchar_t* or a wide string literal (L"" // note the leading L) , as that saves you the conversion from UTF8 to UCS2/UCS4 that will occur when you pass a UTF8String, a char* or a narrow string literal ("" // a literal without a leading L).

    UTF8String and JString.UTF8Representation() are mainly of interest in the situation that you hold a JString and need to pass it to some 3rd party API that uses std::string, char* or some other narrow string format.



    I have asked a colleague to have a look at your C# code.
  • emewen
    Options
    Not necessarily Unity server but just a straight .net(c#) server using the .net Photon engine. I am trying to pass a c++ photon serialized custom type to the server and deserializing it on the server(c#) side. Eventually I may serialize the same custom type on the C# server side and pass to the client c++ endpoint. Currently the issue I am having now is de/serializing on the C# side.
  • Kaiserludi
    Options
    You keep saying "C# server side", but when I look at your code ("ExitGames.Client.Photon.Protocol.Deserialize"), it looks like your are using a Photon C# Client SDK.

    So what exactly are you trying to achieve?
    a) Serializing a CustomType with a C++ Photon Client SDK and deserializing it with a C# Photon Client SDK and vice versa?
    or
    b) Serializing a CustomType with a C++ Photon Client SDK and deserializing it with the C# Photon Server SDK and vice versa?
  • emewen
    Options
    I am trying to accomplish B. The only reason I was using that client SDK on the server was because it was the only static methods I could find to deserialize an object with Photon in C#. Maybe I am confused here but I just need an example of de/serialize with 3 strings in C# that accepts the c++ serialize output above.
  • chvetsov
    chvetsov mod
    edited July 2015
    Options
    Hi, emewen.
    I did not read whole topic. just your last question. So forgive me if something still will be not clear
    On server you may use something like this
    IRpcProtocol protocol = Photon.SocketServer.Protocol.Protocols[Peer.Protocol];
    
    var stream = new MemoryStream();
    protocol.Serialize(stream, someobj);
    
    and 
    protocol.TryParse(stream, out someobj);