public void PreProcessGameList(ref JObject Paramaters, ref List <GameData> RawGames, ref Dictionary <string, JObject> ExtraData)
        {
            bool DoProxy = true;

            try
            {
                DoProxy = Paramaters["__pluginProxy"]?.Value <bool?>() ?? DoProxy;
            }
            catch { }

            bool ShowSource = false;

            try
            {
                ShowSource = Paramaters["__pluginShowSource"]?.Value <bool?>() ?? ShowSource;
            }
            catch { }

            bool ShowStatus = false;

            try
            {
                ShowStatus = Paramaters["__pluginShowStatus"]?.Value <bool?>() ?? ShowStatus;
            }
            catch { }

            bool QueryServers = false;

            try
            {
                QueryServers = Paramaters["__pluginQueryServers"]?.Value <bool?>() ?? QueryServers;
            }
            catch { }

            if (QueryServers)
            {
                lock (pongCache)
                {
                    pongCache.Where(dr => dr.Value.cacheTime.AddSeconds(30) < DateTime.UtcNow).Select(dr => dr.Key).ToList().ForEach(dr => pongCache.Remove(dr));
                }
            }

            long rowIdCounter = -1;

            {
                GameData hardCodedGame = new GameData()
                {
                    addr        = @"0.0.0.0:17770",
                    clientReqId = 0,
                    gameId      = "BZ2",
                    lastUpdate  = DateTime.UtcNow,
                    rowId       = rowIdCounter--,
                    rowPW       = string.Empty,
                    timeoutSec  = 300,
                    //updatePw = string.Empty
                };
                hardCodedGame.GameAttributes.Add(new CustomGameDataField()
                {
                    Key = "n", Value = "\"IonDriver Bismuth (Raknet Master2 Emulator)\""
                });
                hardCodedGame.GameAttributes.Add(new CustomGameDataField()
                {
                    Key = "l", Value = "\"1\""
                });
                hardCodedGame.GameAttributes.Add(new CustomGameDataField()
                {
                    Key = "m", Value = "\"bismuth\""
                });
                //hardCodedGame.GameAttributes.Add(new CustomGameDataField("d", string.Empty));
                //hardCodedGame.GameAttributes.Add(new CustomGameDataField("k", 1.ToString()));
                //hardCodedGame.GameAttributes.Add(new CustomGameDataField("t", 7.ToString()));
                //hardCodedGame.GameAttributes.Add(new CustomGameDataField("r", @"@ZA@d1"));
                //hardCodedGame.GameAttributes.Add(new CustomGameDataField("v", @"S1"));

                RawGames.Add(hardCodedGame);
            }

            JObject statusData = null;

            if (DoProxy && ShowStatus)
            {
                statusData = new JObject();
            }

            if (DoProxy)
            {
                object counterLock = new object();
                int    counter     = sources.Count;

                sources.AsParallel().ForAll(dr =>
                {
                    RemoteCallStatus cacheType = RemoteCallStatus.cached;
                    try
                    {
                        if (dr.Date == null || dr.Date.AddMilliseconds(dr.Stale) < DateTime.UtcNow)
                        {
                            cacheType = RemoteCallStatus.none;
                            //lock (dr)
                            dr.WebRequestActive.Wait(); //await dr.WebRequestActive.WaitAsync();
                            try
                            {
                                // make sure another thread didn't do this for us while we were locked
                                if (dr.Date == null || dr.Date.AddMilliseconds(dr.Stale) < DateTime.UtcNow)
                                {
                                    try
                                    {
                                        using (var client = new HttpClient())
                                        {
                                            client.Timeout = TimeSpan.FromMilliseconds(dr.Timeout);
                                            //var response = await client.GetAsync(dr.Url);
                                            var responseTask = client.GetAsync(dr.Url);
                                            responseTask.Wait();
                                            if (responseTask.IsCompleted && !responseTask.IsCanceled && !responseTask.IsFaulted)
                                            {
                                                var response = responseTask.Result;

                                                if (response.IsSuccessStatusCode)
                                                {
                                                    dr.LastData = JObject.Parse(response.Content.ReadAsStringAsync().Result);
                                                    dr.Date     = DateTime.UtcNow;
                                                    cacheType   = RemoteCallStatus.@new;
                                                }
                                                else if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                                {
                                                    // we failed to get data and it's too old, so destroy the cache
                                                    dr.LastData = null;
                                                    dr.Date     = DateTime.UtcNow;
                                                    cacheType   = RemoteCallStatus.expired;
                                                }
                                            }
                                            else if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                            {
                                                // we failed to get data and it's too old, so destroy the cache
                                                dr.LastData = null;
                                                dr.Date     = DateTime.UtcNow;
                                                cacheType   = RemoteCallStatus.expired;
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                        {
                                            dr.LastData = null;
                                            dr.Date     = DateTime.UtcNow;
                                        }
                                    }
                                }
                            }
                            finally
                            {
                                dr.WebRequestActive.Release();
                            }
                        }
                    }
                    //catch(Exception ex)
                    //{
                    //    Console.WriteLine(ex.ToString());
                    //}
                    finally
                    {
                        if (ShowStatus)
                        {
                            var tmp        = new JObject();
                            tmp["updated"] = dr.Date;
                            tmp["status"]  = cacheType.ToString();
                            tmp["success"] = dr.LastData != null;
                            lock (statusData)
                            {
                                statusData[dr.ProxySource] = tmp;
                            }
                        }

                        lock (counterLock)
                        {
                            counter--;
                        }
                    }
                }); // the async member inside appears to be causing it to not join, but I can't await it so I have to do a block

                while (counter > 0)
                {
                    Thread.Sleep(100);
                }

                HashSet <int> usedPorts = new HashSet <int>()
                {
                    17770
                };                                                     // start with hardcoded game already there
                // clone list so that it can't be modified under us by another thread
                List <ListSource> sourcesClone = sources.ToList();
                foreach (ListSource source in sourcesClone)
                {
                    if (source.LastData != null)
                    {
                        RawGames.AddRange(((JArray)(source.LastData["GET"])).Cast <JObject>().ToList().Select(dr =>
                        {
                            string addressPossibleRemap = string.Empty;
                            try
                            {
                                string[] urlbits = dr["__addr"].Value <string>().Split(':');
                                if (urlbits.Length > 0 && urlbits.Length <= 2 && urlbits[0] == "0.0.0.0")
                                {
                                    int portNum = 17770;
                                    string port = urlbits.Length > 1 ? urlbits[1] : "17770";
                                    if (!int.TryParse(port, out portNum))
                                    {
                                        portNum = 17770;
                                    }

                                    while (usedPorts.Contains(portNum))
                                    {
                                        portNum++;
                                    }
                                    usedPorts.Add(portNum);
                                    if (portNum != 17770)
                                    {
                                        addressPossibleRemap = urlbits[0] + ":" + portNum;
                                    }
                                    else
                                    {
                                        addressPossibleRemap = dr["__addr"].Value <string>();
                                    }
                                }
                                else
                                {
                                    addressPossibleRemap = dr["__addr"].Value <string>();
                                }
                            }
                            catch
                            {
                                addressPossibleRemap = dr["__addr"].Value <string>();
                            }

                            try
                            {
                                GameData remoteGame = new GameData()
                                {
                                    addr        = addressPossibleRemap,//dr["__addr"].Value<string>(),
                                    clientReqId = dr["__clientReqId"]?.Value <long>(),
                                    gameId      = dr["__gameId"]?.Value <string>() ?? "BZ2",
                                    lastUpdate  = DateTime.UtcNow,
                                    rowId       = rowIdCounter--,
                                    rowPW       = string.Empty,
                                    timeoutSec  = dr["__timeoutSec"]?.Value <long>() ?? 60,
                                    //updatePw = string.Empty
                                };

                                dr.Properties().ToList().ForEach(dx =>
                                {
                                    if (!dx.Name.StartsWith("__") && dx.Value.Type != JTokenType.Null)
                                    {
                                        remoteGame.GameAttributes.Add(new CustomGameDataField()
                                        {
                                            Key = dx.Name, Value = (dx.Value.Type == JTokenType.String ? ("\"" + dx.Value.ToString() + "\"") : dx.Value.ToString())
                                        });
                                    }
                                });

                                if (ShowSource)
                                {
                                    remoteGame.GameAttributes.Add(new CustomGameDataField()
                                    {
                                        Key = "proxySource", Value = "\"" + source.ProxySource + "\""
                                    });
                                }

                                //rawGames.Add(kebbzGame);
                                return(remoteGame);
                            }
                            catch (Exception ex)
                            {
                            }
                            return(null);
                        }).Where(dr => dr != null));
                    }
                }
            }

            if (QueryServers)
            {
                RawGames.AsParallel().ForAll(game =>
                {
                    {
                        RaknetPong packetOut = new RaknetPong();// { Players = true, Teams = true, ServerInfo = false };

                        IPEndPoint endPoint = null;
                        {
                            Uri url;
                            IPAddress _ip;
                            if (Uri.TryCreate(String.Format("http://{0}", game.addr), UriKind.Absolute, out url) &&
                                IPAddress.TryParse(url.Host, out _ip))
                            {
                                endPoint = new IPEndPoint(_ip, url.IsDefaultPort ? 17770 : url.Port);
                            }
                        }

                        if (endPoint != null)
                        {
                            try
                            {
                                lock (pongCache)
                                {
                                    if (pongCache.ContainsKey(endPoint))
                                    {
                                        game.CustomAttributes.Add("pong", pongCache[endPoint].data);
                                        return;
                                    }
                                }

                                UdpClient udpServer = new UdpClient(0);

                                byte[] dataSend  = packetOut.GetPacket();
                                var receivedData = udpServer.ReceiveAsync();
                                udpServer.SendAsync(dataSend, dataSend.Length, endPoint).Wait();

                                receivedData.Wait(1000);
                                if (receivedData.IsCompleted && !receivedData.IsCanceled && !receivedData.IsFaulted)
                                {
                                    var receivedData2 = receivedData.Result;

                                    RaknetPongResponse rakPong = null;

                                    using (MemoryStream mem = new MemoryStream(receivedData2.Buffer))
                                        using (BinaryReader reader = new BinaryReader(mem))
                                        {
                                            UInt32 PacketType = reader.ReadUInt32();
                                            if (PacketType != 0x0000001c)
                                            {
                                                return;
                                            }

                                            byte nul = reader.ReadByte();
                                            if (nul != 0x00)
                                            {
                                                return;
                                            }

                                            UInt32 Pong = reader.ReadUInt32();
                                            if (Pong != packetOut.Ping)
                                            {
                                                return;
                                            }

                                            UInt64 Unknown1 = reader.ReadUInt64();

                                            byte Switch1 = reader.ReadByte();
                                            if (Switch1 != 0x00 && Switch1 != 0xff)
                                            {
                                                return;
                                            }

                                            byte Switch2 = reader.ReadByte();
                                            if (Switch2 != 0x00 && Switch2 != 0xff)
                                            {
                                                return;
                                            }

                                            byte Switch3 = reader.ReadByte();
                                            if (Switch3 != 0x00 && Switch3 != 0xff)
                                            {
                                                return;
                                            }

                                            nul = reader.ReadByte();
                                            if (nul != 0x00)
                                            {
                                                return;
                                            }

                                            UInt32 Unknown2 = reader.ReadUInt32();
                                            UInt32 Unknown3 = reader.ReadUInt32();
                                            UInt32 Unknown4 = reader.ReadUInt32();

                                            rakPong = new RaknetPongResponse(reader);

                                            byte[] ZLibData = reader.ReadBytes(rakPong.m_CompressedLen);

                                            byte[] Remainder = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position + 1));

                                            ZLibData = ZLibData.Skip(2).ToArray();
                                            byte[] uncompressedData = new byte[1038];
                                            FixedBufferDecompress(ZLibData, ref uncompressedData);


                                            using (var compressedStream = new MemoryStream(uncompressedData))
                                                using (var compressedStreamReader = new BinaryReader(compressedStream))
                                                {
                                                    rakPong.CompressedData = new CompressibleRaknetPongResponse(compressedStreamReader);
                                                    rakPong.CompressedData.CurrentPlayerCount = rakPong.CurPlayers;
                                                }
                                        }

                                    if (rakPong != null)
                                    {
                                        JObject customRakObject = JObject.FromObject(rakPong);
                                        game.CustomAttributes.Add("pong", customRakObject);

                                        lock (pongCache)
                                        {
                                            pongCache[endPoint] = new PongCacheData()
                                            {
                                                cacheTime = DateTime.UtcNow,
                                                data      = customRakObject
                                            };
                                        }
                                    }
                                }
                            }
                            catch { }
                        }
                    }
                });
            }

            if (statusData != null)
            {
                ExtraData["proxyStatus"] = statusData;
            }

            //return rawGames;
        }
        public void PreProcessGameList(ref JObject Paramaters, ref List <GameData> RawGames, ref Dictionary <string, JObject> ExtraData)
        {
            bool DoProxy = true;

            try
            {
                DoProxy = Paramaters["__pluginProxy"]?.Value <bool?>() ?? DoProxy;
            }
            catch { }

            bool ShowSource = false;

            try
            {
                ShowSource = Paramaters["__pluginShowSource"]?.Value <bool?>() ?? ShowSource;
            }
            catch { }

            bool ShowStatus = false;

            try
            {
                ShowStatus = Paramaters["__pluginShowStatus"]?.Value <bool?>() ?? ShowStatus;
            }
            catch { }

            long rowIdCounter = -1;

            /*{
             *  GameData hardCodedGame = new GameData()
             *  {
             *      addr = @"0.0.0.0:17770",
             *      clientReqId = 0,
             *      gameId = "BZ2",
             *      lastUpdate = DateTime.UtcNow,
             *      rowId = rowIdCounter--,
             *      rowPW = string.Empty,
             *      timeoutSec = 300,
             *      //updatePw = string.Empty
             *  };
             *  hardCodedGame.GameAttributes.Add(new CustomGameDataField() { Key = "n", Value = @"SW9uRHJpdmVyIEJpc211dGggKE1hc3RlciBFbXVsYXRvcikAAAAAAA==" }); // IonDriver Bismuth (Master Emulator)
             *  hardCodedGame.GameAttributes.Add(new CustomGameDataField() { Key = "l", Value = @"1" });
             *  hardCodedGame.GameAttributes.Add(new CustomGameDataField() { Key = "m", Value = @"bismuth" });
             *  //hardCodedGame.GameAttributes.Add(new CustomGameDataField("d", string.Empty));
             *  //hardCodedGame.GameAttributes.Add(new CustomGameDataField("k", 1.ToString()));
             *  //hardCodedGame.GameAttributes.Add(new CustomGameDataField("t", 7.ToString()));
             *  //hardCodedGame.GameAttributes.Add(new CustomGameDataField("r", @"@ZA@d1"));
             *  //hardCodedGame.GameAttributes.Add(new CustomGameDataField("v", @"S1"));
             *
             *  rawGames.Add(hardCodedGame);
             * }*/

            JObject statusData = null;

            if (DoProxy && ShowStatus)
            {
                statusData = new JObject();
            }

            if (DoProxy)
            {
                object counterLock = new object();
                int    counter     = sources.Count;

                sources.AsParallel().ForAll(dr =>
                {
                    RemoteCallStatus cacheType = RemoteCallStatus.cached;
                    try
                    {
                        if (dr.Date == null || dr.Date.AddMilliseconds(dr.Stale) < DateTime.UtcNow)
                        {
                            cacheType = RemoteCallStatus.none;
                            //lock (dr)
                            dr.WebRequestActive.Wait(); //await dr.WebRequestActive.WaitAsync();
                            try
                            {
                                // make sure another thread didn't do this for us while we were locked
                                if (dr.Date == null || dr.Date.AddMilliseconds(dr.Stale) < DateTime.UtcNow)
                                {
                                    try
                                    {
                                        using (var client = new HttpClient())
                                        {
                                            client.Timeout = TimeSpan.FromMilliseconds(dr.Timeout);
                                            //var response = await client.GetAsync(dr.Url);
                                            var responseTask = client.GetAsync(dr.Url);
                                            responseTask.Wait();
                                            if (responseTask.IsCompleted && !responseTask.IsCanceled && !responseTask.IsFaulted)
                                            {
                                                var response = responseTask.Result;

                                                if (response.IsSuccessStatusCode)
                                                {
                                                    dr.LastData = JObject.Parse(response.Content.ReadAsStringAsync().Result);
                                                    dr.Date     = DateTime.UtcNow;
                                                    cacheType   = RemoteCallStatus.@new;
                                                }
                                                else if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                                {
                                                    // we failed to get data and it's too old, so destroy the cache
                                                    dr.LastData = null;
                                                    dr.Date     = DateTime.UtcNow;
                                                    cacheType   = RemoteCallStatus.expired;
                                                }
                                            }
                                            else if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                            {
                                                // we failed to get data and it's too old, so destroy the cache
                                                dr.LastData = null;
                                                dr.Date     = DateTime.UtcNow;
                                                cacheType   = RemoteCallStatus.expired;
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        if (dr.Date == null || dr.Date.AddMilliseconds(dr.MaxStale) < DateTime.UtcNow)
                                        {
                                            dr.LastData = null;
                                            dr.Date     = DateTime.UtcNow;
                                        }
                                    }
                                }
                            }
                            finally
                            {
                                dr.WebRequestActive.Release();
                            }
                        }
                    }
                    //catch(Exception ex)
                    //{
                    //    Console.WriteLine(ex.ToString());
                    //}
                    finally
                    {
                        if (ShowStatus)
                        {
                            var tmp        = new JObject();
                            tmp["updated"] = dr.Date;
                            tmp["status"]  = cacheType.ToString();
                            tmp["success"] = dr.LastData != null;
                            lock (statusData)
                            {
                                statusData[dr.ProxySource] = tmp;
                            }
                        }

                        lock (counterLock)
                        {
                            counter--;
                        }
                    }
                }); // the async member inside appears to be causing it to not join, but I can't await it so I have to do a block

                while (counter > 0)
                {
                    Thread.Sleep(100);
                }

                HashSet <int> usedPorts = new HashSet <int>()
                {
                    17770
                };                                                     // start with hardcoded game already there
                // clone list so that it can't be modified under us by another thread
                List <ListSource> sourcesClone = sources.ToList();
                foreach (ListSource source in sourcesClone)
                {
                    if (source.LastData != null)
                    {
                        RawGames.AddRange(((JArray)(source.LastData["GET"])).Cast <JObject>().ToList().Select(dr =>
                        {
                            //string addressPossibleRemap = string.Empty;
                            //addressPossibleRemap = "0.0.0.0";

                            try
                            {
                                GameData remoteGame = new GameData()
                                {
                                    addr        = null,//addressPossibleRemap,//dr["__addr"].Value<string>(),
                                    clientReqId = dr["__clientReqId"]?.Value <long>(),
                                    gameId      = dr["__gameId"]?.Value <string>() ?? "BZCC",
                                    lastUpdate  = DateTime.UtcNow,
                                    rowId       = rowIdCounter--,
                                    rowPW       = string.Empty,
                                    timeoutSec  = dr["__timeoutSec"]?.Value <long>() ?? 60,
                                    //updatePw = string.Empty
                                };

                                dr.Properties().ToList().ForEach(dx =>
                                {
                                    if (!dx.Name.StartsWith("__") && dx.Value.Type != JTokenType.Null)
                                    {
                                        remoteGame.GameAttributes.Add(new CustomGameDataField()
                                        {
                                            Key = dx.Name, Value = (dx.Value.Type == JTokenType.String ? ("\"" + dx.Value.ToString() + "\"") : dx.Value.ToString())
                                        });
                                    }
                                });

                                if (ShowSource)
                                {
                                    remoteGame.GameAttributes.Add(new CustomGameDataField()
                                    {
                                        Key = "proxySource", Value = $"\"{source.ProxySource}\""
                                    });
                                }

                                //rawGames.Add(kebbzGame);
                                return(remoteGame);
                            }
                            catch (Exception ex)
                            {
                            }
                            return(null);
                        }).Where(dr => dr != null));
                    }
                }
            }

            if (statusData != null)
            {
                ExtraData["proxyStatus"] = statusData;
            }

            //return rawGames;
        }