C#: Structuring Quake 2 query data.
Posted: Fri May 13, 2005 2:23 pm
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:
You can then access the query, like with a dictionary, through the instance of ServerState
Source code:
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);
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;
}
}
}