public void MapSchemaInt8Test()
    {
        var state = new SchemaTest.MapSchemaInt8.MapSchemaInt8();

        byte[] bytes = { 128, 171, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 129, 1, 255, 1, 128, 0, 163, 98, 98, 98, 1, 128, 1, 163, 97, 97, 97, 1, 128, 2, 163, 50, 50, 49, 1, 128, 3, 163, 48, 50, 49, 1, 128, 4, 162, 49, 53, 1, 128, 5, 162, 49, 48, 1 };

        var refs = new Colyseus.Schema.ColyseusReferenceTracker();

        state.Decode(bytes, null, refs);

        Assert.AreEqual(state.status, "Hello world");
        Assert.AreEqual(state.mapOfInt8["bbb"], 1);
        Assert.AreEqual(state.mapOfInt8["aaa"], 1);
        Assert.AreEqual(state.mapOfInt8["221"], 1);
        Assert.AreEqual(state.mapOfInt8["021"], 1);
        Assert.AreEqual(state.mapOfInt8["15"], 1);
        Assert.AreEqual(state.mapOfInt8["10"], 1);

        byte[] addBytes = { 255, 1, 0, 5, 2 };
        state.Decode(addBytes, null, refs);

        Assert.AreEqual(state.mapOfInt8["bbb"], 1);
        Assert.AreEqual(state.mapOfInt8["aaa"], 1);
        Assert.AreEqual(state.mapOfInt8["221"], 1);
        Assert.AreEqual(state.mapOfInt8["021"], 1);
        Assert.AreEqual(state.mapOfInt8["15"], 1);
        Assert.AreEqual(state.mapOfInt8["10"], 2);
    }
    public void ArraySchemaTypesTest()
    {
        var state = new SchemaTest.ArraySchemaTypes.ArraySchemaTypes();

        byte[] bytes = { 128, 1, 129, 2, 130, 3, 131, 4, 255, 1, 128, 0, 5, 128, 1, 6, 255, 2, 128, 0, 0, 128, 1, 10, 128, 2, 20, 128, 3, 205, 192, 13, 255, 3, 128, 0, 163, 111, 110, 101, 128, 1, 163, 116, 119, 111, 128, 2, 165, 116, 104, 114, 101, 101, 255, 4, 128, 0, 232, 3, 0, 0, 128, 1, 192, 13, 0, 0, 128, 2, 72, 244, 255, 255, 255, 5, 128, 100, 129, 208, 156, 255, 6, 128, 100, 129, 208, 156 };

        state.arrayOfSchemas.OnAdd += (value, key) => Debug.Log("onAdd, arrayOfSchemas => " + key);
        state.arrayOfNumbers.OnAdd += (value, key) => Debug.Log("onAdd, arrayOfNumbers => " + key);
        state.arrayOfStrings.OnAdd += (value, key) => Debug.Log("onAdd, arrayOfStrings => " + key);
        state.arrayOfInt32.OnAdd   += (value, key) => Debug.Log("onAdd, arrayOfInt32 => " + key);

        var refs = new Colyseus.Schema.ColyseusReferenceTracker();

        state.Decode(bytes, null, refs);

        Debug.Log("Decoded 1st time!");

        Assert.AreEqual(2, state.arrayOfSchemas.Count);
        Assert.AreEqual(100, state.arrayOfSchemas[0].x);
        Assert.AreEqual(-100, state.arrayOfSchemas[0].y);
        Assert.AreEqual(100, state.arrayOfSchemas[1].x);
        Assert.AreEqual(-100, state.arrayOfSchemas[1].y);

        Assert.AreEqual(4, state.arrayOfNumbers.Count);
        Assert.AreEqual(0, state.arrayOfNumbers[0]);
        Assert.AreEqual(10, state.arrayOfNumbers[1]);
        Assert.AreEqual(20, state.arrayOfNumbers[2]);
        Assert.AreEqual(3520, state.arrayOfNumbers[3]);

        Assert.AreEqual(3, state.arrayOfStrings.Count);
        Assert.AreEqual("one", state.arrayOfStrings[0]);
        Assert.AreEqual("two", state.arrayOfStrings[1]);
        Assert.AreEqual("three", state.arrayOfStrings[2]);

        Assert.AreEqual(3, state.arrayOfInt32.Count);
        Assert.AreEqual(1000, state.arrayOfInt32[0]);
        Assert.AreEqual(3520, state.arrayOfInt32[1]);
        Assert.AreEqual(-3000, state.arrayOfInt32[2]);

        state.arrayOfSchemas.OnRemove += (value, key) => Debug.Log("onRemove, arrayOfSchemas => " + key);
        state.arrayOfNumbers.OnRemove += (value, key) => Debug.Log("onRemove, arrayOfNumbers => " + key);
        state.arrayOfStrings.OnRemove += (value, key) => Debug.Log("onRemove, arrayOfStrings => " + key);
        state.arrayOfInt32.OnRemove   += (value, key) => Debug.Log("onRemove, arrayOfInt32 => " + key);

        byte[] popBytes = { 255, 1, 64, 1, 255, 2, 64, 3, 64, 2, 64, 1, 255, 4, 64, 2, 64, 1, 255, 3, 64, 2, 64, 1 };
        state.Decode(popBytes, null, refs);
        Debug.Log("Decoded 2nd time!");

        Assert.AreEqual(1, state.arrayOfSchemas.Count);
        Assert.AreEqual(1, state.arrayOfNumbers.Count);
        Assert.AreEqual(1, state.arrayOfStrings.Count);
        Assert.AreEqual(1, state.arrayOfInt32.Count);
        Debug.Log("FINISHED");
    }
예제 #3
0
        /// <summary>
        ///     Clear all items and indices
        /// </summary>
        /// <param name="refs">Passed in for garbage collection, if needed</param>
        public void Clear(ColyseusReferenceTracker refs = null)
        {
            if (refs != null && HasSchemaChild)
            {
                foreach (IRef item in items.Values)
                {
                    refs.Remove(item.__refId);
                }
            }

            indexes.Clear();
            items.Clear();
        }
    public void MapSchemaTypesTest()
    {
        var state = new SchemaTest.MapSchemaTypes.MapSchemaTypes();

        byte[] bytes = { 128, 1, 129, 2, 130, 3, 131, 4, 255, 1, 128, 0, 163, 111, 110, 101, 5, 128, 1, 163, 116, 119, 111, 6, 128, 2, 165, 116, 104, 114, 101, 101, 7, 255, 2, 128, 0, 163, 111, 110, 101, 1, 128, 1, 163, 116, 119, 111, 2, 128, 2, 165, 116, 104, 114, 101, 101, 205, 192, 13, 255, 3, 128, 0, 163, 111, 110, 101, 163, 79, 110, 101, 128, 1, 163, 116, 119, 111, 163, 84, 119, 111, 128, 2, 165, 116, 104, 114, 101, 101, 165, 84, 104, 114, 101, 101, 255, 4, 128, 0, 163, 111, 110, 101, 192, 13, 0, 0, 128, 1, 163, 116, 119, 111, 24, 252, 255, 255, 128, 2, 165, 116, 104, 114, 101, 101, 208, 7, 0, 0, 255, 5, 128, 100, 129, 204, 200, 255, 6, 128, 205, 44, 1, 129, 205, 144, 1, 255, 7, 128, 205, 244, 1, 129, 205, 88, 2 };

        state.mapOfSchemas.OnAdd += (value, key) => Debug.Log("OnAdd, mapOfSchemas => " + key);
        state.mapOfNumbers.OnAdd += (value, key) => Debug.Log("OnAdd, mapOfNumbers => " + key);
        state.mapOfStrings.OnAdd += (value, key) => Debug.Log("OnAdd, mapOfStrings => " + key);
        state.mapOfInt32.OnAdd   += (value, key) => Debug.Log("OnAdd, mapOfInt32 => " + key);

        state.mapOfSchemas.OnRemove += (value, key) => Debug.Log("OnRemove, mapOfSchemas => " + key);
        state.mapOfNumbers.OnRemove += (value, key) => Debug.Log("OnRemove, mapOfNumbers => " + key);
        state.mapOfStrings.OnRemove += (value, key) => Debug.Log("OnRemove, mapOfStrings => " + key);
        state.mapOfInt32.OnRemove   += (value, key) => Debug.Log("OnRemove, mapOfInt32 => " + key);

        var refs = new Colyseus.Schema.ColyseusReferenceTracker();

        state.Decode(bytes, null, refs);

        Assert.AreEqual(state.mapOfSchemas.Count, 3);
        Assert.AreEqual(state.mapOfSchemas["one"].x, 100);
        Assert.AreEqual(state.mapOfSchemas["one"].y, 200);
        Assert.AreEqual(state.mapOfSchemas["two"].x, 300);
        Assert.AreEqual(state.mapOfSchemas["two"].y, 400);
        Assert.AreEqual(state.mapOfSchemas["three"].x, 500);
        Assert.AreEqual(state.mapOfSchemas["three"].y, 600);

        Assert.AreEqual(state.mapOfNumbers.Count, 3);
        Assert.AreEqual(state.mapOfNumbers["one"], 1);
        Assert.AreEqual(state.mapOfNumbers["two"], 2);
        Assert.AreEqual(state.mapOfNumbers["three"], 3520);

        Assert.AreEqual(state.mapOfStrings.Count, 3);
        Assert.AreEqual(state.mapOfStrings["one"], "One");
        Assert.AreEqual(state.mapOfStrings["two"], "Two");
        Assert.AreEqual(state.mapOfStrings["three"], "Three");

        Assert.AreEqual(state.mapOfInt32.Count, 3);
        Assert.AreEqual(state.mapOfInt32["one"], 3520);
        Assert.AreEqual(state.mapOfInt32["two"], -1000);
        Assert.AreEqual(state.mapOfInt32["three"], 2000);

        byte[] deleteBytes = { 255, 2, 64, 1, 64, 2, 255, 1, 64, 1, 64, 2, 255, 3, 64, 1, 64, 2, 255, 4, 64, 1, 64, 2 };
        state.Decode(deleteBytes, null, refs);

        Assert.AreEqual(state.mapOfSchemas.Count, 1);
        Assert.AreEqual(state.mapOfNumbers.Count, 1);
        Assert.AreEqual(state.mapOfStrings.Count, 1);
        Assert.AreEqual(state.mapOfInt32.Count, 1);
    }
    public void MapSchemaMoveNullifyTypeTest()
    {
        var state = new SchemaTest.MapSchemaMoveNullifyType.State();

        byte[] bytes = { 129, 1, 64, 255, 1, 128, 0, 161, 48, 0 };

        var refs = new Colyseus.Schema.ColyseusReferenceTracker();

        state.Decode(bytes, null, refs);

        Assert.DoesNotThrow(() =>
        {
            // FIXME: this test only passes because empty
            byte[] moveAndNullifyBytes = { 128, 1, 65 };
            state.Decode(moveAndNullifyBytes, null, refs);
        });
    }
    public void InstanceSharingTypes()
    {
        var refs   = new Colyseus.Schema.ColyseusReferenceTracker();
        var client = new SchemaTest.InstanceSharing.State();

        client.Decode(new byte[] { 130, 1, 131, 2, 128, 3, 129, 3, 255, 1, 255, 2, 255, 3, 128, 4, 255, 3, 128, 4, 255, 4, 128, 10, 129, 10, 255, 4, 128, 10, 129, 10 }, null, refs);
        Assert.AreEqual(client.player1, client.player2);
        Assert.AreEqual(client.player1.position, client.player2.position);
        Assert.AreEqual(refs.refCounts[client.player1.__refId], 2);
        Assert.AreEqual(5, refs.refs.Count);

        client.Decode(new byte[] { 130, 1, 131, 2, 64, 65 }, null, refs);
        Assert.AreEqual(null, client.player2);
        Assert.AreEqual(null, client.player2);
        Assert.AreEqual(3, refs.refs.Count);

        client.Decode(new byte[] { 255, 1, 128, 0, 5, 128, 1, 5, 128, 2, 5, 128, 3, 6, 255, 5, 128, 7, 255, 6, 128, 8, 255, 7, 128, 10, 129, 10, 255, 8, 128, 10, 129, 10 }, null, refs);
        Assert.AreEqual(client.arrayOfPlayers[0], client.arrayOfPlayers[1]);
        Assert.AreEqual(client.arrayOfPlayers[1], client.arrayOfPlayers[2]);
        Assert.AreNotEqual(client.arrayOfPlayers[2], client.arrayOfPlayers[3]);
        Assert.AreEqual(7, refs.refs.Count);

        client.Decode(new byte[] { 255, 1, 64, 3, 64, 2, 64, 1 }, null, refs);
        Assert.AreEqual(1, client.arrayOfPlayers.Count);
        Assert.AreEqual(5, refs.refs.Count);
        var previousArraySchemaRefId = client.arrayOfPlayers.__refId;

        // Replacing ArraySchema
        client.Decode(new byte[] { 130, 9, 255, 9, 128, 0, 10, 255, 10, 128, 11, 255, 11, 128, 10, 129, 20 }, null, refs);
        Assert.AreEqual(false, refs.refs.ContainsKey(previousArraySchemaRefId));
        Assert.AreEqual(1, client.arrayOfPlayers.Count);
        Assert.AreEqual(5, refs.refs.Count);

        // Clearing ArraySchema
        client.Decode(new byte[] { 255, 9, 10 }, null, refs);
        Assert.AreEqual(0, client.arrayOfPlayers.Count);
        Assert.AreEqual(3, refs.refs.Count);
    }
예제 #7
0
        /// <summary>
        ///     Decode incoming data
        /// </summary>
        /// <param name="bytes">The incoming data</param>
        /// <param name="it"><see cref="Iterator" /> used to decode. If null, will create a new one</param>
        /// <param name="refs">
        ///     <see cref="ColyseusReferenceTracker" /> for all refs found through the decoding process. If null, will
        ///     create a new one
        /// </param>
        /// <exception cref="Exception">If no decoding fails</exception>
        public void Decode(byte[] bytes, Iterator it = null, ColyseusReferenceTracker refs = null)
        {
            ColyseusDecoder decode = ColyseusDecoder.GetInstance();

            if (it == null)
            {
                it = new Iterator();
            }

            if (refs == null)
            {
                refs = new ColyseusReferenceTracker();
            }

            int totalBytes = bytes.Length;

            int  refId = 0;
            IRef _ref  = this;

            this.refs = refs;
            refs.Add(refId, _ref);

            List <DataChange> changes    = new List <DataChange>();
            OrderedDictionary allChanges = new OrderedDictionary(); // Dictionary<int, List<DataChange>>

            allChanges.Add(refId, changes);

            while (it.Offset < totalBytes)
            {
                byte _byte = bytes[it.Offset++];

                if (_byte == (byte)SPEC.SWITCH_TO_STRUCTURE)
                {
                    refId = Convert.ToInt32(decode.DecodeNumber(bytes, it));
                    _ref  = refs.Get(refId);

                    //
                    // Trying to access a reference that haven't been decoded yet.
                    //
                    if (_ref == null)
                    {
                        throw new Exception("refId not found: " + refId);
                    }

                    // create empty list of changes for this refId.
                    changes = new List <DataChange>();
                    allChanges[(object)refId] = changes;

                    continue;
                }

                bool isSchema = _ref is Schema;

                byte operation = (byte)(isSchema
                    ? (_byte >> 6) << 6 // "compressed" index + operation
                    : _byte);           // "uncompressed" index + operation (array/map items)

                if (operation == (byte)OPERATION.CLEAR)
                {
                    ((ISchemaCollection)_ref).Clear(refs);
                    continue;
                }

                int    fieldIndex;
                string fieldName = null;
                string fieldType = null;

                System.Type childType = null;

                if (isSchema)
                {
                    fieldIndex = _byte % (operation == 0 ? 255 : operation); // FIXME: JS allows (0 || 255)
                    ((Schema)_ref).fieldsByIndex.TryGetValue(fieldIndex, out fieldName);

                    // fieldType = ((Schema)_ref).fieldTypes[fieldName];
                    ((Schema)_ref).fieldTypes.TryGetValue(fieldName ?? "", out fieldType);
                    ((Schema)_ref).fieldChildTypes.TryGetValue(fieldName ?? "", out childType);
                }
                else
                {
                    fieldName = ""; // FIXME

                    fieldIndex = Convert.ToInt32(decode.DecodeNumber(bytes, it));
                    if (((ISchemaCollection)_ref).HasSchemaChild)
                    {
                        fieldType = "ref";
                        childType = ((ISchemaCollection)_ref).GetChildType();
                    }
                    else
                    {
                        fieldType = ((ISchemaCollection)_ref).ChildPrimitiveType;
                    }
                }

                object value         = null;
                object previousValue = null;
                object dynamicIndex  = null;

                if (!isSchema)
                {
                    previousValue = _ref.GetByIndex(fieldIndex);

                    if ((operation & (byte)OPERATION.ADD) == (byte)OPERATION.ADD)
                    {
                        // MapSchema dynamic index.
                        dynamicIndex = ((ISchemaCollection)_ref).GetItems() is OrderedDictionary
                            ? (object)decode.DecodeString(bytes, it)
                            : fieldIndex;

                        ((ISchemaCollection)_ref).SetIndex(fieldIndex, dynamicIndex);
                    }
                    else
                    {
                        dynamicIndex = ((ISchemaCollection)_ref).GetIndex(fieldIndex);
                    }
                }
                else if (fieldName != null) // FIXME: duplicate check
                {
                    previousValue = ((Schema)_ref)[fieldName];
                }

                //
                // Delete operations
                //
                if ((operation & (byte)OPERATION.DELETE) == (byte)OPERATION.DELETE)
                {
                    if (operation != (byte)OPERATION.DELETE_AND_ADD)
                    {
                        _ref.DeleteByIndex(fieldIndex);
                    }

                    // Flag `refId` for garbage collection.
                    if (previousValue != null && previousValue is IRef)
                    {
                        refs.Remove(((IRef)previousValue).__refId);
                    }

                    value = null;
                }

                if (fieldName == null)
                {
                    //
                    // keep skipping next bytes until reaches a known structure
                    // by local decoder.
                    //
                    Iterator nextIterator = new Iterator {
                        Offset = it.Offset
                    };

                    while (it.Offset < totalBytes)
                    {
                        if (decode.SwitchStructureCheck(bytes, it))
                        {
                            nextIterator.Offset = it.Offset + 1;
                            if (refs.Has(Convert.ToInt32(decode.DecodeNumber(bytes, nextIterator))))
                            {
                                break;
                            }
                        }

                        it.Offset++;
                    }

                    continue;
                }

                if (operation == (byte)OPERATION.DELETE)
                {
                    //
                    // FIXME: refactor me.
                    // Don't do anything.
                    //
                }
                else if (fieldType == "ref")
                {
                    refId = Convert.ToInt32(decode.DecodeNumber(bytes, it));
                    value = refs.Get(refId);

                    if (operation != (byte)OPERATION.REPLACE)
                    {
                        System.Type concreteChildType = GetSchemaType(bytes, it, childType);

                        if (value == null)
                        {
                            value = CreateTypeInstance(concreteChildType);

                            if (previousValue != null)
                            {
                                ((Schema)value).MoveEventHandlers((Schema)previousValue);

                                if (
                                    ((IRef)previousValue).__refId > 0 &&
                                    refId != ((IRef)previousValue).__refId
                                    )
                                {
                                    refs.Remove(((IRef)previousValue).__refId);
                                }
                            }
                        }

                        refs.Add(refId, (IRef)value, value != previousValue);
                    }
                }
                else if (childType == null)
                {
                    // primitive values
                    value = decode.DecodePrimitiveType(fieldType, bytes, it);
                }
                else
                {
                    refId = Convert.ToInt32(decode.DecodeNumber(bytes, it));
                    value = refs.Get(refId);

                    ISchemaCollection valueRef = refs.Has(refId)
                        ? (ISchemaCollection)previousValue
                        : (ISchemaCollection)Activator.CreateInstance(childType);

                    value = valueRef.Clone();

                    // keep reference to nested childPrimitiveType.
                    string childPrimitiveType;
                    ((Schema)_ref).fieldChildPrimitiveTypes.TryGetValue(fieldName, out childPrimitiveType);
                    ((ISchemaCollection)value).ChildPrimitiveType = childPrimitiveType;

                    if (previousValue != null)
                    {
                        ((ISchemaCollection)value).MoveEventHandlers(
                            (ISchemaCollection)previousValue);

                        if (
                            ((IRef)previousValue).__refId > 0 &&
                            refId != ((IRef)previousValue).__refId
                            )
                        {
                            refs.Remove(((IRef)previousValue).__refId);

                            List <DataChange> deletes = new List <DataChange>();
                            IDictionary       items   = ((ISchemaCollection)previousValue).GetItems();

                            foreach (object key in items.Keys)
                            {
                                deletes.Add(new DataChange
                                {
                                    DynamicIndex  = key,
                                    Op            = (byte)OPERATION.DELETE,
                                    Value         = null,
                                    PreviousValue = items[key]
                                });
                            }

                            allChanges[(object)((IRef)previousValue).__refId] = deletes;
                        }
                    }

                    refs.Add(refId, (IRef)value, valueRef != previousValue);
                }

                bool hasChange = previousValue != value;

                if (value != null)
                {
                    if (value is IRef)
                    {
                        ((IRef)value).__refId = refId;
                    }

                    if (_ref is Schema)
                    {
                        ((Schema)_ref)[fieldName] = value;
                    }
                    else if (_ref is ISchemaCollection)
                    {
                        ((ISchemaCollection)_ref).SetByIndex(fieldIndex, dynamicIndex, value);
                    }
                }

                if (hasChange)
                {
                    changes.Add(new DataChange
                    {
                        Op            = operation,
                        Field         = fieldName,
                        DynamicIndex  = dynamicIndex,
                        Value         = value,
                        PreviousValue = previousValue
                    });
                }
            }

            TriggerChanges(ref allChanges);

            refs.GarbageCollection();
        }