Page 1 of 1

C#: Structuring Quake 2 query data.

Posted: Fri May 13, 2005 2:23 pm
by Span
I imagine there aren't many .NET coders around this forum, but if anyone's ever going to take a dive into it...

Usage: Just create a new instance of ObjClient. You can then poll for a server query with it's GetData() method.

Example:

Code: Select all

ObjClient pClient = new ObjClient(new UdpClient());

ServerState pState = pClient.GetData(szServer, iPort);
You can then access the query, like with a dictionary, through the instance of ServerState

Source code:

Code: Select all

	
public class PlayerList
{
	public String szNickname;
	public int iPing;
	public int iFrags;
}

public struct ServerEntry
{
	public Object Value;
	public Object Key;

	public ServerEntry(Object szValue, Object szKey)
	{
		Key = szKey;
		Value = szValue;
	}
}

public class ServerState :IDictionary
{
	// The array of items
	private List<ServerEntry> Items;
	//private ServerEntry[] Items;
	private Int32 ItemsInUse = 0;

	public ServerState()
	{
		Items = new List<ServerEntry>();
	}

	#region IDictionary Members
	public bool IsReadOnly { get { return false; } }
	public bool Contains(object key)
	{
		Int32 index;
		return TryGetIndexOfKey(key, out index);
	}
	public bool IsFixedSize { get { return false; } }
	public void Remove(object key)
	{
		if (key == null) throw new ArgumentNullException("key");
		// Try to find the key in the DictionaryEntry array
		Int32 index;
		if (TryGetIndexOfKey(key, out index))
		{
			// If the key is found, slide all the items up.
			Array.Copy(Items.ToArray(), index + 1, Items.ToArray(), index, ItemsInUse - index - 1);
			ItemsInUse--;
		} 
		else
		{
			// If the key is not in the dictionary, just return. 
		}
	}
	public void Clear() { ItemsInUse = 0; }
	public void Add(object key, object value) 
	{
		// Add the new key/value pair even if this key already exists in the dictionary.
		//if (ItemsInUse == Items.Count)
		//    throw new InvalidOperationException("The dictionary cannot hold any more items.");
		Items.Add (new ServerEntry(value, key));
		ItemsInUse++;
	}
	public ICollection Keys
	{
		get
		{
			// Return an array where each item is a key.
			Object[] keys = new Object[ItemsInUse];
			for (Int32 n = 0; n < ItemsInUse; n++)
				keys[n] = Items[n].Key;
			return keys;
		}
	}
	public ICollection Values
	{
		get
		{
			// Return an array where each item is a value.
			Object[] values = new Object[ItemsInUse];
			for (Int32 n = 0; n < ItemsInUse; n++)
				values[n] = Items[n].Value;
			return values;
		}
	}
	public object this[object key]
	{
		get
		{   
			// If this key is in the dictionary, return its value.
			Int32 index;
			if (TryGetIndexOfKey(key, out index))
			{
				// The key was found; return its value.
				return Items[index].Value;
			} 
			else
			{
				// The key was not found; return null.
				return null;
			}
		}
			set
		{
			// If this key is in the dictionary, change its value. 
			Int32 index;
			if (TryGetIndexOfKey(key, out index))
			{
				// The key was found; change its value.
				//Items.Insert(index, (ServerEntry)value);
				ServerEntry pEntry = new ServerEntry(value, key);					Items[index] = pEntry;
			} 
			else
			{
				// This key is not in the dictionary; add this key/value pair.
				Add(key, value);
			}
		}
	}
	private Boolean TryGetIndexOfKey(Object key, out Int32 index)
	{
		for (index = 0; index < ItemsInUse; index++)
		{
			// If the key is found, return true (the index is also returned).
			if (Items[index].Key.Equals(key)) return true;
		}
	     
		// Key not found, return false (index should be ignored by the caller).
		return false;
	}
	#endregion

	private class ServerStateEnumerator : IDictionaryEnumerator
	{
		// A copy of the SimpleDictionary object's key/value pairs.
		ServerEntry[] items;
		Int32 index = -1;

		public ServerStateEnumerator(ServerState sd)
		{
			// Make a copy of the dictionary entries currently in the SimpleDictionary object.
			items = new ServerEntry[sd.Count];
			Array.Copy(sd.Items.ToArray(), 0, items, 0, sd.Count);
		}

		// Return the current item.
		public Object Current { get { ValidateIndex(); return items[index]; } }

		// Return the current dictionary entry.
		public DictionaryEntry Entry
		{
			get { return (DictionaryEntry) Current; }
		}

		// Return the key of the current item.
		public Object Key { get { ValidateIndex();  return items[index].Key; } }

		// Return the value of the current item.
		public Object Value { get { ValidateIndex();  return items[index].Value; } }

		// Advance to the next item.
		public Boolean MoveNext()
		{
			if (index < items.Length - 1) { index++; return true; }
			return false;
		}

		// Validate the enumeration index and throw an exception if the index is out of range.
		private void ValidateIndex()
		{
			if (index < 0 || index >= items.Length)
			throw new InvalidOperationException("Enumerator is before or after the collection.");
		}

		// Reset the index to restart the enumeration.
		public void Reset()
		{
			index = -1;
		}
	}
	public IDictionaryEnumerator GetEnumerator()
	{
		// Construct and return an enumerator.
		return new ServerStateEnumerator(this);
	}

	#region ICollection Members
	public bool IsSynchronized { get { return false; } }
	public object SyncRoot { get { throw new NotImplementedException(); } }
	public int Count { get { return ItemsInUse; } }
	public void CopyTo(Array array, int index) { throw new NotImplementedException(); }
	#endregion

	#region IEnumerable Members
	IEnumerator IEnumerable.GetEnumerator() 
	{
		// Construct and return an enumerator.
		return ((IDictionary)this).GetEnumerator();
	}
	#endregion
}

	public class SocketState
	{
		public UdpClient pClient;
		public const int BUFFER_SIZE = 1024;
		public byte[] buffer = new byte[BUFFER_SIZE];
		public StringBuilder sb = new StringBuilder();
		public DateTime dtPong;
		public bool bCompleted = false;
	}

	public class ObjClient
	{
		private UdpClient m_pClient;
		private int m_iPos;

		public ObjClient(UdpClient pClient)
		{
			m_pClient = pClient;
		}

		public void Close()
		{
			m_pClient.Close();
		}

		// Sort data received from server
		public ServerState Sort(String[] szItems, ref ServerState pState)
		{
			pState.Add ("playerlist", CreatePlayerList(szItems));

			for (int i=1; i<m_iPos; i++)
			{
				pState.Add(szItems[i], szItems[++i]);
			}

			return pState;
		}

		private PlayerList[] CreatePlayerList(String[] szItems)
		{
			int iLastIndex = szItems.Length;
			iLastIndex--;

			int iPos = iLastIndex;

			do
			{
				iPos--;
			}
			while (szItems[iPos].Contains("\""));

			iPos++;
			m_iPos = iPos;

			if (iPos == iLastIndex)
				return new PlayerList[0];

			int iNumClients = (iLastIndex - iPos);

			PlayerList[] pPlayerList = new PlayerList[++iNumClients];

			int iCur = 0;

			for (; iPos <= iLastIndex; iPos++)
			{
				String[] sz = szItems[iPos].Split(new Char[] { '\"' }, StringSplitOptions.RemoveEmptyEntries);

				pPlayerList[iCur] = new PlayerList();
				String[] szPingFrags = sz[0].Split(new Char[] { ' ' });
				pPlayerList[iCur].iFrags = Int32.Parse(szPingFrags[0]);
				pPlayerList[iCur].iPing = Int32.Parse(szPingFrags[1]);
				pPlayerList[iCur].szNickname = sz[1];
				iCur++;
			}

			return pPlayerList;
		}

		public ServerState GetData(String szHostname, int iPort)
		{
			SocketState so2 = new SocketState();
			ServerState pState = new ServerState();

			so2.pClient = m_pClient;

			try { m_pClient.Connect(szHostname, iPort); }
			catch (SocketException e)
			{
				pState.Add("error", e.Message);
				//pState.szError = e.Message;
				return pState;
			}

			Encoding pEncoding = Encoding.GetEncoding(1252);
			Byte[] pBytes = pEncoding.GetBytes("\xFF\xFF\xFF\xFFstatus");

			try { m_pClient.Send(pBytes, pBytes.Length); }
			catch (SocketException e) { 
				pState.Add ("error", e.Message);
				return pState;
			}

			DateTime dtPing = DateTime.Now;
			TimeSpan diff;

			try
			{
				IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 0);
				m_pClient.Client.ReceiveTimeout = 999;
				so2.buffer = m_pClient.Receive(ref ipEnd);

				DateTime dtPong = DateTime.Now;

				int iPong = 999;

				if (dtPong.Millisecond > 0)
				{
					diff = dtPong - dtPing;

					iPong = diff.Milliseconds;
				}

				String szTemp = Encoding.ASCII.GetString(so2.buffer);

				String[] szItems = szTemp.Split(new Char[] { '\\', '\n' }, StringSplitOptions.RemoveEmptyEntries);

				pState = Sort(szItems, ref pState);
				pState.Add("ping", iPong);
			}
			catch (SocketException e) { pState.Add("error", e.Message); }

			return pState;
		}
	}
}

Posted: Sat May 14, 2005 8:39 am
by aztecx
...

okay lets all give span a clap

Posted: Sat May 14, 2005 9:26 am
by fuct
only one word W H A T ?!

Posted: Sat May 14, 2005 10:38 am
by Sabotage
heh Span :)

Posted: Sat May 14, 2005 10:39 am
by Sabotage
fuct wrote:only one word W H A T ?!
fuct: maybe coz ur not smart ? :lol:

Posted: Sat May 14, 2005 3:43 pm
by fuct
always an insult lol :) Image

Posted: Fri Jun 03, 2005 9:53 am
by Span
fuct wrote:only one word W H A T ?!
It's a reusable piece of code that queries a Q2 server for it's status data and then sorts it in a dictionary (sort of a complex array).

Posted: Tue Jun 07, 2005 2:30 am
by Sweet
fuct wrote:only one word W H A T ?!
Something like that :oh:

Posted: Tue Jun 07, 2005 2:33 am
by Den
Looks interesting :) might give it a go some day.

Posted: Thu Sep 01, 2005 11:38 am
by maGro
i coded a few years in c/c++ and i might understand at least pieces of the code... but i dont get the point of this thread..

Posted: Thu Sep 01, 2005 11:52 am
by Clown
I get that it's 4 months old.

Posted: Thu Sep 01, 2005 1:26 pm
by Flunx
Mr.old never gets old
Image