// // InSim4.cs // // Author: // Robert BRACCAGNI alias Gai-Luron // // Copyright (c) 2010 Gai-Luron // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #define MONO using System; using System.Collections; using System.Threading; namespace InSim { public enum tyre { TYRE_R1, // 0 TYRE_R2, // 1 TYRE_R3, // 2 TYRE_R4, // 3 TYRE_ROAD_SUPER, // 4 TYRE_ROAD_NORMAL, // 5 TYRE_HYBRID, // 6 TYRE_KNOBBLY, // 7 TYRE_NUM, TYRE_NO_CHANGE, }; enum vtn { VOTE_NONE, // 0 - no vote VOTE_END, // 1 - end race VOTE_RESTART, // 2 - restart VOTE_QUALIFY, // 3 - qualify VOTE_NUM }; enum bfn { BFN_DEL_BTN, // 0 - instruction : delete one button (must set ClickID) BFN_CLEAR, // 1 - instruction : clear all buttons made by this insim instance BFN_USER_CLEAR, // 2 - info : user cleared this insim instance's buttons BFN_REQUEST, // 3 - user request : SHIFT+B or SHIFT+I - request for buttons }; enum pen { PENALTY_NONE, // 0 PENALTY_DT, // 1 PENALTY_DT_VALID, // 2 PENALTY_SG, // 3 PENALTY_SG_VALID, // 4 PENALTY_30, // 5 PENALTY_45, // 6 PENALTY_NUM } enum penr { PENR_UNKNOWN, // 0 - unknown or cleared penalty PENR_ADMIN, // 1 - penalty given by admin PENR_WRONG_WAY, // 2 - wrong way driving PENR_FALSE_START, // 3 - starting before green light PENR_SPEEDING, // 4 - speeding in pit lane PENR_STOP_SHORT, // 5 - stop-go pit stop too short PENR_STOP_LATE, // 6 - compulsory stop is too late PENR_NUM }; enum obh { OBH_LAYOUT, //1 // an added object OBH_CAN_MOVE, //2 // a movable object OBH_WAS_MOVING, //4 // was moving before this hit OBH_ON_SPOT //8 // object in original position }; enum uco { UCO_CIRCLE_ENTER, //1 entered a circle UCO_CIRCLE_LEAVE, //2 left a circle UCO_CP_FWD, //4 crossed cp in forward direction UCO_CP_REV, //8 crossed cp in reverse direction }; enum BTN_style { ISB_C1 = 1, ISB_C2 = 2, ISB_C4 = 4, ISB_CLICK = 8, ISB_LIGHT = 16, ISB_DARK = 32, ISB_LEFT = 64, ISB_RIGHT = 128 }; enum PIT_work { PSE_NOTHING = 0, // bit 0 (1) PSE_STOP = 2, // bit 1 (2) PSE_FR_DAM = 4, // bit 2 (4) PSE_FR_WHL = 8, // etc... PSE_LE_FR_DAM = 16, PSE_LE_FR_WHL = 32, PSE_RI_FR_DAM = 64, PSE_RI_FR_WHL = 128, PSE_RE_DAM = 256, PSE_RE_WHL = 512, PSE_LE_RE_DAM = 1024, PSE_LE_RE_WHL = 2048, PSE_RI_RE_DAM = 4096, PSE_RI_RE_WHL = 8192, PSE_BODY_MINOR = 16384, PSE_BODY_MAJOR = 32768, PSE_SETUP = 65536, PSE_REFUEL = 131072, }; enum confirm { CONF_MENTIONED = 1, CONF_CONFIRMED = 2, CONF_PENALTY_DT = 4, CONF_PENALTY_SG = 8, CONF_PENALTY_30 = 16, CONF_PENALTY_45 = 32, CONF_DID_NOT_PIT = 64 } enum ISF { RES_0 = 1, RES_1 = 2, // bit 1 : spare LOCAL = 4, // bit 2 : spare MSO_COLS = 8, // bit 3 : spare NLP = 16, // bit 4 : set to receive NLP packets MCI = 32, // bit 5 : set to receive MCI packets CON = 64, // bit 6 : set to receive CON packets OBH = 128, // bit 7 : set to receive OBH packets HLV = 256, // bit 8 : receive HLV packets AXM_LOAD = 512, // bit 9 : receive AXM when loading a layout AXM_EDIT = 1024, // bit 10 : receive AXM when changing objects REQ_JOIN = 2048 // bit 11 : process join requests } enum TypePack { ISP_NONE, // 0 : not used ISP_ISI, // 1 - instruction : insim initialise ISP_VER, // 2 - info : version info ISP_TINY, // 3 - both ways : multi purpose ISP_SMALL, // 4 - both ways : multi purpose ISP_STA, // 5 - info : state info ISP_SCH, // 6 - instruction : single character ISP_SFP, // 7 - instruction : state flags pack ISP_SCC, // 8 - instruction : set car camera ISP_CPP, // 9 - both ways : cam pos pack ISP_ISM, // 10 - info : start multiplayer ISP_MSO, // 11 - info : message out ISP_III, // 12 - info : hidden /i message ISP_MST, // 13 - instruction : type message or /command ISP_MTC, // 14 - instruction : message to a connection ISP_MOD, // 15 - instruction : set screen mode ISP_VTN, // 16 - info : vote notification ISP_RST, // 17 - info : race start ISP_NCN, // 18 - info : new connection ISP_CNL, // 19 - info : connection left ISP_CPR, // 20 - info : connection renamed ISP_NPL, // 21 - info : new player (joined race) ISP_PLP, // 22 - info : player pit (keeps slot in race) ISP_PLL, // 23 - info : player leave (spectate - loses slot) ISP_LAP, // 24 - info : lap time ISP_SPX, // 25 - info : split x time ISP_PIT, // 26 - info : pit stop start ISP_PSF, // 27 - info : pit stop finish ISP_PLA, // 28 - info : pit lane enter / leave ISP_CCH, // 29 - info : camera changed ISP_PEN, // 30 - info : penalty given or cleared ISP_TOC, // 31 - info : take over car ISP_FLG, // 32 - info : flag (yellow or blue) ISP_PFL, // 33 - info : player flags (help flags) ISP_FIN, // 34 - info : finished race ISP_RES, // 35 - info : result confirmed ISP_REO, // 36 - both ways : reorder (info or instruction) ISP_NLP, // 37 - info : node and lap packet ISP_MCI, // 38 - info : multi car info ISP_MSX, // 39 - instruction : type message ISP_MSL, // 40 - instruction : message to local computer ISP_CRS, // 41 - info : car reset ISP_BFN, // 42 - both ways : delete buttons / receive button requests ISP_AXI, // 43 - info : autocross layout information ISP_AXO, // 44 - info : hit an autocross object ISP_BTN, // 45 - instruction : show a button on local or remote screen ISP_BTC, // 46 - info : sent when a user clicks a button ISP_BTT, // 47 - info : sent after typing into a button ISP_RIP, // 48 - both ways : replay information packet ISP_SSH, // 49 - both ways : screenshot ISP_CON, // 50 - info : contact between cars (collision report) ISP_OBH, // 51 - info : contact car + object (collision report) ISP_HLV, // 52 - info : report incidents that would violate HLVC ISP_PLC, // 53 - instruction : player cars ISP_AXM, // 54 - both ways : autocross multiple objects ISP_ACR, // 55 - info : admin command report ISP_HCP, // 56 - instruction : car handicaps ISP_NCI, // 57 - info : new connection - extra info for host ISP_JRR, // 58 - instruction : reply to a join request (allow / disallow) ISP_UCO, // 59 - info : report InSim checkpoint / InSim circle ISP_OCO, // 60 - instruction : object control (currently used for lights) ISP_TTC, // 61 - instruction : multi purpose - target to connection ISP_SLC, // 62 - info : connection selected a car ISP_CSC, // 63 - info : car state changed }; enum TypeTiny { TINY_NONE, // 0 - keep alive : see "maintaining the connection" TINY_VER, // 1 - info request : get version TINY_CLOSE, // 2 - instruction : close insim TINY_PING, // 3 - ping request : external progam requesting a reply TINY_REPLY, // 4 - ping reply : reply to a ping request TINY_VTC, // 5 - both ways : game vote cancel (info or request) TINY_SCP, // 6 - info request : send camera pos TINY_SST, // 7 - info request : send state info TINY_GTH, // 8 - info request : get time in hundredths (i.e. SMALL_RTP) TINY_MPE, // 9 - info : multi player end TINY_ISM, // 10 - info request : get multiplayer info (i.e. ISP_ISM) TINY_REN, // 11 - info : race end (return to race setup screen) TINY_CLR, // 12 - info : all players cleared from race TINY_NCN, // 13 - info request : get NCN for all connections TINY_NPL, // 14 - info request : get all players TINY_RES, // 15 - info request : get all results TINY_NLP, // 16 - info request : send an IS_NLP TINY_MCI, // 17 - info request : send an IS_MCI TINY_REO, // 18 - info request : send an IS_REO TINY_RST, // 19 - info request : send an IS_RST TINY_AXI, // 20 - info request : send an IS_AXI - AutoX Info TINY_AXC, // 21 - info : autocross cleared TINY_RIP, // 22 - info request : send an IS_RIP - Replay Information Packet TINY_NCI, // 23 - info request : get NCI for all guests (on host only) TINY_ALC, // 24 - info request : send a SMALL_ALC (allowed cars) TINY_AXM, // 25 - info request : send IS_AXM packets for the entire layout TINY_SLC, // 26 - info request : send IS_SLC packets for all connections }; enum TypeSmall // the fourth byte of IS_SMALL packets is one of these { SMALL_NONE, // 0 : not used SMALL_SSP, // 1 - instruction : start sending positions SMALL_SSG, // 2 - instruction : start sending gauges SMALL_VTA, // 3 - report : vote action SMALL_TMS, // 4 - instruction : time stop SMALL_STP, // 5 - instruction : time step SMALL_RTP, // 6 - info : race time packet (reply to GTH) SMALL_NLI, // 7 - instruction : set node lap interval SMALL_ALC, // 8 - both ways : set or get allowed cars (TINY_ALC) }; enum TypeTTC // the fourth byte of IS_SMALL packets is one of these { TTC_NONE, // 0 : not used TTC_SEL, // 1 - info request : send IS_AXM for a layout editor selection } public class Connect { public class ConnectException : Exception { public ConnectException(string message) : base(message) { } public ConnectException(string message, Exception innerException) : base(message, innerException) { } } public class objPacket { public DateTime dateReceived; public byte[] recvPacket; public objPacket(byte[] precvPacket) { recvPacket = precvPacket; dateReceived = DateTime.Now; } } public bool connected = false; public string Product; public string Version; public int InSimVersion; private System.Net.Sockets.UdpClient uc; private TcpConnection.Connection tc; private bool TCPmode; bool waitReceiveLow = true; public bool waitReceive = true; private Encoder myEncoder = new Encoder(); private string Host; private int Port; private GLDebug.Debug myDebug; public Queue InsimPacks = new Queue(500); public Thread TInsimReceive = null; System.Net.IPEndPoint remoteEP = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0); public Connect( GLDebug.Debug pmyDebug ) { this.myDebug = pmyDebug; } public void insimConnect( string host, int port, string adminPassword, string mode, string nameApp, bool isLocal, bool TCPmode) { this.TCPmode = TCPmode; this.Host = host; this.Port = port; if ( this.TCPmode ) insimConnectTCP( host, port, adminPassword, mode, nameApp, isLocal); else insimConnectUDP( host, port, adminPassword, mode, nameApp, isLocal); // Start Thread Receiving packet // Why a thread, because of Lagging option TInsimReceive = new Thread(new ThreadStart(this.TInSimReceive)); TInsimReceive.Start(); } public void insimConnectTCP( string host, int port, string adminPassword, string mode, string nameApp, bool isLocal) { int nbTry = 0; int maxTry = 2; tc = new TcpConnection.Connection(host, port); myDebug.Write("mss","Connecting to " + host + " / " + port + " "); retryConnect: try { tc.Connect(); } catch { if (nbTry++ > maxTry) { myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss", "Ko"); myDebug.printDateOnEachLine = true; throw new ConnectException("Insim TCP Connection Failed on " + Host + " / " + Port); } else { System.Threading.Thread.Sleep(200); myDebug.printDateOnEachLine = false; myDebug.Write("mss","."); myDebug.printDateOnEachLine = true; goto retryConnect; } } if (adminPassword.Length > 16) throw (new Exception("Wrong length Password! :'" + adminPassword + "' max 16 characters")); myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss",""); myDebug.WriteLine("mss","Connection OK"); myDebug.printDateOnEachLine = true; byte[] inSimInit = myEncoder.ISI(adminPassword, 0, 0, nameApp, isLocal); try { this.Send(inSimInit, inSimInit.Length); } catch (Exception e) { throw e; } byte[] recvPacket; this.waitReceiveLow = true; recvPacket = this.ReceivePack(); if (recvPacket == null) { // myDebug.WriteLine("err","Wrong Password! :'" + adminPassword + "'"); throw (new Exception("Wrong Password! :'" + adminPassword + "'")); } InSim.Decoder.VER ver = new InSim.Decoder.VER(recvPacket); this.connected = true; this.Product = ver.Product; this.Version = ver.Version; this.InSimVersion = ver.InSimVersion; } public void insimConnectUDP( string host, int port, string adminPassword, string mode,string nameApp,bool isLocal) { int nbTry = 0; int maxTry = 2; myDebug.Write("mss","Connecting to " + host + " / " + port + " "); retryConnect: try { uc = new System.Net.Sockets.UdpClient(host, port); } catch( Exception e ) { myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss", ""); myDebug.printDateOnEachLine = true; throw e; } #if MONO int localport = 0; //for mono #else int localport = ((System.Net.IPEndPoint)uc.Client.LocalEndPoint).Port;//for .NET #endif byte[] inSimInit = myEncoder.ISI(adminPassword, localport, 0, nameApp, isLocal); try { this.Send(inSimInit, inSimInit.Length); } catch (Exception e) { myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss", ""); myDebug.printDateOnEachLine = true; throw e; } //request version Not Need in insim 4, because ISI send This // byte[] verreq = InSim.Encoder.VER(); // this.Send(verreq, verreq.Length); //retr version info byte[] recvPacket; try { this.waitReceiveLow = true; recvPacket = this.ReceivePack(); } catch { if (nbTry++ > maxTry) { myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss",""); myDebug.printDateOnEachLine = true; throw (new Exception("Can't Receive reply of ISI Packet")); } else { System.Threading.Thread.Sleep(200); myDebug.printDateOnEachLine = false; myDebug.Write("mss","."); myDebug.printDateOnEachLine = true; goto retryConnect; } } myDebug.printDateOnEachLine = false; myDebug.WriteLine("mss",""); myDebug.WriteLine("mss","Connection OK"); myDebug.printDateOnEachLine = true; InSim.Decoder.VER ver = new InSim.Decoder.VER(recvPacket); this.connected = true; this.Product = ver.Product; this.Version = ver.Version; this.InSimVersion = ver.InSimVersion; } public void TInSimReceive() // Thread of reception { myDebug.WriteLine("mss", "InSImReceive Thread Started..."); while (true) { byte[] recvPacket; this.waitReceiveLow = true; try { recvPacket = this.ReceivePack(); } catch { System.Threading.Thread.Sleep(500); continue; } Monitor.Enter(InsimPacks); InsimPacks.Enqueue( new objPacket( recvPacket )); Monitor.Exit(InsimPacks); } } public objPacket Receive() { objPacket recvPacket; while (true) { Monitor.Enter(InsimPacks); if (InsimPacks.Count != 0) { // Console.WriteLine(InsimPacks.Count); recvPacket = (objPacket)InsimPacks.Dequeue(); } else { recvPacket = null; } Monitor.Exit(InsimPacks); if (waitReceive == false) break; } return recvPacket; } public void Send(byte[] outMsg, int Length) { if (this.TCPmode) this.SendTCP(outMsg, Length); else this.SendUDP(outMsg, Length); } public void SendTCP(byte[] outMsg, int Length) { try { tc.SendToServer(outMsg, Length); } catch { throw new ConnectException("Insim TCP Connection Lost on " + Host + " / " + Port ); } } public void SendUDP(byte[] outMsg, int Length) { try { uc.Send(outMsg, Length); } catch { throw new ConnectException("Insim UDP Connection Lost on " + Host + " / " + Port ); } } public byte[] ReceivePack() { if (this.TCPmode) return ReceiveTCP(); else return ReceiveUDP(); } public byte[] ReceiveTCP() { if (tc.Available || waitReceiveLow ) return tc.GetPackFromInsimServer(); else return null; } public byte[] ReceiveUDP() { try { if (uc.Available != 0 || waitReceiveLow) { return uc.Receive(ref remoteEP); } else return null; } catch { throw new ConnectException("Insim UDP Connection Lost on " + Host + " / " + Port); } } public void Close() { if (this.TCPmode) CloseTCP(); else CloseUDP(); if (TInsimReceive != null) { TInsimReceive.Abort(); TInsimReceive.Join(); } } public void CloseTCP() { tc.Disconnect(); } public void CloseUDP() { uc.Close(); } public string packetHead(byte[] packet) { string packetHead; packetHead = Enum.GetName(typeof(TypePack), packet[1]); if (packetHead == null) packetHead = "ISP_" + packet[1].ToString(); packetHead = packetHead.Remove(0, 4); return packetHead; } public uint verifyID(byte[] packet) { return (uint)0; } } public class Encoder { /// /// Encoder for messages sent to LFS console /// /// Message to send /// /// public byte[] IS_TINY(byte Type, byte ReqI, byte SubT) { byte[] packet = new byte[4]; packet[0] = 4; packet[1] = Type; packet[2] = ReqI; packet[3] = SubT; return packet; } public byte[] IS_SMALL(byte Type, byte ReqI, byte SubT, uint Uval ) { byte[] packet = new byte[8]; packet[0] = 8; packet[1] = Type; packet[2] = ReqI; packet[3] = SubT; packet[4] = (byte)(Uval & 0xff); packet[5] = (byte)((Uval >> 8) & 0xff); packet[6] = (byte)((Uval >> 16) & 0xff); packet[7] = (byte)((Uval >> 24) & 0xff); return packet; } // MST OK in Insim 4 public byte[] MST(string msg) { int msgLen = msg.Length>63?63:msg.Length; byte[] packet = new byte[68]; packet[0] = 68; packet[1] = (byte)TypePack.ISP_MST; packet[2] = 0; packet[3] = 0; InSim.CodePage.GetBytes(msg, 0, msgLen, packet, 4); return packet; } // MSX OK in Insim 4 public byte[] MSX(string msg) { int msgLen = msg.Length > 96 ? 96 : msg.Length; byte[] packet = new byte[100]; packet[0] = 100; packet[1] = (byte)TypePack.ISP_MSX; packet[2] = 0; packet[3] = 0; InSim.CodePage.GetBytes(msg, 0, msgLen, packet, 4); return packet; } // MSP OK in Insim 4 public byte[] MSX(byte[] msg) { byte[] packet = new byte[100]; packet[0] = 100; packet[1] = (byte)TypePack.ISP_MSX; packet[2] = 0; packet[3] = 0; System.Array.Copy(msg, 0, packet, 4, System.Math.Min(96, msg.Length)); return packet; } // MSP OK in Insim 4 public byte[] MST(byte[] msg) { byte[] packet = new byte[68]; packet[0] = 68; packet[1] = (byte)TypePack.ISP_MST; packet[2] = 0; packet[3] = 0; System.Array.Copy(msg, 0, packet, 4, System.Math.Min(63,msg.Length)); return packet; } // MTC OK in Insim 4 public byte[] MTC(int UCID, int PLID, string msg) { int msgLen = msg.Length>63?63:msg.Length; byte[] packet = new byte[72]; packet[0] = 72; packet[1] = (byte)TypePack.ISP_MTC; packet[2] = 0; packet[3] = 0; packet[4] = (byte)UCID; packet[5] = (byte)PLID; packet[6] = 0; packet[7] = 0; InSim.CodePage.GetBytes(msg, 0, msgLen, packet, 8); return packet; } // MTC OK in Insim 4 public byte[] MTC(int UCID, int PLID, byte[] msg) { byte[] packet = new byte[72]; packet[0] = 72; packet[1] = (byte)TypePack.ISP_MTC; packet[2] = 0; packet[3] = 0; packet[4] = (byte)UCID; packet[5] = (byte)PLID; packet[6] = 0; packet[7] = 0; System.Array.Copy(msg, 0, packet, 8, System.Math.Min(63, msg.Length)); return packet; } /// /// Request LFS version information /// /// // VER OK in Insim 4 public byte[] TINY_NONE() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_NONE); } public byte[] TINY_PING() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_PING); } public byte[] VER() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_VER); } public byte[] VTC() { return IS_TINY((byte)TypePack.ISP_TINY, 0, (byte)TypeTiny.TINY_VTC); } public byte[] NCN() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_NCN); } public byte[] ISM() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_ISM); } public byte[] NPL() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_NPL); } public byte[] REO(int ReqI) { return IS_TINY((byte)TypePack.ISP_TINY, (byte)ReqI, (byte)TypeTiny.TINY_REO); } /// /// Request LFS Status /// /// // SST OK in Insim 4 public byte[] SST() { return IS_TINY((byte)TypePack.ISP_TINY, 10, (byte)TypeTiny.TINY_SST); } /// /// InSim Close Request Encoder /// /// // OK in InSim 4 public byte[] ISC() { return IS_TINY((byte)TypePack.ISP_TINY, 1, (byte)TypeTiny.TINY_CLOSE ); } /// /// Sets car state refresh interval /// /// Car state refresh interval in ms. 0 = stop, minimum = 100 /// // OK in Insim 4 public byte[] NLI(int interval) { return IS_SMALL((byte)TypePack.ISP_SMALL, 0, (byte)TypeSmall.SMALL_NLI, (uint)interval); } /// /// InSim Initialization Request Encoder /// /// Administrator password. /// Port number. 0 for same port as output. /// Seconds between MCI packets. 0 to disable. /// // OK in VERSION 4 public byte[] ISI(string adminPass, int portNum, byte mciSeconds, string nameApp, bool local) { byte[] packet = new byte[44]; packet[0] = 44; packet[1] = (byte)TypePack.ISP_ISI; packet[2] = 1; packet[3] = 0; // Port packet[4] = (byte)(portNum % 256); // LSB packet[5] = (byte)(portNum / 256); // MSB // Flags if (local) packet[6] = (byte)ISF.MCI | (byte)ISF.LOCAL | (byte)ISF.OBH | (byte)ISF.CON; // LSB else packet[6] = (byte)ISF.MCI | (byte)ISF.OBH | (byte)ISF.CON; // LSB packet[7] = 7; //Insim Version packet[8] = 0; packet[9] = (byte)'!'; // Number of milli seconds between NLP or MCI packets (0=none) packet[10] = 100; // LSB packet[11] = 0; // MSB System.Text.Encoding.ASCII.GetBytes(adminPass, 0, Math.Min(adminPass.Length, 16), packet, 12); System.Text.Encoding.ASCII.GetBytes(nameApp, 0, Math.Min(nameApp.Length, 16), packet, 28); return packet; } public byte[] BFN(byte ReqI, int SubT, int UCID, int ClickID) { byte[] packet = new byte[8]; packet[0] = 8; packet[1] = (byte)TypePack.ISP_BFN; packet[2] = ReqI; packet[3] = (byte)SubT; packet[4] = (byte)UCID; packet[5] = (byte)ClickID; packet[6] = 0; packet[7] = 0; return packet; } public byte[] BTN(byte ReqI, int L, int T, int W, int H, int UCID, int ClickID, int style, int TypeIn, string Caption, string Text) { int poke = Caption.Length; string allText; if (poke > 0) allText = " " + Caption + " " + Text; else allText = Text; while (allText.Length % 4 != 0) allText += " "; if (allText.Length > 240) allText = allText.Substring(0, 240); byte[] packet = new byte[12 + allText.Length]; packet[0] = (byte)(12 + allText.Length); packet[1] = (byte)TypePack.ISP_BTN; packet[2] = ReqI; // ReqI packet[3] = (byte)UCID; // UCID packet[4] = (byte)ClickID; // ClickID Of Button packet[5] = 0; // Inst packet[6] = (byte)style; // BUtton Style packet[7] = (byte)TypeIn; // TypeIn packet[8] = (byte)L; // Left packet[9] = (byte)T; // Top packet[10] = (byte)W; // Largeur packet[11] = (byte)H; // Largeur InSim.CodePage.GetBytes(allText, 0, allText.Length, packet, 12); // System.Text.Encoding.ASCII.GetBytes(allText, 0, allText.Length, packet, 12); if (poke != 0) { packet[12] = 0; packet[12 + poke + 1] = 0; } int l = allText.Length; for (int i = 12 + allText.Length - 1; i > 12; i--) { if (packet[i] == ' ') packet[i] = 0; else break; } return packet; } public byte[] REO( byte ReqI, int nbPlayer, byte[] arPLID ) { byte[] packet = new byte[36]; packet[0] = 36; packet[1] = (byte)TypePack.ISP_REO; packet[2] = ReqI; packet[3] = (byte)nbPlayer; for( int i = 0; i < 32;i++ ) packet[i+4] = (byte)arPLID[i]; return packet; } } public class Decoder { /// /// Version packet decoder /// static int pakGetByte(byte[] pak, int first) { return (int)pak[first]; } static string pakGetString(byte[] pak, int first, int len) { return InSim.CodePage.GetString(pak, first, len); } static int pakGetWord(byte[] pak, int first) { return (int)System.BitConverter.ToUInt16(pak, first); } static int pakGetShort(byte[] pak, int first) { return (int)System.BitConverter.ToInt16(pak, first); } static long pakGetUnsigned(byte[] pak, int first) { return (long)System.BitConverter.ToUInt32(pak, first); } static int pakGetInt(byte[] pak, int first) { return (int)System.BitConverter.ToInt32(pak, first); } static float pakGetFloat(byte[] pak, int first) { return (float)System.BitConverter.ToSingle(pak, first); } public class TINY { public readonly int ReqI; public readonly string SubT; public TINY(byte[] packet) { ReqI = pakGetByte(packet, 2); SubT = Enum.GetName(typeof(TypeTiny), packet[3]); } } public class SMALL { public readonly int ReqI; public readonly string SubT; public long uval; public SMALL(byte[] packet) { ReqI = pakGetByte(packet, 2); SubT = Enum.GetName(typeof(TypeSmall), packet[3]); uval = pakGetUnsigned(packet, 4); } } public class VER { public readonly string Version; public readonly string Product; public readonly int InSimVersion; public VER(byte[] packet) { Version = pakGetString(packet, 4, 8); Product = pakGetString(packet, 12, 6); InSimVersion = pakGetWord(packet, 18); } } public class ISM { public readonly int Host; public readonly string HName; public ISM(byte[] packet) { Host = pakGetByte(packet, 4); HName = pakGetString(packet, 8, 32); } } // Ok for Insim 4 public class DefCompCar { public int node; public int lap; public int PLID; public int Position; public int Infos; public int x; public int y; public int z; public int speed; public int direction; public int heading; public int angvel; } public class MCI { public int numOfPlayers; public DefCompCar[] compCar = new DefCompCar[8]; public MCI(byte[] packet) { numOfPlayers = pakGetByte( packet, 3 ); int offsetStartPlayer = 4; int lengthPlayer = 28; for (int i = 0; i < System.Math.Min(8,numOfPlayers); i++) { compCar[i] = new DefCompCar(); compCar[i].node =pakGetWord(packet, offsetStartPlayer + i * lengthPlayer + 0); compCar[i].lap = pakGetWord(packet, offsetStartPlayer + i * lengthPlayer + 2); compCar[i].PLID = pakGetByte(packet, offsetStartPlayer + i * lengthPlayer + 4); compCar[i].Position = pakGetByte(packet, offsetStartPlayer + i * lengthPlayer + 5); compCar[i].Infos = pakGetByte(packet, offsetStartPlayer + i * lengthPlayer + 6); compCar[i].x = pakGetInt(packet, offsetStartPlayer + i * lengthPlayer + 8); compCar[i].y = pakGetInt( packet, offsetStartPlayer + i * lengthPlayer + 12); compCar[i].z = pakGetInt( packet, offsetStartPlayer + i * lengthPlayer + 16); compCar[i].speed = pakGetWord( packet, offsetStartPlayer + i * lengthPlayer + 20); compCar[i].direction = pakGetWord( packet, offsetStartPlayer + i * lengthPlayer + 22); compCar[i].heading = pakGetWord( packet, offsetStartPlayer + i * lengthPlayer + 24); compCar[i].angvel = pakGetShort(packet, offsetStartPlayer + i * lengthPlayer + 26); // System.Console.WriteLine("ID:{0} x:{1} y:{2} z:{3} speed:{4} direction:{5} heading:{6} angvel:{7}", PLID, x, y, z, speed, direction, heading, angvel); // if(debug)System.Console.WriteLine("{0:F2}m {1:F2}m {2:F2}m {3:F2}km/h {4:F2} {5:F2} {6:F2}", xm, ym, zm, spm, dirm, headm, angm); } } } // Ok for Insim 4 public class NLP { public NLP(byte[] packet) { } } public class CarContact // 8 bytes : car in a contact with an object { public int PLID; public int Info; // like Info byte in CompCar (CCI_BLUE / CCI_YELLOW / CCI_LAG) public int Sp2; // spare public int Steer; // front wheel steer in degrees (right positive) public int ThrBrk; // high 4 bits : throttle / low 4 bits : brake (0 to 15) public int CluHan; // high 4 bits : clutch / low 4 bits : handbrake (0 to 15) public int GearSp; // high 4 bits : gear (15=R) / low 4 bits : spare public int Speed; // m/s public int Direction; // car's motion if Speed > 0 : 0 = world y direction, 128 = 180 deg public int Heading; // direction of forward axis : 0 = world y direction, 128 = 180 deg public int AccelF; // m/s^2 longitudinal acceleration (forward positive) public int AccelR; // m/s^2 lateral acceleration (right positive) public int X; // position (1 metre = 16) public int Y; // position (1 metre = 16) } public class CON { public readonly int Zero; public readonly int SpClose; // high 4 bits : reserved / low 12 bits : closing speed (10 = 1 m/s) public readonly int Time; // looping time stamp (hundredths - time since reset - like TINY_GTH) public CarContact PlayerA = new CarContact(); public CarContact PlayerB = new CarContact(); public CON(byte[] packet) // Size 40 bytes { Zero = pakGetByte(packet, 3);//1 Byte SpClose = pakGetWord(packet, 4);//2 Bytes Time = pakGetWord(packet, 6);//2 Bytes //Player A PlayerA.PLID = pakGetByte(packet, 8); //1 Byte // player's unique id PlayerA.Info = pakGetByte(packet, 9); //1 Byte // like Info byte in CompCar (CCI_BLUE / CCI_YELLOW / CCI_LAG) PlayerA.Sp2 = pakGetByte(packet, 10); //1 Byte // spare PlayerA.Steer = pakGetByte(packet, 11); //1 Byte // front wheel steer in degrees (right positive) PlayerA.ThrBrk = pakGetByte(packet, 12); //1 Byte // high 4 bits : throttle / low 4 bits : brake (0 to 15) PlayerA.CluHan = pakGetByte(packet, 13); //1 Byte // high 4 bits : clutch / low 4 bits : handbrake (0 to 15) PlayerA.GearSp = pakGetByte(packet, 14); //1 Byte // high 4 bits : gear (15=R) / low 4 bits : spare PlayerA.Speed = pakGetByte(packet, 15); //1 Byte // m/s PlayerA.Direction = pakGetByte(packet, 16); //1 Byte // car's motion if Speed > 0 : 0 = world y direction, 128 = 180 deg PlayerA.Heading = pakGetByte(packet, 17); //1 Byte // direction of forward axis : 0 = world y direction, 128 = 180 deg PlayerA.AccelF = pakGetByte(packet, 18); //1 Byte // m/s^2 longitudinal acceleration (forward positive) PlayerA.AccelR = pakGetByte(packet, 19); //1 Byte // m/s^2 lateral acceleration (right positive) PlayerA.X= pakGetShort(packet, 20); //2 Byte // position (1 metre = 16) PlayerA.Y = pakGetShort(packet, 22); //2 Byte // position (1 metre = 16) //Player B PlayerB.PLID = pakGetByte(packet, 24); //1 Byte PlayerB.Info = pakGetByte(packet, 25); //1 Byte // like Info byte in CompCar (CCI_BLUE / CCI_YELLOW / CCI_LAG) PlayerB.Sp2 = pakGetByte(packet, 26); //1 Byte // spare PlayerB.Steer = pakGetByte(packet, 27); //1 Byte // front wheel steer in degrees (right positive) PlayerB.ThrBrk = pakGetByte(packet, 28); //1 Byte // high 4 bits : throttle / low 4 bits : brake (0 to 15) PlayerB.CluHan = pakGetByte(packet, 29); //1 Byte // high 4 bits : clutch / low 4 bits : handbrake (0 to 15) PlayerB.GearSp = pakGetByte(packet, 30); //1 Byte // high 4 bits : gear (15=R) / low 4 bits : spare PlayerB.Speed = pakGetByte(packet, 31); //1 Byte // m/s PlayerB.Direction = pakGetByte(packet, 32); //1 Byte // car's motion if Speed > 0 : 0 = world y direction, 128 = 180 deg PlayerB.Heading = pakGetByte(packet, 33); //1 Byte // direction of forward axis : 0 = world y direction, 128 = 180 deg PlayerB.AccelF = pakGetByte(packet, 34); //1 Byte // m/s^2 longitudinal acceleration (forward positive) PlayerB.AccelR = pakGetByte(packet, 35); //1 Byte // m/s^2 lateral acceleration (right positive) PlayerB.X = pakGetShort(packet, 36); //2 Bytes // position (1 metre = 16) PlayerB.Y = pakGetShort(packet, 38); //2 Bytes // position (1 metre = 16) } } public class ObjectInfo // Info about a single object - explained in the layout file format { public int X; public int Y; public int Z; public int Flags; public int Index; public int Heading; } public class CarContOBJ // 8 bytes : car in a contact with an object { public int Direction; // car's motion if Speed > 0 : 0 = world y direction, 128 = 180 deg public int Heading; // direction of forward axis : 0 = world y direction, 128 = 180 deg public int Speed; // m/s public int PlayerPosZ; // position (1 metre = 4) public int PlayerPosX; // position (1 metre = 16) public int PlayerPosY; // position (1 metre = 16) } // OK For Insim 6 public class OBH // 24 Byte size Object Collision between Car > Object { public CarContOBJ CarCont = new CarContOBJ(); public readonly int PLID; // player's unique id public readonly int SpClose; // closing speed (10 = 1 m/s) public readonly int ObjectHitTime; // looping time stamp public readonly int ObjectPosX; // as in ObjectInfo public readonly int ObjectPosY; // as in ObjectInfo public readonly int ObjectPosZ; // as in ObjectInfo public readonly int Sp1; //spare1 public readonly int Index; // AXO_x as in ObjectInfo or zero if it is an unknown object public readonly int OBHFlags; public OBH(byte[] packet) { PLID = pakGetByte(packet, 3); //1 Byte SpClose = pakGetWord(packet, 4); //2 Bytes ObjectHitTime = pakGetWord(packet, 6); //2 Bytes CarCont.Direction = pakGetByte(packet, 8); //1 Byte CarCont.Heading = pakGetByte(packet, 9); //1 Byte CarCont.Speed = pakGetByte(packet, 10); //1 Byte CarCont.PlayerPosZ = pakGetByte(packet, 11); //1 Byte CarCont.PlayerPosX = pakGetShort(packet, 12); //2 Bytes CarCont.PlayerPosY = pakGetShort(packet, 14); //2 Bytes ObjectPosX = pakGetShort(packet, 16); //2 Bytes ObjectPosY = pakGetShort(packet, 18); //2 Bytes ObjectPosZ = pakGetByte(packet, 20); //1 Byte Sp1 = pakGetByte(packet, 21); //1 Byte Index = pakGetByte(packet, 22); //1 Byte OBHFlags = pakGetByte(packet, 23); //1 Byte } } public class UCO // Size 28 Bytes: report InSim checkpoint / InSim circle { public CarContOBJ C = new CarContOBJ(); public ObjectInfo OBJInfo = new ObjectInfo(); public readonly int PLID; // player's unique id public readonly int Sp0; //Spare 0 public readonly int UCOAction; public readonly int Sp2; //Spare 2 public readonly int Sp3; //Spare 3 public readonly int Time; // hundredths of a second since start (as in SMALL_RTP) public UCO(byte[] packet) { PLID = pakGetByte(packet, 3); //1 Byte Sp0 = pakGetByte(packet, 4);//1 Byte UCOAction = pakGetByte(packet, 5);//1 Byte Sp2 = pakGetByte(packet, 6);//1 Byte Sp3 = pakGetByte(packet, 7);//1 Byte Time = pakGetInt(packet, 8);//4 Byte C.Direction = pakGetByte(packet, 12);//1 Byte C.Heading = pakGetByte(packet, 13);//1 Byte C.Speed = pakGetByte(packet, 14);//1 Byte C.PlayerPosZ = pakGetByte(packet, 15);//1 Byte C.PlayerPosX = pakGetShort(packet, 16);//2 Bytes C.PlayerPosY = pakGetShort(packet, 18);//2 Bytes OBJInfo.X = pakGetShort(packet, 20);//2 Bytes OBJInfo.Y = pakGetShort(packet, 22);//2 Bytes OBJInfo.Z = pakGetByte(packet, 24);//1 Byte OBJInfo.Flags = pakGetByte(packet, 25);//1 Byte OBJInfo.Index = pakGetByte(packet, 26);//1 Byte OBJInfo.Heading = pakGetByte(packet, 27);//1 Byte } } /// /// State pack decoder /// LFS will send a StatePack any time the info in the StatePack changes. /// // OK For Insim 4 public class STA { /// /// Short Track Name. /// public readonly float ReplaySpeed = 0; public readonly int Flags = 0; public readonly int InGameCam = 0; public readonly int ViewPlayer = 0; public readonly int NumP = 0; public readonly int NumConns = 0; public readonly int NumFinished = 0; public readonly int RaceInProg = 0; public readonly int QualMins = 0; public readonly int RaceLaps = 0; public string ShortTrackName = "NOT SET"; public readonly int Weather = 0; public readonly int Wind = 0; public STA() { } public STA(byte[] packet) { ReplaySpeed = pakGetFloat(packet, 4); Flags = pakGetWord(packet, 8); InGameCam = pakGetByte(packet, 10); ViewPlayer = pakGetByte(packet, 11); NumP = pakGetByte(packet, 12); NumConns = pakGetByte(packet, 13); NumFinished = pakGetByte( packet,14 ); RaceInProg = pakGetByte( packet, 15 ); QualMins = pakGetByte(packet, 16); RaceLaps = pakGetByte(packet, 17); ShortTrackName = pakGetString(packet, 20, 6); Weather = pakGetByte(packet, 26); Wind = pakGetByte(packet, 27); } } // Ok for InSim 4 public class REO { /// /// Short Track Name. /// public readonly int ReqI; public readonly int NumP; public byte[] PLID = new byte[32]; public REO(byte[] packet) { ReqI = pakGetByte(packet, 2); NumP = pakGetByte(packet, 3); Array.ConstrainedCopy(packet, 4, PLID, 0, 32); } } public class RES { /// /// Short Track Name. /// public readonly int PLID; public readonly string userName; public readonly string nickName; public readonly string Plate; public readonly string CName; public readonly long TTime; public readonly long BTime; public readonly int NumStops; public readonly int Confirm; public readonly int LapDone; public readonly int Flags; public readonly int ResultNum; public readonly int NumRes; public RES(byte[] packet) { PLID = pakGetByte(packet, 3 ); userName = pakGetString(packet, 4, 24); nickName = pakGetString(packet, 28, 24); Plate = pakGetString(packet, 52, 8); CName = pakGetString(packet, 60, 4); TTime = pakGetUnsigned(packet, 64); BTime = pakGetUnsigned(packet, 68); NumStops = pakGetByte(packet, 73); Confirm = pakGetByte(packet, 74); LapDone = pakGetWord(packet, 76); Flags = pakGetWord(packet, 78); ResultNum = pakGetByte(packet, 80); NumRes = pakGetByte( packet, 81); } } public class FIN { /// /// Short Track Name. /// public readonly int PLID; public readonly long TTime; public readonly long BTime; public readonly int NumStops; public readonly int Confirm; public readonly int LapDone; public readonly int Flags; public FIN(byte[] packet) { PLID = pakGetByte(packet, 3); TTime = pakGetUnsigned(packet, 4); BTime = pakGetUnsigned(packet, 8); NumStops = pakGetByte(packet, 13); Confirm = pakGetByte(packet, 14); LapDone = pakGetWord(packet, 16); Flags = pakGetWord(packet, 18); } } public enum fact { PITLANE_EXIT, // 0 - left pit lane PITLANE_ENTER, // 1 - entered pit lane PITLANE_NO_PURPOSE, // 2 - entered for no purpose PITLANE_DT, // 3 - entered for drive-through PITLANE_SG, // 4 - entered for stop-go PITLANE_NUM, } public class PLA { public readonly int NumP; public int PLID; public fact fact; public PLA(byte[] packet) { PLID = pakGetByte(packet, 3); fact = (fact)pakGetByte(packet, 4); } } //NOT USED in Insim 4 public class MSS { public readonly string UserName; public readonly string PlayerName; public readonly string Message; public MSS(byte[] packet) { UserName = ""; PlayerName = ""; Message = ""; } } // MSO OK FOR insim 4 public class MSO { public readonly int UCID; public readonly int PLID; public readonly int UserType; public readonly int TextStart; public readonly string message; public readonly string completeMessage; public MSO(byte[] packet) { UCID = pakGetByte( packet, 4); PLID = pakGetByte( packet, 5); UserType = pakGetByte( packet, 6); TextStart = pakGetByte( packet, 7); message = pakGetString(packet, 8 + TextStart, 128 - TextStart); completeMessage = pakGetString(packet, 8, 128); } } // Ok For Insim 4 public class NPL { public readonly int PLID; public readonly int UCID; public readonly int PType; public readonly int Flags; public readonly string nickName; public readonly string Plate; public readonly string CName; public readonly string SName; public readonly tyre TyreRearLeft; public readonly tyre TyreRearRight; public readonly tyre TyreFrontLeft; public readonly tyre TyreFrontRight; public readonly int H_Mass; public readonly int H_TRes; public readonly int Pass; public readonly int SetF; public readonly int NumP; // public readonly PlayerFlags flags; public enum PlayerFlags : ushort { SwapSide = 1, // If Swapside -> pilote à gauche Reserved_2 = 2, Reserved_4 = 4, AutoGears = 8, Shifter = 16, Reserved_32 = 32, HelpBrake = 64, AxisClutch = 128, InPits = 256, AutoClutch = 512, Mouse = 1024, KbNoHelp = 2048, KbStabilised = 4096, CustomView = 8192 } public NPL(byte[] pak) { PLID = pakGetByte( pak, 3); UCID = pakGetByte( pak, 4 ); PType = pakGetByte( pak, 5 ); Flags = pakGetWord(pak, 6); nickName = pakGetString(pak, 8, 24); Plate = pakGetString(pak, 32, 8); CName = pakGetString(pak, 40, 4); SName = pakGetString(pak, 44, 16); TyreRearLeft = (tyre)pakGetByte(pak, 60 ); TyreRearRight = (tyre)pakGetByte(pak, 61); TyreFrontLeft = (tyre)pakGetByte(pak, 62); TyreFrontRight = (tyre)pakGetByte(pak, 63); H_Mass = pakGetByte(pak, 64); H_TRes = pakGetByte(pak, 65); Pass = pakGetByte(pak, 67); SetF = pakGetByte(pak, 72); NumP = pakGetByte(pak, 73); // flags = (PlayerFlags)(ushort)((pak[6]) | (pak[7] << 8)); } } // Ok For insim 4 public class PIT { public readonly int PLID; public readonly int LapsDone; public readonly int Flags; public readonly int Penalty; public readonly int NumStop; public readonly tyre TyreRearLeft; public readonly tyre TyreRearRight; public readonly tyre TyreFrontLeft; public readonly tyre TyreFrontRight; public readonly long Work; public readonly string sWork; public PIT(byte[] pak) { PLID = pakGetByte(pak, 3); LapsDone = pakGetWord(pak, 4); Flags = pakGetWord(pak, 6); Penalty = pakGetByte(pak, 9); NumStop = pakGetByte(pak, 10); TyreRearLeft = (tyre)pakGetByte(pak, 12); TyreRearRight = (tyre)pakGetByte(pak, 13); TyreFrontLeft = (tyre)pakGetByte(pak, 14); TyreFrontRight = (tyre)pakGetByte(pak, 15); Work = pakGetUnsigned(pak, 16); sWork = ""; string virg = ""; if( (Work & (long)PIT_work.PSE_FR_DAM) != 0 ||(Work & (long)PIT_work.PSE_RE_DAM) != 0 || (Work & (long)PIT_work.PSE_LE_FR_DAM) != 0 || (Work & (long)PIT_work.PSE_RI_FR_DAM) != 0 || (Work & (long)PIT_work.PSE_LE_RE_DAM) != 0 || (Work & (long)PIT_work.PSE_RI_RE_DAM) != 0 ) { sWork = sWork + virg + "Mechanicals Damages"; virg = ", "; } if( (Work & (long)PIT_work.PSE_BODY_MINOR) != 0 || (Work & (long)PIT_work.PSE_BODY_MAJOR) != 0 ) { sWork = sWork + virg + "Body Dammage"; virg = ", "; } if((Work & (long)PIT_work.PSE_REFUEL) != 0 ) { sWork = sWork + virg + "Refuel"; virg = ", "; } if((Work & (long)PIT_work.PSE_SETUP) != 0 ) { sWork = sWork + virg + "Setup"; virg = ", "; } if( (Work & (long)PIT_work.PSE_FR_WHL) != 0 || (Work & (long)PIT_work.PSE_LE_FR_WHL) != 0 || (Work & (long)PIT_work.PSE_RI_FR_WHL) != 0 || (Work & (long)PIT_work.PSE_RE_WHL) != 0 || (Work & (long)PIT_work.PSE_LE_RE_WHL) != 0 || (Work & (long)PIT_work.PSE_RI_RE_WHL) != 0 ) { sWork = sWork + virg + "Wheels or Transmissions"; virg = ", "; } } } // Ok For insim 4 public class PSF { public readonly int PLID; public readonly long STime; public PSF(byte[] pak) { PLID = pakGetByte(pak, 3); STime = pakGetUnsigned(pak, 4); } } // LAP OK for insim 4 public class LAP { public readonly int PLID; public readonly long LTime; public readonly long ETime; public readonly int LapsDone; public readonly int Flags; public readonly int Penalty; public readonly int NumStop; public LAP(byte[] pak) { PLID = pakGetByte( pak, 3 ); LTime = pakGetUnsigned(pak, 4); ETime = pakGetUnsigned(pak, 8); LapsDone = pakGetWord(pak, 12); Flags = pakGetWord(pak, 14); Penalty = pakGetByte(pak, 17); NumStop = pakGetByte(pak, 18); } } /// /// Split X time decoder /// // LAP OK for insim 4 public class SPX { public readonly int PLID; public readonly long STime; public readonly long ETime; public readonly int Split; public readonly int Penalty; public readonly int NumStop; public SPX(byte[] pak) { PLID = pakGetByte(pak, 3); STime = pakGetUnsigned(pak, 4); ETime = pakGetUnsigned(pak, 8); Split = pakGetByte( pak, 12 ); Penalty = pakGetByte(pak, 13); NumStop = pakGetByte(pak, 14); } } // RST Ok for Insim 4 public class RST { /// /// Gets time for qualifications in minutes. If zero, race started. /// public readonly int RaceLaps; public readonly int QualMins; public readonly int NumP; public readonly string Track; public readonly int Weather; public readonly int Wind; public readonly int Flags; public readonly int NumNodes; public readonly int Finish; public readonly int Split1; public readonly int Split2; public readonly int Split3; public RST(byte[] pak) { RaceLaps = pakGetByte( pak ,4 ); QualMins = pakGetByte( pak, 5 ); NumP = pakGetByte(pak, 6); Track = pakGetString(pak, 8, 6); Weather = pakGetByte(pak, 14); Wind = pakGetByte(pak, 15); Flags = pakGetByte(pak, 16); NumNodes = pakGetWord(pak, 18); Finish = pakGetWord(pak, 20); Split1 = pakGetWord(pak, 22); Split2 = pakGetWord(pak, 24); Split3 = pakGetWord(pak, 26); } } // Ok pour Insim 4 public class NCN { public readonly int UCID; public readonly string userName; public readonly string nickName; public readonly int Admin; public readonly int Total; public readonly int Flags; public NCN(byte[] pak) { UCID = pakGetByte( pak, 3 ); userName = pakGetString(pak, 4, 24); nickName = pakGetString(pak, 28, 24); Admin = pakGetByte(pak, 52); Total = pakGetByte(pak, 53); Flags = pakGetByte(pak, 54); } } // Ok For insim 4 public class CNL { public readonly int UCID; public readonly int Reason; public readonly int Total; public CNL(byte[] pak) { UCID = pakGetByte(pak, 3); Reason = pakGetByte(pak, 4); Total = pakGetByte(pak, 5); } } // Ok For insim 4 public class CPR { public readonly int UCID; public readonly string newNickName; public readonly string Plate; public CPR(byte[] pak) { UCID = pakGetByte( pak, 3 ); newNickName = pakGetString(pak, 4, 24); Plate = pakGetString(pak, 28, 8); } } // Ok for Insim 4 /// /// PLayer Pits /// public class PLP { public readonly int PLID; public PLP(byte[] pak) { PLID = pakGetByte( pak , 3 ); } } // Ok for Insim 4 /// /// PLayer Leave race /// public class PLL { public readonly int PLID; public PLL(byte[] pak) { PLID = pakGetByte( pak , 3 ); } } // Ok For insim 4 public class FLG { public readonly int PLID; public readonly int OffOn; public readonly int Flag; public readonly int CarBehind; public FLG(byte[] pak) { PLID = pakGetByte(pak, 3); OffOn = pakGetByte(pak, 4); Flag = pakGetByte(pak, 5); CarBehind = pakGetByte(pak, 6); } } public class PEN { public readonly int PLID; public readonly int OldPen; public readonly int NewPen; public readonly int Reason; public PEN(byte[] pak) { PLID = pakGetByte(pak, 3); OldPen = pakGetByte(pak, 4); NewPen = pakGetByte(pak, 5); Reason = pakGetByte(pak, 6); } } public class BFN { public readonly int SubT; public readonly int UCID; public readonly int ClickID; public BFN(byte[] pak) { SubT = pakGetByte(pak, 3); UCID = pakGetByte(pak, 4); ClickID = pakGetByte(pak, 5); } } public class BTC { public readonly int UCID; public readonly int ClickID; public readonly int CFlags; public BTC(byte[] pak) { UCID = pakGetByte(pak, 3); ClickID = pakGetByte(pak, 4); CFlags = pakGetByte(pak, 6); } } public class BTT { public readonly int UCID; public readonly int ClickID; public readonly int TypIn; public string Text; public BTT(byte[] pak) { UCID = pakGetByte(pak, 3); ClickID = pakGetByte(pak, 4); TypIn = pakGetByte(pak, 6); Text = pakGetString( pak,8,96 ); } } public class TOC { public readonly int PLID; public readonly int OldUCID; public readonly int NewUCID; public TOC(byte[] pak) { PLID = pakGetByte(pak, 3); OldUCID = pakGetByte(pak, 4); NewUCID = pakGetByte(pak, 5); } } public class VTN { public readonly int UCID; public readonly int Action; public VTN(byte[] pak) { UCID = pakGetByte(pak, 4); Action = pakGetByte(pak, 5); } } public class PFL { public readonly int PLID; public readonly int Flags; public PFL(byte[] pak) { PLID = pakGetByte(pak, 3); Flags = pakGetWord(pak, 4); } } public class CRS { public readonly int PLID; public CRS(byte[] pak) { PLID = pakGetByte(pak, 3); } } } }