The online racing simulator
Helpful functions/tips
2
(28 posts, started )
I have been getting annoyed at how TimeSpan structs in .NET do not support XML serialisation, so I wrote my own immutable LFS time struct, which I've called Elapsed. It includes pretty much everything you may need for describing times in LFS and also supports XML serialisation.

using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace DarkTimes.Lfs
{
/// <summary>
/// Represents an elapsed time span in LFS.
/// </summary>
[Serializable]
public struct Elapsed : IComparable<Elapsed>, IXmlSerializable
{
#region Fields
private long totalMilliseconds;
#endregion

#region Properties
public int Hours
{
get { return (int)(this.totalMilliseconds / 3600000); }
}

public int Minutes
{
get { return (int)(this.totalMilliseconds / 60000 % 60); }
}

public int Seconds
{
get { return (int)(this.totalMilliseconds / 1000 % 60); }
}

public int Milliseconds
{
get { return (int)(this.totalMilliseconds % 1000); }
}

public int TotalSeconds
{
get { return (int)(this.totalMilliseconds / 1000); }
}

public long TotalMilliseconds
{
get { return this.totalMilliseconds; }
}

public bool IsZero
{
get { return (this.totalMilliseconds == 0); }
}
#endregion

#region Constructors
public Elapsed(long totalMilliseconds)
{
this.totalMilliseconds = totalMilliseconds;
}

public Elapsed(int hours, int minutes, int seconds, int milliseconds)
{
this.totalMilliseconds = hours * 3600000;
this.totalMilliseconds += minutes * 60000;
this.totalMilliseconds += seconds * 1000;
this.totalMilliseconds += milliseconds;
}
#endregion

#region Methods
public Elapsed Add(Elapsed value)
{
return new Elapsed(this.totalMilliseconds + value.totalMilliseconds);
}

public Elapsed Subtract(Elapsed value)
{
return new Elapsed(this.totalMilliseconds - value.totalMilliseconds);
}

public override string ToString()
{
if (this.Hours > 0)
{
return string.Format("{0}:{1:00}:{2:00}.{3:000}", this.Hours, this.Minutes, this.Seconds, this.Milliseconds);
}
return string.Format("{0}:{1:00}.{2:000}", this.Minutes, this.Seconds, this.Milliseconds);
}

public override bool Equals(object obj)
{
return ((obj is Elapsed) && (this == (Elapsed)obj));
}

public override int GetHashCode()
{
return ((int)totalMilliseconds ^ (int)(totalMilliseconds >> 32));
}
#endregion

#region IComparable
public int CompareTo(Elapsed other)
{
if (this.totalMilliseconds > other.totalMilliseconds)
{
return 1;
}
else if (this.totalMilliseconds < other.totalMilliseconds)
{
return -1;
}
return 0;
}
#endregion

#region IXmlSerializable
public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader reader)
{
if (!reader.IsEmptyElement)
{
long ms = 0;
if (long.TryParse(reader.ReadString(), out ms))
{
this.totalMilliseconds = ms;
}
reader.ReadEndElement();
}
}

public void WriteXml(XmlWriter writer)
{
writer.WriteString(this.totalMilliseconds.ToString());
}
#endregion

#region Static Methods
public static Elapsed FromSeconds(int seconds)
{
return new Elapsed(seconds * 1000);
}

public static Elapsed FromMilliseconds(long milliseconds)
{
return new Elapsed(milliseconds);
}

public static byte[] ToBinary(Elapsed time)
{
return BitConverter.GetBytes(time.totalMilliseconds);
}

public static Elapsed FromBinary(byte[] bytes)
{
return new Elapsed(BitConverter.ToInt64(bytes, 0));
}
#endregion

#region Operators
public static Elapsed operator +(Elapsed a, Elapsed b)
{
return new Elapsed(a.totalMilliseconds + b.totalMilliseconds);
}

public static Elapsed operator -(Elapsed a, Elapsed b)
{
return new Elapsed(a.totalMilliseconds - b.totalMilliseconds);
}

public static Elapsed operator *(Elapsed a, Elapsed b)
{
return new Elapsed(a.totalMilliseconds * b.totalMilliseconds);
}

public static Elapsed operator /(Elapsed a, Elapsed b)
{
return new Elapsed(a.totalMilliseconds / b.totalMilliseconds);
}

public static bool operator ==(Elapsed a, Elapsed b)
{
return (a.totalMilliseconds == b.totalMilliseconds);
}

public static bool operator !=(Elapsed a, Elapsed b)
{
return (a.totalMilliseconds != b.totalMilliseconds);
}

public static bool operator >(Elapsed a, Elapsed b)
{
return (a.totalMilliseconds > b.totalMilliseconds);
}

public static bool operator <(Elapsed a, Elapsed b)
{
return (a.totalMilliseconds < b.totalMilliseconds);
}
#endregion
}
}

Quote from nikka :if playernode > finishnode: distance = finishnode - playernode + maxnode.
if playernode <= finishnode: distance = finishnode - playernode.

Distance is then each players distance to finishnode. Closest = leader.

Lol, that's great!

fDistance = ((iPlyLaps * iNodeCount) + iPlyNode) / (iSrvLaps * iNodeCount);

Where numbers closer to 1.0 are further into the race . Also, times this number by ten, and you get the percent your done with the race .
-
(DarkTimes) DELETED by DarkTimes
I've noticed some .NET programs access LFS pubstat with user/pass for authentication, but without encrypting the password*. Encrypting a password with MD5 in .NET is very simple, there's no reason not to do so.

Here is a quick example.


<?php 
using System
;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

string ComputeMd5Hash(string value) {
    
byte[] hash MD5.Create().ComputeHash(ASCIIEncoding.ASCII.GetBytes(value));

    return 
String.Join(String.Empty, hash.Select(=> h.ToString("x")));
}

// You use it like this...
string passwordHash ComputeMd5Hash(myPassword);
?>

The output of this method should match the output of the PHP md5 function.

* I also see some of these programs store the users password in plain text in a configuration file, which is like leaving the keys to your house under a plant pot in the garden. At the very least you should encrypt the password before you store it.

It would be easy to create some fake addon that read that configuration file and sent the password to me so I could steal your LFS account. I would never do this, but it would be trivial to do so using this method.

Custom addons should not store any passwords at all, as it is too big a security vulnerability. Even if the password was stored using MD5 encryption it would not take too long to crack using a rainbow table attack.
2

Helpful functions/tips
(28 posts, started )
FGED GREDG RDFGDR GSFDG