/// <summary>
        /// Event called when any client or host connection has a change in a network data collection.
        /// </summary>
        /// <param name="packet">The base packet containing the raw data.</param>
        /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param>
        private void ConnectionCollectionChanged(NetworkPacket packet, NetworkEventArgs data)
        {
            try
            {
                //Make sure the data is of the correct type.
                if (data.DataType == typeof(NotifyCollectionChangedEventArgs))
                {
                    //Grab the collection changed information from the data.
                    NotifyCollectionChangedEventArgs args = data.Data as NotifyCollectionChangedEventArgs;

                    //Check if we have the source collection whose items was changed.
                    if (_registeredObjects.ContainsKey(data.NetworkDataId))
                    {
                        //Get the source collection we want to manipulate
                        IList collection = _registeredObjects[data.NetworkDataId] as IList;

                        //Disable the listener for this object while we do our changes.
                        ListenerDisable((INetworkData)collection);

                        //apply the changes that occured at the client/host to our collection.
                        switch (args.Action)
                        {
                            case NotifyCollectionChangedAction.Add:
                                for (int i = 0; i < args.NewItems.Count; i++)
                                    collection.Insert(args.NewStartingIndex + i, args.NewItems[i]);
                                break;
                            case NotifyCollectionChangedAction.Move:
                                for (int i = 0; i < args.NewItems.Count; i++)
                                {
                                    object temp = collection[args.OldStartingIndex + (args.OldStartingIndex > args.NewStartingIndex ? i : 0)];
                                    collection.Remove(temp);
                                    collection.Insert(args.NewStartingIndex + i, temp);
                                }
                                break;
                            case NotifyCollectionChangedAction.Remove:
                                for (int i = 0; i < args.OldItems.Count; i++)
                                    collection.RemoveAt(args.OldStartingIndex + i);
                                break;
                            case NotifyCollectionChangedAction.Replace:
                                for (int i = 0; i < args.NewItems.Count; i++)
                                    collection[args.OldStartingIndex + i] = args.NewItems[i];
                                break;
                            case NotifyCollectionChangedAction.Reset:
                                collection.Clear();
                                break;
                        }
                        //Enable the listener for our collection.
                        ListenerEnable((INetworkData)collection);

                        //Forward if necessary.
                        data.Forward();
                    }
                    else if (OnNotificationOccured != null)
                        OnNotificationOccured(data, string.Format("A CollectionChanged packet was received for a collection on a network id but the network id object was not found in registered objects."));
                }
                else if (OnNotificationOccured != null)
                    OnWarningOccured(data, new Warning(string.Format("A network packet for collection changed was received but that data was of an invalid type. Expected a type of '{0}' but received '{1}'.", typeof(NotifyCollectionChangedEventArgs).FullName, data.DataType.FullName)));
            }
            catch (Exception e)
            {
                ThrowException(data, e);
            }
        }
 /// <summary>
 /// Event called when any client or host connection has had any of its registered network data changed property.
 /// </summary>
 /// <param name="packet">The base packet containing the raw data.</param>
 /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param>
 /// <exception cref="NetworkLibrary.Exceptions.ParsingException" />
 /// <exception cref="System.Exception" />
 private void ConnectionPropertyChanged(NetworkPacket packet, NetworkEventArgs data)
 {
     try
     {
         //Check to see if the property changed packet we recieved was found in the registered objects collection.
         if (_registeredObjects.ContainsKey(data.NetworkDataId) && data.PropertyName != "Count")
         {
             try
             {
                 //Disable listening on the object while we pass in the value.
                 //This is done so that it doesn't end in an infinite loop between the host and the client.
                 this.ListenerDisable(_registeredObjects[data.NetworkDataId]);
                 //Set the value of the property on the object
                 _registeredObjects[data.NetworkDataId].GetType().GetProperty(data.PropertyName).SetValue(_registeredObjects[data.NetworkDataId], data.Data, null);
                 this.ListenerEnable(_registeredObjects[data.NetworkDataId]);
             }
             catch (Exception e)
             {
                 throw new ParsingException(string.Format("Error while passing the value '{0}' of type '{1}' to the following property '{2}' on an object of type '{3}'. Error message received: {4}", data.Data, data.DataType.FullName, data.PropertyName, _registeredObjects[data.NetworkDataId].GetType().FullName, e.Message));
             }
         }
     }
     catch (Exception e)
     {
         ThrowException(this, e);
     }
 }
        /// <summary>
        /// Event that is called automatically when a NetworkRequest was recieved.
        /// </summary>
        /// <param name="packet">The base packet containing the raw data.</param>
        /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param>
        private void ReceivedNetworkRequest(NetworkPacket packet, NetworkEventArgs data)
        {
            //Prelimenary checking on whether the data is of correct type
            if (data.DataType == typeof(RequestNetworkData))
            {
                // The data passed over the network is a real Request. Processing the request.
                try
                {
                    //Create the response for the request and pass in all data of the request over to the
                    //the response. This is done so the InternalName as well as other data is passed over.
                    RequestNetworkData response = new RequestNetworkData(data.Data as RequestNetworkData);

                    //Start processing the request.
                    switch (response.RequestType)
                    {
                        case RequestNetworkDataType.RequestType:
                            //The connection is requesting a data of specific type. Search the registered
                            //objects for any objects that fit the description.
                            for (int i = 0; i < _registeredObjects.Count; i++)
                                if (_registeredObjects.ElementAt(i).Value.GetType().FullName == response.ClassTypeName)
                                {
                                    response.Data = _registeredObjects.ElementAt(i).Value;
                                    break;
                                }
                            break;
                        case RequestNetworkDataType.RequestName:
                            //The connection is requesting name for it's object. Pass in a random
                            //generated identifier.
                            response.NetworkId = GetNewNetworkId(response.ClassTypeName);
                            break;
                        case RequestNetworkDataType.RequestData:
                            //The connection is requesting a data with specific NetworkId.
                            //Return the object containing that NetworkId.
                            response.Data = this._registeredObjects[response.NetworkId];
                            break;
                    }
                    //Send the response over the network to the client/host.
                    _network.SendSingleRawEvent((int)CorePacketCode.NetworkDataRequestResponse, new Serialiser(true).Serialise(response), packet.Source);
                }
                catch (Exception e)
                {
                    //An unknown error occured. Since this is not critical part of the NetworkLibrary we
                    //pass it on as a Warning.
                    if (OnWarningOccured != null)
                        OnWarningOccured(this, new Warning("A network request was received but an unknown error occured while processing the request.", e));
                }
            }
            //Received a packet containing the code for a Request but the data was of an invalid type.
            //Since this is not a critical part of the NetworkLibrary we pass it on as a Warning.
            else if (OnWarningOccured != null)
                OnWarningOccured(this, new Warning("A network request was received but was of an invalid format. Request was truncated."));
        }
        /// <summary>
        /// Event that is called automatically when receiving a response to a Network Request.
        /// </summary>
        /// <param name="packet">The base packet containing the raw data.</param>
        /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param>
        private void ReceivedNetworkRequestResponse(NetworkPacket packet, NetworkEventArgs data)
        {
            //Prelimenary checking on whether the data is of correct type
            if (data.DataType == typeof(RequestNetworkData))
            {
                // The data passed over the network is a real Response. Processing the response.
                try
                {
                    //Retreave the original request that was the source of the response.
                    RequestNetworkData internalRequest = _requestedData[(data.Data as RequestNetworkData).InternalName];

                    //Pass all data retreived from the response into the request.
                    internalRequest.NetworkId = (data.Data as RequestNetworkData).NetworkId;
                    internalRequest.Data = (data.Data as RequestNetworkData).Data;
                    //Check whether the request was requesting data or type of an object.
                    //If it is, we register into our local NetworkLibrary automatically.
                    if ((internalRequest.RequestType == RequestNetworkDataType.RequestData ||
                        internalRequest.RequestType == RequestNetworkDataType.RequestType) &&
                        internalRequest.Data != null)
                        //The request was requesting data. Registering it automatically.
                        RegisterRecursive(internalRequest.Data as INetworkData);

                    lock (internalRequest)
                    {
                        //This is important. In many cases when processing data in the NetworkLibrary and data
                        //needs to be requested, the request is sent and the thread that is doing the processing
                        //is put on sleep. With this we send a pulse into the thread to wake it up so it can continue
                        //on the processing and finish the process it started.
                        Monitor.Pulse(internalRequest);
                    }
                    //Remove the request from our collection. Since the request has been sent, processed and finished
                    //we don't need it anymore.
                    _requestedData.Remove(internalRequest.InternalName);
                }
                catch (Exception e)
                {
                    //An unknown error occured. Since this could result in a method or a thread being paused forever
                    //we pass it on as a real Exception.
                    ThrowException(this, new Exception("A network response was received but an unknown error occured while processing the request.", e));
                }
            }
            //Received a packet containing the code for a Request but the data was of an invalid type.
            //Since this could be random junk we pass it on as a Warning.
            else if (OnWarningOccured != null)
                OnWarningOccured(this, new Warning("A network request response was received but was of an invalid format. Request was truncated."));
        }
예제 #5
0
파일: Lobby.cs 프로젝트: TheThing/Shooter
        protected void StartGame(object source, NetworkEventArgs args)
        {
            Game.Network.UnregisterEvent((int)PacketCode.NewPlayer, NewPlayer);
            Game.Network.UnregisterEvent((int)PacketCode.Chat, NewChat);
            Game.Network.UnregisterEvent((int)PacketCode.StartGame, StartGame);
            Game.Network.UnregisterEvent((int)CorePacketCode.PropertyUpdated, UpdateGameSettings);

            string map = args.Data as string;
            string[] splitted = map.Split('\n');

            _game.Board = new Board(_game, _game.Map);
            if (Game.Network.NetworkType == NetworkType.Host)
            {
                _game.Board.Load(map.Replace("\n", ""), splitted[0].Length, splitted.Length);
                Game.Network.NetworkDataHandler.RegisterRecursive(_game.Board);
            }

            _mainMenu.Options.Insert(8, new Option("Start", 10));
            _mainMenu.Options.Insert(8, new Option("-", 10));
            _mainMenu.ReDraw();

            string text = "-- Host has started the game, please click Start --";
            for (int i = _chat.Length - 1; i >= 0; i--)
            {
                string temp = _chat[i].Text;
                _chat[i].Text = text;
                text = temp;
                _chat[i].Draw();
            }
        }
예제 #6
0
 /// <summary>
 /// Event callback method to handle when a new client has been connected.
 /// </summary>
 /// <param name="packet">The source network packet.</param>
 /// <param name="args">The NetworkEventArgs containing all the data of the packet.</param>
 private void ClientConnected(NetworkPacket packet, NetworkEventArgs args)
 {
     //Check to see if the version of the network library matches.
     if (args.BasePacket.Header.GetValue<int>("ver") != this._header.GetValue<int>("ver"))
     {
         //The client is using a different version. We therefore disconnect him.
         Disconnect(args.SourceConnection);
         //Set handled to true so other events don't get called.
         args.Handled = true;
     }
     else
         _clientConnections.Add(args.SourceConnection);
 }
예제 #7
0
 /// <summary>
 /// Run a registered event with the relevant arguments.
 /// </summary>
 /// <param name="method">The method to be run.</param>
 /// <param name="eventArgs">Arguments to pass the the method.</param>
 private void ExecuteEvent(delegateNetworkEvent method, NetworkEventArgs eventArgs)
 {
     try
     {
         method(eventArgs.BasePacket, eventArgs);
     }
     catch (Exception e)
     {
         ThrowOnExceptionOccured(this, e);
     }
 }
예제 #8
0
파일: Lobby.cs 프로젝트: TheThing/Shooter
        protected void NewPlayer(object source, NetworkEventArgs args)
        {
            if (args.BasePacket.Header.GetValue<string>("prog") != "shooter" && Game.Network.NetworkType == NetworkType.Host)
            {
                (Game.Network as ConnectionHost).Disconnect(args.SourceConnection);
                return;
            }
            Player p = args.Data as Player;
            p.Connection = args.SourceConnection;
            int index = 0;
            for (; index < _game.Players.Length; index++)
            {
                if (_game.Players[index] == null)
                    break;
            }
            if (index == 4)
            {
                if (Game.Network.NetworkType == NetworkType.Host)
                    (Game.Network as ConnectionHost).Disconnect(args.SourceConnection);
                return;
            }
            _game.Players[index] = p;

            args.Forward();
            if (Game.Network.NetworkType == NetworkType.Host)
            {
                Game.Network.SendEvent((int)PacketCode.Chat, "-- player " + p.Name + " has connected --", true, args.SourceConnection);
                args.SendReply((int)CorePacketCode.AssignNewHeaderValue, new NetworkLibrary.Utilities.Header("id", index));
            }
            UpdatePlayers();
        }
예제 #9
0
파일: Shop.cs 프로젝트: TheThing/Shooter
 protected void PlayerDisconnected(object source, NetworkEventArgs args)
 {
     Player p = args.Data as Player;
     for (int i = 0; i < _game.Players.Length; i++)
         if (_game.Players[i] == p)
         {
             if ((_playerIndex == 0 && i < 2) || (_playerIndex == 2 && i >= 2))
                 Game.Network.SendEvent((int)PacketCode.PlayerSelectionChanged, new int[] { i % 2, -1 }, true);
             break;
         }
 }
예제 #10
0
 /// <summary>
 /// Event callback to handle a new value assignment for the header.
 /// </summary>
 /// <param name="packet">The source network packet.</param>
 /// <param name="data">NetworkEventArgs containing all relevant data.</param>
 private void AssignValueInHeader(NetworkPacket packet, NetworkEventArgs data)
 {
     if (data.DataType == typeof(Header))
         this._header.Add(data.Data as Header);
 }
예제 #11
0
파일: Shop.cs 프로젝트: TheThing/Shooter
 void PlayerSelectionChanged(object source, NetworkEventArgs args)
 {
     int[] values = args.Data as int[];
     DrawOption(values[0], _playerSelection[values[0]], false);
     _playerSelection[values[0]] = values[1];
     if (_playerSelection[values[0]] != -1)
         DrawOption(values[0], _playerSelection[values[0]], true);
     else
     {
         DrawOption(values[0], _guns.Count, true);
         if (_playerSelection[0] == -1 && _playerSelection[1] == -1)
         {
             Menu m = new Menu(Label.CreateLabelArrayFromText("Press any key to continue."));
             m.Start(-1, 5);
         }
     }
     args.Forward();
 }
예제 #12
0
파일: Shop.cs 프로젝트: TheThing/Shooter
 //Network related code
 void PlayerNetworkBuys(object source, NetworkEventArgs args)
 {
     UpdatePlayer((int)args.Data);
     DrawOption((int)args.Data, _playerSelection[(int)args.Data], true);
     args.Forward();
 }
예제 #13
0
 private void PropertyUpdated(NetworkPacket packet, NetworkEventArgs args)
 {
     SendPacket(packet, packet.Source);
 }
예제 #14
0
 private void ClearBullet(object sender, NetworkEventArgs args)
 {
     (args.Data as Shot).Clear();
 }
예제 #15
0
 /// <summary>
 /// Execute all registered event with specific code id in the dictionary.
 /// </summary>
 /// <param name="eventArgs">The event data containing the packet in a parsed format.</param>
 /// <param name="id">The id of the event to execute.</param>
 /// <exception cref="System.Exception" />
 private void ExecuteEventsWithId(NetworkEventArgs eventArgs, int id)
 {
     //Check to see if we have any registered events for that event id.
     if (_registeredEvents.ContainsKey(id))
         //Run all registered events in order.
         for (int i = 0; i < _registeredEvents[id].Count; i++)
         {
             //Check to see if we have a dispatcher that we can use to run the event
             //in a threadsafe enviroment
             if (_dispatcher != null)
                 _dispatcher.Invoke((delegateEmpty)delegate
                 {
                     ExecuteEvent(_registeredEvents[id][i], eventArgs);
                 });
             //Since we don't have a dispacher we check to see if we are allowed to ignoer it.
             else if (_ignoreDispatcher)
                 //We are allowed to ignore the dispatcher. This will run the event directly in
                 //an unsafe multithread form. The programmer will have to take care of all the locks
                 //and such.
                 ExecuteEvent(_registeredEvents[id][i], eventArgs);
             else
                 //Throw an exception on the fact that dispatcher had not been properly
                 //assigned.
                 ThrowOnExceptionOccured(this, new Exception("Dispatcher had not been specified and ignoring it was disabled"));
             if (_disposed || eventArgs.Handled)
                 return;
         }
 }
예제 #16
0
파일: Lobby.cs 프로젝트: TheThing/Shooter
 protected void NewChat(object source, NetworkEventArgs args)
 {
     string text = args.Data as string;
     for (int i = _chat.Length - 1; i >= 0; i--)
     {
         string temp = _chat[i].Text;
         _chat[i].Text = text;
         text = temp;
         _chat[i].Draw();
     }
     args.Forward();
 }
예제 #17
0
 /// <summary>
 /// Execute all registerd events for a specific packet code.
 /// </summary>
 /// <param name="packet">The source packet to send to the events.</param>
 private void ExecuteRegisteredEvents(NetworkPacket packet)
 {
     NetworkEventArgs args;
     if (_packetParsers.ContainsKey(packet.Id))
     {
         args = _packetParsers[packet.Id].ParsePacket(packet);
         if (args == null)
             return;
     }
     else
     {
         args = new NetworkEventArgs(packet);
         if (packet.Message != null)
         {
             try
             {
                 args.Data = new Serialiser().Deserialise(packet.Message);
             }
             catch (Exception e)
             {
                 ThrowOnExceptionOccured(packet, e);
                 return;
             }
         }
         else
             args.Data = null;
     }
     ExecuteEventsWithId(args, (int)CorePacketCode.PreviewPacket);
     if (packet.Id == (int)CorePacketCode.PropertyUpdated)
         ExecuteEventsWithId(args, (int)CorePacketCode.PreviewPropertyUpdated);
     if (packet.Id == (int)CorePacketCode.CollectionChanged)
         ExecuteEventsWithId(args, (int)CorePacketCode.PreviewCollectionChanged);
     ExecuteEventsWithId(args, packet.Id);
 }
예제 #18
0
파일: Lobby.cs 프로젝트: TheThing/Shooter
 protected void PlayerDisconnected(object source, NetworkEventArgs args)
 {
     Player p = args.Data as Player;
     for (int i = 0; i < _game.Players.Length; i++)
         if (_game.Players[i] == p)
         {
             _game.Players[i] = null;
             break;
         }
     if (_active)
         UpdatePlayers();
 }
        /// <summary>
        /// Parse an incoming string from an incoming packet and return a specialised NetworkEventArgs containg property changed information.
        /// </summary>
        /// <param name="item">The packet to parse.</param>
        /// <returns>Specialised NetworkEventArgs.</returns>
        public NetworkEventArgs ParsePacket(NetworkPacket packet)
        {
            //Split the message into maximum 3 parts because of the property changed packet format:
            //networkid:property_name:value
            string[] data = packet.Message.Split(new char[] { ':' }, 3);

            //Create the holder for our results.
            NetworkEventArgs result = new NetworkEventArgs(packet);

            //Make sure the message was correct.
            if (data.Length == 3)
            {
                INetworkDataHandler dataHandler = ObjectFactory.GetInstance<INetworkDataHandler>();

                //Check to see if we have the object that had it's property changed.
                if (dataHandler.RegisteredObjects.ContainsKey(data[0]))
                {
                    //We have the object so now we extract the information we want from the packet.
                    result.NetworkDataId = data[0];
                    result.PropertyName = data[1];

                    try
                    {
                        //Deserialise the property value.
                        result.Data = new Serialiser().Deserialise(data[2]);

                        //Return our results.
                        return result;
                    }
                    catch (Exception e)
                    {
                        //We received a valid packet but encountered an error while deserialising.
                        //We pass this on as a warning.
                        if (OnWarningOccured != null)
                            OnWarningOccured(packet, new Warning(string.Format("Error while deserialising a property changed packet. Error message received: {0}.", e.Message), e));
                    }
                }
                else if (OnNotificationOccured != null)
                        OnNotificationOccured(packet, string.Format("Error while processing an incoming property changed packet. Network object name of '{0}' was not found in the collection", data[0]));
            }
            else if (OnNotificationOccured != null)
                OnNotificationOccured(packet, "Property updated was not in a correct format. Acepting a message in format of 'name:property:value'");

            //If we ever get here it means we encountered an error. We therefore return a null value.
            return null;
        }
예제 #20
0
파일: Lobby.cs 프로젝트: TheThing/Shooter
 protected void UpdateGameSettings(object source, NetworkEventArgs args)
 {
     lock (_menuSettings)
     {
         bool changed = false;
         (_menuSettings.Options[1] as OptionValue).Content = "<none>";
         if (_game.Map != null)
             if (!string.IsNullOrEmpty(_game.Map.Description))
                 if ((_menuSettings.Options[1] as OptionValue).Content != _game.Map.Description)
                 {
                     (_menuSettings.Options[1] as OptionValue).Content = _game.Map.Description;
                     changed = true;
                 }
         if ((_menuSettings.Options[0] as OptionNumeric).Value != _game.DefaultHealth)
         {
             (_menuSettings.Options[0] as OptionNumeric).Value = _game.DefaultHealth;
             changed = true;
         }
         if (changed)
             _menuSettings.ReDraw();
     }
 }
        /// <summary>
        /// Parse an incoming string from an incoming packet and return a specialised NetworkEventArgs.
        /// </summary>
        /// <param name="item">The packet to parse.</param>
        /// <returns>Specialised NetworkEventArgs.</returns>
        public NetworkEventArgs ParsePacket(NetworkPacket packet)
        {
            //Split the message into maximum 6 parts so we can extract it's data. The format is as follows:
            //networkid:collectionChangedAction:startingIndexForNewItems:startingIndexForOldItems:ListOfItemsRemovedOrAdded
            string[] data = packet.Message.Split(new char[] { ':' }, 6);

            //Make sure the maximum length was archieved.
            if (data.Length == 6)
            {
                //Get the data handler.
                INetworkDataHandler dataHandler = ObjectFactory.GetInstance<INetworkDataHandler>();

                //Make sure we have the item whose collection was changed.
                if (dataHandler.RegisteredObjects.ContainsKey(data[0]))
                {
                    //Create the holder for our results.
                    NetworkEventArgs result = new NetworkEventArgs(packet);

                    //Assign the relevant values.
                    result.NetworkDataId = data[0];
                    IList itemList;
                    int newIndex, oldIndex, oldCount, intAction;
                    try
                    {
                        //Deserialise and convert the data to it's correct form.
                        itemList = new Serialiser().Deserialise(data[5]) as IList;
                        intAction = Convert.ToInt32(data[1]);
                        newIndex = Convert.ToInt32(data[2]);
                        oldIndex = Convert.ToInt32(data[3]);
                        oldCount = Convert.ToInt32(data[4]);
                    }
                    catch (Exception e)
                    {
                        if (OnWarningOccured != null)
                            OnWarningOccured(packet, new Warning("An unknown error occured while deserialising a collection changed packet that was received. Message received: " + e.Message, e));
                        return null;
                    }

                    NotifyCollectionChangedAction action = (NotifyCollectionChangedAction)intAction;

                    //Create a new instance of notify collection changed that contains the relevant
                    //information about the changes in the collection.
                    switch (action)
                    {
                        case NotifyCollectionChangedAction.Add:
                            result.Data = new NotifyCollectionChangedEventArgs(action, itemList, newIndex);
                            break;
                        case NotifyCollectionChangedAction.Move:
                            result.Data = new NotifyCollectionChangedEventArgs(action, itemList, newIndex, oldIndex);
                            break;
                        case NotifyCollectionChangedAction.Remove:
                            result.Data = new NotifyCollectionChangedEventArgs(action, itemList, oldIndex);
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            result.Data = new NotifyCollectionChangedEventArgs(action, itemList, new bool[oldCount], newIndex);
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            result.Data = new NotifyCollectionChangedEventArgs(action);
                            break;
                    }

                    //Return our results.
                    return result;
                }
                else if (OnNotificationOccured != null)
                    OnNotificationOccured(packet, string.Format("Collection changed parser was called but the network id of '{0}' was not found in the registered objects.", data[0]));

            }
            else if (OnNotificationOccured != null)
                OnNotificationOccured(packet, "Collection changed packet was not in a correct format. Acepting a message in format of 'name:newstartindex:oldstartindex:value'");

            //If we ever get here it means we encountered an error. We therefore return a null value.
            return null;
        }