View Full Version : .NET - InSim.NET - InSim library
DarkTimes
7th June 2010, 19:03
InSim.NET is a InSim library for Live for Speed, written for the .NET Framework. It allows you to create a socket connection with the game and to send and receive packets of data. These packets can be used to control LFS, issue commands and request information. The library has been designed for flexibility, extensibility and performance. It tries to match the original InSim API as closely as possible, while taking care not to get in your way.
Note: InSim.NET was previously known as Spark, but had to change its name to prevent it clashing with another .NET project with the same name.
Note: Many code examples in this thread were written for version 1.0 of InSim.NET (known as Spark) and may not work correctly in the current version. You can find up-to-date examples on CodePlex.
Quick Links
Home Page (http://insimdotnet.codeplex.com/)
Download (http://insimdotnet.codeplex.com/releases)
Documentation (http://insimdotnet.codeplex.com/documentation) (work in progress)
Source Code (http://insimdotnet.codeplex.com/SourceControl/list/changesets)
What's New?
This release is for version 2.0 of the library, which has seen a number of large changes
Full support for InSim, InSim Relay, OutSim and OutGauge
Full support for all LFS character encodings
Improved API
Improved networking code
Improved documentation
A new home on CodePlex
New Mercurial source code repository
Requirements
InSim.NET supports the .NET Framework 3.5 and 4.0 and is also CLS compliant with all .NET languages. It is written in C# and compiled with Visual Studio 2010.
Source Code
InSim.NET now uses Mercurial (http://mercurial.selenic.com/) distributed source control, which means it's easy to clone the latest repository, create forks and make changes. You can find an excellent (and humorous) tutorial on Mercurial at hginit.com (http://hginit.com/). For a simple tutorial on how to fork the codebase, see the CodePlex forks documentation (http://codeplex.codeplex.com/wikipage?title=Forks).
Anyone is welcome to clone the repository and create their own version of the library, so long as they obey the license!
License
InSim.NET is released under the Lesser General Public License (LGPL).
Download
You can download InSim.NET from its project page on CodePlex.
http://insimdotnet.codeplex.com/
filur
7th June 2010, 19:49
Looks very nice, i'll give it a go sometime. :thumbsup:
Dygear
7th June 2010, 21:01
Looks very nice, i'll give it a go sometime. :thumbsup:
Going over to the Spark side?!
[Ok that was lame, but I did find it just a little funny.]
DarkTimes as always, love the code coming from your direction!
filur
8th June 2010, 01:00
Packets.PacketFactory.Build seems to be missing a case for ISP_BTC, a bug or am i missing something?
DarkTimes
8th June 2010, 01:19
Obviously a bug.
broken
9th June 2010, 14:28
I've always wanted to build my C# insim projects on this base! Now I can finally get it without the sniffer. :razz:
As soon as I have some time for it, I'll definitely check it out! :thumbsup:
Whiskey
10th June 2010, 18:22
Mmm, looks easy enough to start learning some C# this summer holidays :nod:
filur
10th June 2010, 19:23
Here is Sparktris. :)
The patch for Spark can be found in the source zip.
The binary probably requires the .NET framework v4 or higher.
The game is single player and intended to be connected to a local LFS client.
Dygear
10th June 2010, 21:14
Here is Sparktris. :)
The patch for Spark can be found in the source zip.
The binary probably requires the .NET framework v4 or higher.
The game is single player and intended to be connected to a local LFS client.
You ... Have way to much time on your hands :).
Whiskey
11th June 2010, 12:19
[Read next post first]
This is not as easy as I thought:schwitz:
I'm trying the "Car Updates" example, and I found 2 problems.
1-"using Spark.Helpers;" sentence is missing
2-I execute the program and I see "InSim - TCP : Example" message in LFS, but after that nothing appear in the console :shrug:
I tried first with a Windows Forms proyect, but that was too much for me. I can't even run this copy&paste example haha
EDIT: the other examples work perfect :)
Whiskey
11th June 2010, 13:16
It seems that the dictionary isn't working right (I'm new to C# and dictionaries).
In "NewPlayer" function this line "_players.Add(npl.PLID, npl);" adds a driver (PLID=20, for example)
But in "PlayerLeft" function, "_players.ContainsKey(pll.PLID)" returns false with the same PLID (this time it comes from pll packet instead of npl, but it still PLID=20).
Am I doing something wrong or that dictionary isn't working fine?
I'm pretty sure this is the cause to the problem in my previous post
DarkTimes
11th June 2010, 16:45
Sorry, I've not had time to work on this since I posted it. Been very busy. I'll try to get all the kinks worked out over the weekend.
In terms of the car update sample, it appears I missed out a couple of things, mainly I forgot to set the MCI flag and interval in the ISI packet. I'm not at home to test this, but try this code:
using System;
using System.Collections.Generic;
using Spark;
using Spark.Packets;
using Spark.Helpers;
class Program
{
// We store the players in a dictionary.
static Dictionary<int, IS_NPL> _players = new Dictionary<int, IS_NPL>();
static void Main()
{
// Create new InSim object.
using (var insim = new InSim())
{
// Bind handlers.
insim.Bind<IS_NPL>(NewPlayer);
insim.Bind<IS_PLL>(PlayerLeft);
insim.Bind<IS_MCI>(MultiCarInfo);
// Establish the InSim connection.
insim.Connect("127.0.0.1", 29999);
// Initialize InSim.
insim.Send(new IS_ISI { IName = "^3Example", Flags = InSimFlags.ISF_MCI, Interval = 500 });
// Request players.
insim.Send(new IS_TINY { SubT = TinyType.TINY_NPL, ReqI = 255 });
// Prevent program from exiting.
insim.Run();
}
}
static void NewPlayer(IS_NPL npl)
{
if (_players.ContainsKey(npl.PLID))
{
// Leaving pits, just update NPL object.
_players[npl.PLID] = npl;
}
else
{
// Add new player.
_players.Add(npl.PLID, npl);
}
}
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
}
static void MultiCarInfo(IS_MCI mci)
{
// Loop through each car on track.
foreach (var car in mci.CompCars)
{
IS_NPL npl;
if (_players.TryGetValue(car.PLID, out npl))
{
// Convert LFS speed into Mph.
var mph = MathHelper.SpeedToMph(car.Speed);
// Print nicely formatted string to console.
Console.WriteLine("Speed: {0} {1:F2}", npl.PName, mph);
}
}
}
}
filur
11th June 2010, 17:07
Patches for Spark 1.0, i'lll update this post if i do any more.
DarkTimes
11th June 2010, 17:34
OK - Thanks for those!
I've uploaded a new version to the first post, with those fixes, as well as a couple of other things. I created a separate solution with all the examples in it, so it's easier for people to get off the ground. You can find it in the SparkExamples folder. I also added a readme and proper licenses.
In case I didn't mention it before the library is released under the LGPL.
filur
11th June 2010, 17:45
I've uploaded a new version to the first post, with those fixes
Had a quick look and noticed this didn't make it into IS_BTN.cs:
- writer.Write(Text, 240);
+ writer.Write(Text, Size - 12);
DarkTimes
11th June 2010, 17:53
Ah sorry, trying to do things too fast. I've uploaded a fixed version.
As I say I'll try to do real work on it this weekend.
filur
11th June 2010, 21:48
Had another look and spotted two issues in IS_BTN.cs where a text longer than 240 chars would be handled incorrectly and the variable size stuff padded an empty text to a length of 4.
So here's a patch for those.
Dygear
12th June 2010, 05:27
Had another look and spotted two issues in IS_BTN.cs where a text longer than 240 chars would be handled incorrectly and the variable size stuff padded an empty text to a length of 4.
So here's a patch for those.
Fantastic! Good to see filur programming again!
Whiskey
12th June 2010, 14:57
It's receiving MCI packets :thumbsup:
I'm still tryng to understand the basis of this, as I wasn't able yet to use the dictionary or get the license name of a player (me xD)
Another bug:
These two functions return the same speed. They return my speed in kph :schwitz:
var mph = MathHelper.SpeedToMph(car.Speed);
var kph = MathHelper.SpeedToKph(car.Speed);
Whiskey
12th June 2010, 19:13
Wierd enough my dictionary has started to work correctly itself:razz:
DarkTimes
13th June 2010, 18:59
The dictionary should work, dunno what problems you're having.
There is a bug in the double MathHelper.SpeedToMph(int) method, I will release a fix at some point, but you can change it to this:
public static double SpeedToMph(int speed)
{
return speed / 146.486067;
}
Obviously there are several issues that need to be worked out in the library, my plan is to port InSimSniffer over to Spark which should let me resolve most of these problems.
I realise I also need to add proper string decoding, but I've been considering releasing a standalone library for this.
DarkTimes
13th June 2010, 21:26
Well actually an issue which could affect the dictionary of players is if you connect to LFS on the menu screen and then join a host. A better solution would be to request the players both when connecting to LFS and also when joining a multiplayer race.
using System;
using System.Collections.Generic;
using Spark;
using Spark.Packets;
using Spark.Helpers;
namespace Spark.Example5
{
class Program
{
static InSim _insim;
// We store the players in a dictionary.
static Dictionary<int, IS_NPL> _players = new Dictionary<int, IS_NPL>();
static void Main()
{
// Create new InSim object.
using (_insim = new InSim())
{
// Bind handlers.
_insim.Bind<IS_ISM>(MultiPlayerInfo);
_insim.Bind<IS_NPL>(NewPlayer);
_insim.Bind<IS_PLL>(PlayerLeft);
_insim.Bind<IS_MCI>(MultiCarInfo);
// Establish the InSim connection.
_insim.Connect("127.0.0.1", 29999);
// Initialize InSim.
_insim.Send(new IS_ISI { IName = "^3Example", Flags = InSimFlags.ISF_MCI, Interval = 500, Admin = string.Empty });
// Request for multiplayer info packet to be sent.
_insim.Send(new IS_TINY { SubT = TinyType.TINY_ISM, ReqI = 255 });
// Prevent program from exiting.
_insim.Run();
}
}
static void MultiPlayerInfo(IS_ISM ism)
{
// When joining multiplayer request for all connections and players to be sent.
_insim.Send(new IS_TINY { SubT = TinyType.TINY_NCN, ReqI = 255 });
_insim.Send(new IS_TINY { SubT = TinyType.TINY_NPL, ReqI = 255 });
}
static void NewPlayer(IS_NPL npl)
{
if (_players.ContainsKey(npl.PLID))
{
// Leaving pits, just update NPL object.
_players[npl.PLID] = npl;
}
else
{
// Add new player.
_players.Add(npl.PLID, npl);
}
}
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
}
static void MultiCarInfo(IS_MCI mci)
{
// Loop through each car on track.
foreach (var car in mci.CompCars)
{
// Get the player driving this car.
IS_NPL npl;
if (_players.TryGetValue(car.PLID, out npl))
{
// Check cars speed.
var kph = MathHelper.SpeedToKph(car.Speed);
if (kph > 80)
{
// Spectate player and send chat message.
_insim.Send("/spec {0}", npl.PName);
_insim.Send("{0} ^3spectated for speeding", npl.PName);
}
}
}
}
}
}
Dygear
14th June 2010, 05:20
I realise I also need to add proper string decoding, but I've been considering releasing a standalone library for this.
Yes me too. with the LFSWorld SDK and PRISM both having to decode strings and parse times, and convert speed I thought I might as well release a standalone lib to handle all such functions. As it is going to be used by many projects the license for such a lib would have to be very liberal, to the point where it would have to be MIT. Nothing else really comes close as far as code portability.
DarkTimes
18th June 2010, 12:02
Uploaded 1.0.2 to the first post (http://www.lfsforum.net/showthread.php?p=1435446#post1435446).
Changes Since 1.0.1
Allowed reuse of InSim, TcpSocket and UdpSocket without needing to create a new instance each time
Added asyncronous connect, by calling InSim.BeginConnect(string, int, AsyncCallback) and InSim.EndConnect(IAsyncResult) methods
Added InSim.Connecting event which is raised when the connect operation is begun but before the connection is established
InSim.Connect and InSim.EndConnect try to throw an appropriate InSimException instead of a generic SocketException
Added IS_BTN patch supplied by filur
Fixed bug with MathHelper.SpeedToMph method where it was returning Kph
Fixed "existing connection closed by remote host" error when calling InSim.Disconnect()
Lots of small corrections and tweaks to the SparkExamples solution
Whiskey
18th June 2010, 14:32
It's nice to see you have time again to improve this :)
DarkTimes
19th June 2010, 10:36
Uploaded 1.0.3 to the first post (http://www.lfsforum.net/showthread.php?p=1435446#post1435446).
Changes
Fixed critical bug which was stopping the socket from correctly being released when the InSim connection closed. As a consequence InSim.Run() should now exit properly and InSim.IsConnected should now return the correct value in all situations.
Added InSim Relay (http://www.lfsforum.net/showthread.php?t=30740) support. Check Example 7 in SparkExamples for a detailed example.
Edit: I also changed the Car Update example to now spectate players who speed, as it makes more sense than just printing out car speeds.
InSim Relay
Connecting to InSim relay is pretty simple and support needed no additions to the main InSim class. In this example we connect to relay, request the host list, then print out the name of each LFS host that is received.
using System;
using Spark;
using Spark.Packets;
using Spark.Helpers;
class Program
{
static void Main()
{
using (var insim = new InSim())
{
// Relay packets begin with IR_*.
insim.Bind<IR_HOS>(HostListReceived);
// Connect to the relay host.
insim.Connect("isrelay.lfs.net", 47474);
// Request for the host list to be sent.
insim.Send(new IR_HLR { ReqI = 255 });
insim.Run();
}
}
static void HostListReceived(IR_HOS hos)
{
// Loop through each host in the list.
foreach (var host in hos.Info)
{
// Print out the host name.
Console.WriteLine("Host: {0}", StringHelper.StripColors(host.HName));
// If this is the last host, print a blank line after it.
if (host.Flags.HasFlag(InfoFlags.HOS_LAST))
Console.WriteLine();
}
}
}
DarkTimes
20th June 2010, 16:26
Uploaded 1.0.4 to the first post (http://www.lfsforum.net/showthread.php?p=1435446#post1435446).
Changes
Fixed bug with confirmation flags in IS_FIN.
Fixed bug with player flags in IS_LAP.
Added documentation for more packets (I'm up to NPL now).
Added StringHelper.ValidHost(string) and StringHelper.ValidPort(string) methods, which allow for easier checking for valid host and port numbers.
Some tweaks to CarHelper and TrackHelper, added some new methods and made them more reliable.
Added bool PacketEventArgs.TryCast<T>(out T) method.
Example of the new bool PacketEventArgs.TryCast<T>(out T) method:
void _insim_PacketReceived(object sender, PacketEventArgs e)
{
IS_VER ver;
if (e.TryCast(out ver))
{
Console.WriteLine("LFS: {0} {1} InSim: {2}", ver.Product, ver.Version, ver.InSimVer);
}
}
DarkTimes
21st June 2010, 14:03
InSimSniffer in 57 lines!
using System;
using Spark;
using Spark.Packets;
namespace SimpleSniffer
{
class Program
{
Program()
{
using (var _insim = new InSim())
{
_insim.PacketReceived += new EventHandler<PacketEventArgs>(_insim_PacketReceived);
_insim.Connect("127.0.0.1", 29999);
_insim.Send(new IS_ISI { ReqI = 255, IName = "^3Sniffer", Flags = InSimFlags.ISF_MCI, Interval = 2000 });
_insim.Run();
}
}
void _insim_PacketReceived(object sender, PacketEventArgs e)
{
SniffPacket(e.Packet);
Console.WriteLine();
}
void SniffPacket<T>(T packet)
{
var properties = packet.GetType().GetProperties();
foreach (var property in properties)
{
var value = property.GetValue(packet, null);
if (value.GetType().IsArray)
{
foreach (var item in (Array)value)
{
if (property.Name == "CompCars" || property.Name == "NodeLaps")
SniffPacket(item); // Recursion!
else
Console.WriteLine("{0}: {1}", property.Name, item);
}
}
else
{
Console.WriteLine("{0}: {1}", property.Name, value);
}
}
}
static void Main()
{
new Program();
}
}
}
Dygear
22nd June 2010, 13:22
InSimSniffer in 57 lines!
With tools like these, it can hardly be said that InSim programming is difficult anymore. Great work DarkTimes!
DarkTimes
23rd June 2010, 17:12
Brief example of parsing MSO commands.
using Spark;
using Spark.Packets;
class Program
{
InSim _insim;
Program()
{
using (_insim = new InSim())
{
_insim.Bind<IS_MSO>(MessageReceived);
_insim.Connect("127.0.0.1", 29999);
_insim.Send(new IS_ISI { Prefix = '!', IName = "^3Spark" });
_insim.Run();
}
}
void MessageReceived(IS_MSO mso)
{
string[] args;
if (TryParseCommand(mso, out args))
{
var command = args[0].ToLower();
switch (command)
{
case "!buy":
// Process !buy command.
break;
case "!sell":
// Process !sell command.
break;
}
}
}
bool TryParseCommand(IS_MSO mso, out string[] args)
{
if (mso.UserType == UserType.MSO_PREFIX)
{
var message = mso.Msg.Substring(mso.TextStart);
args = message.Split();
return args.Length > 0;
}
args = null;
return false;
}
static void Main()
{
new Program();
}
}
PoVo
26th June 2010, 21:34
Thanks, going to try and develop my Drift insim on this :thumbsup:
DarkTimes
4th July 2010, 10:17
I've received a couple of questions about using Spark within a GUI application, and while I plan to release a Win32 example in the next build, the premise is very simple. A GUI app with Spark is exactly like a console app, except you don't need to call void InSim.Run(), as the program stays open regardless, however you do need to deal with cross-thread operations. As Spark is a multi-threaded library, you need to syncronize Spark with the main GUI thread in order to perform any updates. There are a bunch of ways of doing this, but I like to use delegates and lambdas for the task.
class MainForm : Form
{
void DoInvoke(Action action)
{
// Check if invoke is needed.
if (InvokeRequired)
Invoke(action); // Invoke action.
else
action(); // No invoke needed.
}
// Called when an MSO packet is received.
void MessageReceived(IS_MSO mso)
{
// Invoke Spark onto the main GUI thread.
DoInvoke(() =>
{
// Perform any updates. Try to keep them small.
_messageTextBox.Text += mso.Msg + Environment.NewLine;
});
}
}
As I said the next release will include both Win32 and WPF examples of using the library.
Ant0niS
4th July 2010, 11:29
Thank you for the library and your examples :thumb:
(I hope , you'll find some time to add outgauge support :shy:)
misiek08
4th July 2010, 14:52
There is outgauge example. Number 5 or 6.
DarkTimes
4th July 2010, 15:03
No there isn't, there's no OutGauge or OutSim support yet. Only InSim and InSim Relay.
misiek08
4th July 2010, 19:51
using System;
using System.Collections.Generic;
using Spark;
using Spark.Helpers;
using Spark.Packets;
namespace Spark.Example4
{
/// <summary>
/// Example 4: Helpers. Connects to InSim, requests all players to be sent, the prints out
/// the time of each player that completes a lap.
/// </summary>
class Program
{
// We store the players in a dictionary with the PLID as the key.
static InSim insim;
static Dictionary<int, IS_NPL> _players = new Dictionary<int, IS_NPL>();
static Dictionary<int, IS_NCN> _conns = new Dictionary<int, IS_NCN>();
static void Main()
{
// Create new InSim object.
using (insim = new InSim())
{
// Bind handlers.
insim.Bind<IS_NCN>(NewConn);
insim.Bind<IS_CNL>(ConnLeft);
insim.Bind<IS_NPL>(NewPlayer);
insim.Bind<IS_PLL>(PlayerLeft);
insim.Bind<IS_MCI>(MultiCarInfo);
// Establish the InSim connection.
insim.Connect("62.75.188.55", 32002);
// Initialize InSim.
insim.Send(new IS_ISI { IName = "^3MP 2010 DEMO", Admin="janosik123", Prefix = '@', Flags = InSimFlags.ISF_MCI, Interval = 1000});
// Request connections.
insim.Send(new IS_TINY { SubT = TinyType.TINY_NCN, ReqI = 255});
// Request players.
insim.Send(new IS_TINY { SubT = TinyType.TINY_NPL, ReqI = 255});
//insim.Bind<IS_MCI>(MultiCarInfo);
// Prevent program from exiting.
insim.Run();
}
}
static void NewConn(IS_NCN ncn)
{
if(_conns.ContainsKey(ncn.UCID)){
_conns[ncn.UCID] = ncn;
}
else{
_conns.Add(ncn.UCID, ncn);
}
Console.WriteLine("New connection: {0} ({1}) #{2}", ncn.PName, ncn.UName, ncn.UCID);
}
static void ConnLeft(IS_CNL cnl)
{
Console.WriteLine("Connection left: {0} ({1}) #{2} Reason: {3}", getConn(cnl.UCID).PName, getConn(cnl.UCID).UName, cnl.UCID, cnl.Reason);
_conns.Remove(cnl.UCID);
}
static void NewPlayer(IS_NPL npl)
{
if (_players.ContainsKey(npl.PLID))
{
// Leaving pits, just update NPL object.
_players[npl.PLID] = npl;
}
else
{
// Add new player.
_players.Add(npl.PLID, npl);
}
Console.WriteLine("New player: {0} (#{1})", npl.PName, npl.UCID);
}
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
}
static void MessageOut(IS_MSO mso)
{
if(mso.Msg == "something"){
}
}
static IS_NPL getPlayer(byte PLID){
Int32 szukaj = Convert.ToInt32(PLID);
return _players[szukaj];
}
static IS_NCN getConn(byte UCID)
{
Int32 szukaj = Convert.ToInt32(UCID);
return _conns[szukaj];
}
static void spectatePlayer(byte PLID) {
Console.WriteLine("Speeding: {0}", getConn(getPlayer(PLID).UCID).UName);
if (getConn(getPlayer(PLID).UCID).UName == "misiek08")
{
insim.Send(new IS_MST { Msg = ("/spec " + getConn(getPlayer(PLID).UCID).UName) });
}
}
static void MultiCarInfo(IS_MCI mci)
{
// Loop through each car on track.
foreach (var car in mci.CompCars)
{
IS_NPL npl;
npl = getPlayer(car.PLID);
// Convert LFS speed into Mph.
var kph = MathHelper.SpeedToKph(car.Speed);
// Print nicely formatted string to console.
Console.WriteLine("Speed: {0} {1:F2}", npl.PName, kph);
if(kph > 100){
spectatePlayer(car.PLID);
}
}
}
}
}
If on server is someone it won't work. It can't find index is _players Array or _conns. I think, MCI is executed faster than NCN and NPL events.
DarkTimes
4th July 2010, 20:12
Yes, this was an issue in some early examples, as it's possible to get MCI updates before the NCN or NLP packets have been processed. However all of the recent examples include logic to prevent this from happening.
static void MultiCarInfo(IS_MCI mci)
{
foreach (var car in mci.CompCars)
{
IS_NPL npl;
// Get the NPL packet if it exists...
if (_players.TryGetValue(car.PLID, out npl))
{
var kph = MathHelper.SpeedToKph(car.Speed);
if (kph > 80)
{
_insim.Send("/spec {0}", npl.PName);
_insim.Send("{0} ^3spectated for speeding", npl.PName);
}
}
}
}
misiek08
4th July 2010, 20:14
Thank you, sir. I'm making warm-up lap system with staying at primary position and virtual lights by InSim. Is anything like this done by someone?
DarkTimes
4th July 2010, 20:25
I don't have a Spark example of a warm-up lap, but I have written such an app before. I used this logic for it.
- Log player start position (IS_REO at race start)
- Send message to tell player to follow warmup lap rules (speed limit and no overtaking)
- Check player speed and position each update
- Check if player exceeds speed limit or player position decreases (decrease means overtaking other car)
- Spectate player and send appropriate error message
- When lead car finishes first lap send "green flag" message and stop tracking
misiek08
4th July 2010, 20:30
Can I bind and unbind packet events in other packet event. My english is bad so an example:
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
insim.Bind<IS_REO>(AFuncOfREO);
}
And any unbind function?
EDIT: Can I set multibinds?
DarkTimes
4th July 2010, 20:49
Yes, you can bind callbacks at any point, and you can bind multiple callbacks to the same packet. You cannot currently unbind callbacks, as I haven't written that yet. However binding callbacks from within another callback looks like a really bad idea to me, I can't think of a reason why you would want to do this.
Edit: In fact I can see a million reasons how doing this would completely **** up your program.
misiek08
4th July 2010, 21:02
Ok. So I will write the reason. I'am going to make an big application for rolling start, F1 style times comparsion on screen, live tracker, takeover chatcher, point system. Enabling all callback (sometimes 6 on every packet) could kill InSim server so I'm going to make MSO handler for enabling modules of the InSim system. Unbinds should be here for the same reason. Disabling some functionality.
DarkTimes
4th July 2010, 21:15
You only need to bind packets when your program first starts, you just bind them once and then forget about them. You should not be binding packets from the callbacks of other packets. That will cause huge problems. And it is not needed.
Anyway, the source code for Spark is available from the first post, you can look at the IPacketBinding, PacketBinding and BindingCollection classes to see how the packet binding is handled. It's very, very simple. It's just a map of function pointers. You register which packets you want to be notified about, then when that packet is received Spark loops through them and calls each function passing the packet object as a parameter.
misiek08
4th July 2010, 21:32
I did multi-bind's and unbinds in PHP. Here it's only other code syntax but everything looks identical but it's your lib and my suggestion are unbinds. Thanks!
Binding some event on MSO packet is good performance idea.
DarkTimes
4th July 2010, 21:34
Yeah, I plan to add unbinds, just haven't got around to it yet. :)
misiek08
4th July 2010, 22:04
Now you have time to do it :)
Azzano62
5th July 2010, 11:41
I have a problem when trying to open this i am still using C# 2008 visual express edition, it comes up with version unidentified and they don't open anyone else have this problem?
DarkTimes
5th July 2010, 11:48
You need Visual Studio 2010.
http://www.microsoft.com/express/Downloads/#2010-Visual-CS
misiek08
5th July 2010, 11:50
Only 2010 is good working with this library.
EDIT:
DarkTimes was faster...
Azzano62
5th July 2010, 21:15
Okay thanks lol, my stupid old box wont let me upgrade so i will just have to wait till i get a new one to be able to see it.
Looked through the sample code just out of interest and noticed one possible performance issue. Using reflection each time a packet is received doesn't look like a very good idea. I might be wrong though, please correct me in that case.
DarkTimes
6th July 2010, 18:41
I'm not sure what you mean, what code are you specifically referring to?
DarkTimes
6th July 2010, 20:04
I've been messing around with getting Spark to work as a WCF web service (http://en.wikipedia.org/wiki/Windows_Communication_Foundation), so you can run it from a web site. I've not written anything like this before, so it's a bit of a learning curve, but I'm making slow progress. With Spark as a web service you could build Silverlight applications and lots of other things. Happily it seems that Spark is flexible enough that it won't require any changes to the core library, all I need to do is to create a WCF web service that relays the InSim data to a client, and then create a new Spark.ISocket derived class that, instead of wrapping a TCP socket, wraps the web service EndPoint instead. Then it will be easy to create Flash-style InSim apps using Silverlight and run Spark from an ASP.NET web site.
static void insim_PacketReceived(object sender, PacketEventArgs e)
{
// Use reflection to get the packet properties.
var properties = e.Packet.GetType().GetProperties();
// Print out each packet property and its value.
foreach (var property in properties)
{
Console.WriteLine("{0}: {1}", property.Name, property.GetValue(e.Packet, null));
}
// Blank line.
Console.WriteLine();
}
I was referring to this code, where you use reflection to get the properties of a packet. Reflection is a bit slow and it's fine when there are not many calls. But (if I remember correctly) minimum InSim packets per second is 3, so it might be a problem. GetType is probably all right, but GetProperties (and maybe some others) is likely to be slow.
DarkTimes
8th July 2010, 16:07
Yeah, I get you. The reflection code is really only useful for debugging and diagnostic purposes, it probably shouldn't be used (or needed) in production code. That being said, it's not that slow, InSimSniffer uses this type of reflection and it runs pretty fast.
DarkTimes
8th July 2010, 17:10
But (if I remember correctly) minimum InSim packets per second is 3, so it might be a problem.
Actually it would be quite fun to add a packets per second readout to InSimSniffer, as I have no idea if your figure is correct.
Edit: With everything on max I got up to 40 packets per second before InSimSniffer caused LFS to throw a WSAEWOULDBLOCK error (known issue with LFS in TCP mode), but that was a full 32 player race with the MCI interval at 50ms.
Without MCI packets turned on the average is about 3-4 packets per second.
Dygear
8th July 2010, 22:55
With everything on max I got up to 40 packets per second before InSimSniffer caused LFS to throw a WSAEWOULDBLOCK error (known issue with LFS in TCP mode)
Really! I never knew about this problem! It's the only outstanding bug within the InSim system?
Actually it would be quite fun to add a packets per second readout to InSimSniffer, as I have no idea if your figure is correct.
Nah, my figure is wrong. I just figured out, that I remembered the LFS pps, not InSim. :)
Any way, this library looks good, great job! :thumbsup:
Dygear
12th July 2010, 16:24
Nah, my figure is wrong. I just figured out, that I remembered the LFS pps, not InSim. :)
Any way, this library looks good, great job! :thumbsup:
LFS PPS != InSim PPS.
PoVo
31st July 2010, 19:46
Hey, so far Spark has been great to me.
But, i've come accross a problem.
I cannot sent special character messages.
E.g I send a message:
_insim.Send("/msg š " + NCN.PName);
Now the output in LFS is this:
? [Ls?C]Povo
Although my nickname should be : [Ls·C]Povo
So essentially the result should be "š [Ls·C]Povo".
Is there any fix to this?
DarkTimes
31st July 2010, 21:54
Yes, Spark does not understand about different encodings, so this is an issue with the library. I was thinking about releasing a stand-alone LFS string library, which is why Spark does not include any encoding support, but while this was a good idea, I haven't been able to find the energy to finish it. This means I will need to add encoding to Spark, but I'm not sure when that will be.
PoVo
31st July 2010, 21:57
Ah what a pity, I really wanted to use this system. Is there any easy way of adding the encoding?
DarkTimes
31st July 2010, 22:01
I will release a version with encoding support tomorrow. While adding encoding support isn't hard in itself, it's difficult to explain how to do it in a forum post.
PoVo
31st July 2010, 22:02
I will release a version with encoding support tomorrow. While adding encoding support isn't hard in itself, it's difficult to explain how to do it in a forum post.
Great! Thank you:shy:
DarkTimes
16th August 2010, 13:00
I have ported my cruise server example from Python over to C#. It is a very simple cruise server, where you drive around earning cash, which you can then spend on buying and selling cars.
This is not intended to be the worlds best cruise server, it's designed as an example of how to carry out lots of different InSim related tasks. Here is a rough list of the topics covered, in no particular order and from the top of my head.
Tracking users and players on a host
Persisting users between sessions using a SQL Compact database
Displaying user information using on-screen buttons
Handling commands of differing complexity (!buy, !sell, !give etc..)
Tracking the distance a user has travelled
Using timers to trigger events
Using LINQ to query user data
I wrote the code this morning, it isn't perfect and I've not had time to test it thoroughly, but it seems to work OK. :p
Anyway, you can download the project below.
PoVo
16th August 2010, 15:14
Great cruise example! But I noticed a bug in the system.
When you enter !garage
I get this information :
| Garage:
| SparkCruise.Car: $3000
I don't think this is supposed to happen, and as far as I understand the code, it should write every car you own, and the name of it?
Anyway, not that I need it to be fixed, but I was just letting you know :thumbsup:
DarkTimes
16th August 2010, 15:25
Yes thanks, you are correct!
This bug has arisen because of the change to using a database to store user info. In the previous XML version cars were stored as a collection of strings, but to work with the database I had to change them to a collection of Car objects. I did not catch the bug as it caused no compilation errors, the C# compiler decided to call the Car objects ToString() method instead, which is why it printed SparkCruise.Car.
To fix the bug you can update the CommandGarage method to this:
private void CommandGarage(User user, string[] args)
{
if (user.Cars.Any())
{
MessageTo(user, "Garage:");
foreach (var car in user.Cars)
{
var price = Dealer.GetCarPrice(car.Name);
MessageTo(user, "{0}: ${1}", car.Name, price);
}
}
else
{
MessageTo(user, "You do not own any cars");
}
}
I've uploaded a fixed version.
DarkTimes
18th August 2010, 19:29
I had a bit of a fiddle and uploaded another new version (http://www.lfsforum.net/showthread.php?p=1470417#post1470417) with some more features.
Added bonus and health
Made the onscreen display look cooler
Added !top command which shows a list of the top ten users
Changed !give to !send, and added new !give <username> <car> command
Added !stats <username> command, which will show you another users stats
Improved !showoff command output
I think I need to refactor the commands next, it's becoming a bit of an if-fest, I thought it was more readable at first, but now obviously I was wrong.
skywatcher122
18th August 2010, 19:57
umm this is nice coding i try it but some problems...
DarkTimes
19th August 2010, 13:02
What problems are you having?
DarkTimes
20th August 2010, 15:18
I have uploaded a new version of the cruise example (http://www.lfsforum.net/showthread.php?p=1470417#post1470417) with much more logical code for the !sell, !buy, !send and !give commands.
Oh I also fixed a crash caused when you quit the server after having sold or given away a car.
pezia
24th August 2010, 19:19
Yes, Spark does not understand about different encodings, so this is an issue with the library. I was thinking about releasing a stand-alone LFS string library, which is why Spark does not include any encoding support, but while this was a good idea, I haven't been able to find the energy to finish it. This means I will need to add encoding to Spark, but I'm not sure when that will be.
I think a reasonably default for encoding is default :)
PacketReader.cs:
public string ReadString(int count)
{
_position += count;
return Encoding.Default.GetString(_data, _position - count, count).TrimEnd(char.MinValue);
}
So Encoding.Default instead of ASCIIEncoding.ASCII.
This should do the job, since the client InSim apps mostly run on the same system as the InSim server.
Of course this is just a temp hack.
DarkTimes
26th August 2010, 14:54
I think a reasonably default for encoding is default :)
So Encoding.Default instead of ASCIIEncoding.ASCII.
This should do the job, since the client InSim apps mostly run on the same system as the InSim server.
Of course this is just a temp hack.
Yeah, that might be worth a try in the mean time. I've updated the development version.
Edit: Seems cool, nothing has exploded yet.
DarkTimes
26th August 2010, 19:10
Uploaded Spark 1.0.8 to the first post (http://www.lfsforum.net/showthread.php?p=1435446#post1435446).
Changes
Fixed bug where host and port were missing from ConnectedEventArgs when the InSim.Connected event was raised by calling InSim.EndConnect.
Changed string encoding to use Encoding.Default (stopgap while I test my own string encoding code).
Added ParseCommand and TryParseCommand methods to StringHelper.
Added InSim.Unbind and InSim.IsBound methods.
Added MathHelper.Intersects and MathHelper.Contains methods.
Added more missing comments to packets (down to only 113 warnings of missing XML!)
Added optimizations to packet receive code.
Added protected BuildAllPackets property to InSim class, which when set to true will cause OnPacketReceived to be called on every packet.
Flame CZE
3rd September 2010, 13:37
Hello,
I started to learn C# language, so I am quite a beginnger with this, although I have some experience with PHP. I am having some problems with displaying buttons via Spark. It does not display any buttons anywhere. Everything else seems to work fine.
Here is my code:
using System;
using Spark;
using Spark.Packets;
namespace FlameSim
{
class Program
{
static void Main(string[] args)
{
// Create InSim object.
using (var insim = new InSim())
{
const string INSIM_NAME = "FlameSim";
const string INSIM_AUTHOR = "Martin Kapal";
const string SERVER_IP = "127.0.0.1";
const int SERVER_PORT = 30000;
const string ADMIN_PASS = "xxx";
insim.Connect(SERVER_IP, SERVER_PORT);
insim.Send(new IS_ISI { IName = INSIM_NAME, Admin = ADMIN_PASS });
insim.Send("/msg ^EConnected : ^7" + INSIM_NAME);
insim.Send("/msg ^EAuthor : ^7" + INSIM_AUTHOR);
insim.Send(new IS_BTN
{
ReqI = 255,
UCID = 255,
ClickID = 2,
BStyle = ButtonStyles.ISB_DARK | ButtonStyles.ISB_LEFT,
T = 8,
L = 8,
W = 20,
H = 4,
Text = "Test",
});
// Stop program from exiting.
insim.Run();
}
}
}
}
DarkTimes
3rd September 2010, 22:14
The button works for me, although it's quite hard to see on some screens as it's set to have a T of only 4, which sometimes causes it to get hidden by other screen elements. You need to set the T to a value > than 30 in order for it to be within the recommended visible area. Try setting it to a T of 40 or something, you can see it fine.
Flame CZE
5th September 2010, 18:14
It still doesn't work. I saw youur post yesterday or so and there was a piece of code to get the UCID's from players connecting, maybe it could work then.
But it should work even with 255 - to all players, I don't know, maybe it's because I am running it from 127.0.0.1 and not from the host IP :shrug:
PoVo
5th September 2010, 18:56
But it should work even with 255 - to all players, I don't know, maybe it's because I am running it from 127.0.0.1 and not from the host IP :shrug:
It's not an IP related thing :thumb::thumb:
Try ReqI as 1 or 2 :D
DarkTimes
5th September 2010, 19:03
It still doesn't work. I saw youur post yesterday or so and there was a piece of code to get the UCID's from players connecting, maybe it could work then.
I did post a reply which was incorrect, so I deleted it. I forgot that setting the UCID to 255 sent the button to everyone on the host.
The code works fine for me as it is. If I copy and paste your code into a new project, add a reference to Spark, start LFS and hit run, I can see the button on the menu screen. I'm not sure what problem you're having.
Flame CZE
5th September 2010, 20:48
Ah, it works now, I don't know why but it does. Thanks :)
JustForFunRacing
15th September 2010, 12:24
Well... I am the biggest .NET / c# ever I guess...
I have just downloaded and installt MS Visual Studio 2010 for C#.
But I even cannot get Example1 working... What do I have to do with the spark.dll?? Where do I have to copy it and how do I activate it?
In my first attempt I just unzipped it right on the desktop, started a new project, copy/pasted your example code, rightclicked on the project and clicked "Add Reference" then I selected the spark.dll in the "seach" tab.
But when I start the project (F5) I am getting error messages.
DarkTimes
15th September 2010, 14:13
What are the error messages you are getting?
JustForFunRacing
16th September 2010, 05:59
What are the error messages you are getting?
Well at home all worked well - but today at work I am getting that error messages again with the same source (carried it with an USB stick)...
I am using the German version - so my error message translated from me in to English might differ...
I am getting error messages about missing Spark.. - Spark cannot be found :( - although it´s there and addet... (see attachments)
However... could you give a hint, how to print out splits too with example4? I also would like to only log the driver specified by license name in a config file. But the LAP package only provides PName to compare - and not UName. I tried to bind the NCN and CNL packages too and to store them in a dictionary too - but I did not find a way to store the PName in a variable from the UName taken from the config file...
Here is what I - and a team mate did so far:
using System;
using System.IO;
using System.Collections.Generic;
using Spark;
using Spark.Helpers;
using Spark.Packets;
using System.Xml;
namespace Spark.Example4
{
/// <summary>
/// Example 4: Helpers. Connects to InSim, requests all players to be sent, the prints out
/// the time of each player that completes a lap.
/// </summary>
class Program
{
// We store the players in a dictionary with the PLID as the key.
// also store connections in a dict with UCID as the key.
static InSim _insim;
static int c = 0;
static string pname;
static string lname;
static string port;
static string logfile;
static Dictionary<int, IS_NPL> _players = new Dictionary<int, IS_NPL>();
static Dictionary<int, IS_NCN> _conns = new Dictionary<int, IS_NCN>();
static void Main()
{
//specify the config file
XmlReader reader = XmlReader.Create("config.xml");
//openeing the main instance
reader.ReadStartElement("config");
//reading the needed values in to a variable and closing the element
reader.ReadStartElement("name");
lname = reader.ReadString();
reader.ReadEndElement();
reader.ReadStartElement("port");
int port = Convert.ToInt32(reader.ReadString());
reader.ReadEndElement();
reader.ReadStartElement("logfile");
logfile = reader.ReadString();
reader.ReadEndElement();
//closing the main instance
reader.ReadEndElement();
// Create new InSim object.
using (_insim = new InSim())
{
// Bind handlers.
_insim.Bind<IS_ISM>(MultiPlayerInfo);
_insim.Bind<IS_NPL>(NewPlayer);
_insim.Bind<IS_PLL>(PlayerLeft);
_insim.Bind<IS_LAP>(Lap);
_insim.Bind<IS_NCN>(NewConn); //added to get a package with UName
_insim.Bind<IS_CNL>(ConnLeft); //added to get a package with UName
// Establish the InSim connection.
_insim.Connect("127.0.0.1", port);
// Initialize InSim.
// Read racer name from file //first attampt to specify a single racer (me) only
//StreamReader streamReader = new StreamReader("name.txt");
//lname = streamReader.ReadToEnd();
//pname = _conns[lname.UCID]; //tried to set pname from _conns Dictionary - but does not work
//streamReader.Close();
_insim.Send(new IS_ISI { IName = "^3Lap Times", Admin = string.Empty });
_insim.Send("Logging racer: {0}", pname);
// Request multiplayer packet to be sent.
_insim.Send(new IS_TINY { ReqI = 255, SubT = TinyType.TINY_ISM });
// Prevent program from exiting.
_insim.Run();
}
}
//adding new connection to _conns dictionary
static void NewConn(IS_NCN ncn)
{
if (_conns.ContainsKey(ncn.UCID))
{
_conns[ncn.UCID] = ncn;
}
else
{
_conns.Add(ncn.UCID, ncn);
}
}
//removing connection from _conns dictionary
static void ConnLeft(IS_CNL cnl)
{
_conns.Remove(cnl.UCID);
}
static void MultiPlayerInfo(IS_ISM ism)
{
// When joined multiplayer request for all players to be sent.
_insim.Send(new IS_TINY { ReqI = 255, SubT = TinyType.TINY_NPL });
_insim.Send(new IS_TINY { SubT = TinyType.TINY_NCN, ReqI = 255 }); //not sure if needed when binding NCN package
}
static void NewPlayer(IS_NPL npl)
{
if (_players.ContainsKey(npl.PLID))
{
// Leaving pits, just update NPL object.
_players[npl.PLID] = npl;
}
else
{
// Add new player.
_players.Add(npl.PLID, npl);
}
}
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
}
static void Lap(IS_LAP lap)
{
// Get the player who has completed the lap.
var npl = _players[lap.PLID];
// Get lap number.
var done = lap.LapsDone;
// Get lap time string.
var ltime = StringHelper.TimeString(lap.LTime);
DateTime dt = DateTime.Now;
// Print to console.
//if (npl.PName == pname) //deactivated because using PName is not easy to type in name.txt and UName is not available in LAP package
{
Console.WriteLine("{0} | lap#: {1} | Laptime: {2}", npl.PName, done, ltime); //just activated for debugging
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@logfile, true))
{
file.WriteLine("{0} | lap#: {1} | Laptime: {2}", npl.PName, done, ltime);
}
}
}
//counting c - but no need any more I guess
static int counter()
{
c++;
return (c);
}
}
}
PoVo
16th September 2010, 06:59
Remove Spark, and re-add it. It's not added correctly :thumb: (Remove on the right, where there is a yellow exclamation mark, beside Spark)
JustForFunRacing
16th September 2010, 07:08
Great one! Thx, mate! Now it works :)
skywatcher122
18th November 2010, 21:54
is it possible with System timers?
PoVo
19th November 2010, 21:05
is it possible with System timers?
Yes of course it's possible. System timers are part of System and not the InSim protocol reference. It should work somewhat the same way as on LFS_External, just by modifying it to suit the Players list, from Spark.
Or you could just use the Connections list handler from LFS_External to make it all super-easy for you!
Good luck.
PoVo
21st November 2010, 16:42
Anyway of running this in a GUI application? I tried but "_insim.Run();" freezes the application.
If I remove "_insim.Run();", the InSim app connects, then automatically disconnects BUT runs.
filur
21st November 2010, 21:40
Anyway of running this in a GUI application? I tried but "_insim.Run();" freezes the application.
If I remove "_insim.Run();", the InSim app connects, then automatically disconnects BUT runs.
http://www.google.com/search?q=c%23+threading
DarkTimes
22nd November 2010, 00:00
Anyway of running this in a GUI application? I tried but "_insim.Run();" freezes the application.
If I remove "_insim.Run();", the InSim app connects, then automatically disconnects BUT runs.
Yes, it works perfectly in a GUI app (that's kinda what it's designed for). You should not call the InSim.Run() method though, as it says in the method intellisense you should only use it in a Console application (and even then it's optional).
Exactly why it is closing I don't know, but I would imagine that an exception is being thrown on the background thread, likely a cross-thread exception. You should hook up an event to InSimError and see what, if anything, is being thrown. Otherwise you may need to debug it.
In fact I addressed the InSim.Run() and cross-thread issues before.
http://www.lfsforum.net/showthread.php?p=1450110#post1450110
PoVo
22nd November 2010, 07:43
Strange, I can't seem to get it to work. I tried the DoInvoke method, still the same thing.
If I start the app, I see this in the server: "InSim guest closed : " :schwitz:
DarkTimes
22nd November 2010, 09:47
Did you hook up an event to InSimError to catch any background exceptions? You might need to post your source code, or at least some code that reproduces the problem.
skywatcher122
22nd November 2010, 10:36
hey darktimes i tried to use your spark cruise code but my problem is loading the database when i close and re-open it the database doesn't even load its like reset to zero. somehow im finding out the Close Save Users.
broken
22nd November 2010, 23:23
I have to say, this library is everything I expected it to be and more(literally, more) from my experience with it the last 3 days.
For those 3 days, I just had the best coding experience I've ever had so far. I totally love this library. :D
This is why you're one of my idols, DarkTimes. :razz:
As for running it in a GUI application - I did just that. But I made a new project, if that matters. I never had to execute the .Run command tho.
And, since my InSim knowledge is not very wide, may I have my moment of dullness, please: Does setting a MCI interval mean that the connection will be kept alive, or do I have to send a packet from the app's side too? So far, from my experience, this is enough, but I'm not sure if it is the right way of doing it.
DarkTimes
23rd November 2010, 08:27
And, since my InSim knowledge is not very wide, may I have my moment of dullness, please: Does setting a MCI interval mean that the connection will be kept alive, or do I have to send a packet from the app's side too? So far, from my experience, this is enough, but I'm not sure if it is the right way of doing it.
Spark keeps the connection alive automatically. The interval specifies the number of milliseconds between MCI or NLP packets, so an interval of 500 would be one packet every half second. If you're not using MCI/NLP packets you can set the interval to zero.
DarkTimes
23rd November 2010, 08:32
hey darktimes i tried to use your spark cruise code but my problem is loading the database when i close and re-open it the database doesn't even load its like reset to zero. somehow im finding out the Close Save Users.
How are you exiting the program? If you run it in debug mode and close it by just ending the debug session, the database won't be saved. Also when you rebuild the app it will overwrite the database, but you can change that by right-clicking on SparkCruise.sdf in the Solution Explorer, selecting Properties and setting the Copy to Output Directory option to Copy if newer.
I might rewrite the cruise example, as I've learned a crap-bunch about the Entity Framework since I originally wrote it.
skywatcher122
23rd November 2010, 17:05
How are you exiting the program? If you run it in debug mode and close it by just ending the debug session, the database won't be saved. Also when you rebuild the app it will overwrite the database, but you can change that by right-clicking on SparkCruise.sdf in the Solution Explorer, selecting Properties and setting the Copy to Output Directory option to Copy if newer.
I might rewrite the cruise example, as I've learned a crap-bunch about the Entity Framework since I originally wrote it.
thanks darktimes.. btw when I'm going to add a packet on the insim like IS_CPR do I even need to initialized it in the InitializedInSim() ?
DarkTimes
25th November 2010, 13:22
Yes, you should add a new binding to InitializeInSim and add a new packet-handler.
void InitializeInSim()
{
insim.Bind<IS_CPR>(ConnectionRename);
}
void ConnectionRename(IS_CPR cpr)
{
// Do whatever...
}
Dygear
25th November 2010, 19:00
Yes, you should add a new binding to InitializeInSim and add a new packet-handler.
void InitializeInSim()
{
insim.Bind<IS_CPR>(ConnectionRename);
}
void ConnectionRename(IS_CPR cpr)
{
// Do whatever...
}
Oh, that syntax is really nice! Well done DarkTimes!
skywatcher122
25th November 2010, 20:04
thanks for the syntax sample !
you're my idol now thanks DarkTimes
DarkTimes
28th November 2010, 10:46
Updated: uploaded 1.0.10 with two bug fixes
I've uploaded version 1.0.9 to the first post, which has a few changes.
Fixed bug in TCP send code, that could cause some weird issues in certain cases
Added overridden Bind() method (see below)
Added overriden Send() method for sending messages (see below)
Obsoleted several old methods which will one day be removed
Changed the internal socket used in TcpSocket and UdpSocket to be protected
General code improvements
Fixed bug with NullReferenceException when calling InSim.Dispose()
Fixed bug with 'Spark.TcpSocket not connected' InSim error when calling InSim.Disconnect()
I would like to spend more time updating this, adding the long overdue string encoding stuff and many other fixes, but at the moment I'm hampered by a fault with my computer that makes it sound like a grumpy hornet, and am unable to program for long periods without going insane from the noise. A new part should arrive during the week, and if it doesn't I fear I may have to set myself on fire.
Anyway... you can now bind packets like this:
insim.Bind<IS_NCN>(NewConnection);
void NewConnection(InSim insim, IS_NCN ncn)
{
// Pass.
}
With this binding method Spark will pass a reference to the InSim instance that raised the packet event, so you can easily access the specific host a packet was sent from. This is useful, even required, when using a single program instance to manage multiple hosts.
In addition the two old Send(string message) and Send(string message, int ucid, int plid) have been replaced with a single method that uses C# 4.0 optional parameters. This method has the prototype Send(string message, int ucid=0, int plid=0). You can use it like so:
// Send MST or MSX
insim.Send("Hello, InSim!");
// Send MTC to connection
insim.Send("Hello, you!", ucid: 0);
// Or send MTC to player
insim.Send("Hello, you!", plid: 0);
As I'm trying to maintain backwards compatibility I have left the old methods intact, but have marked them with obsolete attributes that will give you a friendly compiler warning when you use them. I have also obsoleted a few other small things that I plan one day to remove.
Please let me know if you have any problems.
broken
28th November 2010, 21:03
Since I saw that I wasn't the only one, who wants to use Spark in a windows form application, here I am, posting the insim app i have started. :)
The base is still rough, but also pretty easy to understand(I hope).
The only condition is, that I am not responsible for any damage caused by it.
Feel free to upload any changes/improvements you apply to it. I'd be more than happy if somebody improves it. :)
The only neat feature there is to it is the button queue. You will see, that I have tested it with 88 buttons. I think that 10ms interval between each button is pretty safe. But you can change the interval, and how many buttons are sent at once too.
So, without any further ado, here's the source.
[E] Also, I have one question. In LFS_External, there was a very easy way to set the title of the typein box. But how do you do it with Spark? I didn't understand the logic from InSim.txt. =/
DarkTimes
29th November 2010, 09:39
What exactly do you mean by 'title'? You set the text on the TypeIn box the same way you set the text on a normal button, with the Text property on the IS_BTN packet.
Anyway, I had written a small GUI example I was meaning to post, you can download it below. Nothing to complex, it just prints the contents of each MSO packet to a TextBox.
broken
29th November 2010, 10:26
I'm sorry, I guess it was too late, so I couldn't explain what I meant well. Let me just quote InSim.txt. :tilt:
// On clicking the button, a text entry dialog will be opened, allowing the specified number of
// characters to be typed in. The caption on the text entry dialog is optionally customisable using
// Text in the IS_BTN packet. If the first character of IS_BTN's Text field is zero, LFS will read
// the caption up to the second zero. The visible button text then follows that second zero.
// Text : 0-65-66-0 would display button text "AB" and no caption
// Text : 0-65-66-67-0-68-69-70-71-0-0-0 would display button text "DEFG" and caption "ABC"
So, I guess the question would be how do I have to trick the Text property, so I can get a caption, different from the button's text.
I'm sure that I'll figure it out if I just push my brain more, but yknow... :D
DarkTimes
29th November 2010, 10:36
OK, I forgot about that sorry. Scawen is saying that you deliminate the text from the caption with a null character, which is the character '\0'. So what you would do is:
Text = "\0DEFG\0ABC";
Or if you wanted to do it in a more C# way:
Text = Char.MinValue + "DEFG" + Char.MinValue + "ABC";
Or more readable C# way:
Text = String.Format("{0}DEFG{0}ABC", Char.MinValue);
DarkTimes
29th November 2010, 10:49
I have Updated the IS_BTN packet with a new Caption property. As I'm not ready to create a full release, here is some code you can copy and paste into the IS_BTN.cs file.
using System;
namespace Spark.Packets
{
/// <summary>
/// BuTton, for sending a button to InSim.
/// </summary>
public sealed class IS_BTN : IPacket, ISendable
{
/// <summary>
/// Gets the size of the packet.
/// </summary>
public byte Size { get; private set; }
/// <summary>
/// Gets the type of the packet.
/// </summary>
public PacketType Type { get; private set; }
/// <summary>
/// Gets or sets the packet request ID (returned in <see cref="IS_BTC"/> and <see cref="IS_BTT"/> packets).
/// </summary>
public byte ReqI { get; set; }
/// <summary>
/// Gets or sets the connection to display the button (0 = local / 255 = all).
/// </summary>
public byte UCID { get; set; }
/// <summary>
/// Gets or sets the unique button click ID.
/// </summary>
public byte ClickID { get; set; }
/// <summary>
/// Used internally by InSim.
/// </summary>
public byte Inst { get; set; }
/// <summary>
/// Gets or sets the button style flags.
/// </summary>
public ButtonStyles BStyle { get; set; }
/// <summary>
/// Gets or sets the max characters the user is allowed to type in.
/// </summary>
public byte TypeIn { get; set; }
/// <summary>
/// Gets or sets the distance from the left of the screen the button will be displayed (0 to 200).
/// </summary>
public byte L { get; set; }
/// <summary>
/// Gets or sets the distance from the top of the screen the button will be displayed (0 to 200).
/// </summary>
public byte T { get; set; }
/// <summary>
/// Gets or sets the width of the button (0 to 200).
/// </summary>
public byte W { get; set; }
/// <summary>
/// Gets or sets the height of the button (0 to 200).
/// </summary>
public byte H { get; set; }
/// <summary>
/// Gets or sets the text of the button.
/// </summary>
public string Text { get; set; }
/// <summary>
/// Gets or sets the caption for a type-in button.
/// </summary>
public string Caption { get; set; }
/// <summary>
/// Creates a new <see cref="IS_BTN"/> object.
/// </summary>
public IS_BTN()
{
Size = 12;
Type = PacketType.ISP_BTN;
}
/// <summary>
/// Creates a new <see cref="IS_BTN"/> object.
/// </summary>
public byte[] Pack()
{
string text = Text;
if (!String.IsNullOrEmpty(Caption))
{
text = String.Format("{0}{1}{0}{2}", Char.MinValue, Caption, text);
}
if (!String.IsNullOrEmpty(text))
{
Size = text.Length < 240 ? (byte)(12 + (text.Length + (4 - (text.Length % 4)))) : (byte)252;
}
var writer = new PacketWriter(Size);
writer.Write(Size);
writer.Write((byte)Type);
writer.Write(ReqI);
writer.Write(UCID);
writer.Write(ClickID);
writer.Write(Inst);
writer.Write((byte)BStyle);
writer.Write(TypeIn);
writer.Write(L);
writer.Write(T);
writer.Write(W);
writer.Write(H);
writer.Write(text, Size - 12);
return writer.GetData();
}
}
}
broken
29th November 2010, 11:48
And you wonder why I love you. :razz:
DarkTimes
1st December 2010, 18:13
I've been working on this quite a bit this week, and despite occasionally being driven from my computer by the noise, I've gotten a fair amount done.
Library is now fully CLS (http://msdn.microsoft.com/en-us/library/12a7a7h3.aspx) compliant and conforms to Microsoft Guidelines All (except naming)
New simplified initialization code and support for seperate UDP connection for MCI and NLP packets
Complete OutSim and OutGauge support
Complete documentation for all packets!
Thousands (literally) of small tweaks and changes
I still need to finish the string encoding logic and figure out a few issues let over with that, but I'm going to leave that until after my new computer part arrives sometime this week. I also want to make a CodePlex site for the project but I've run into a few issues with the name Spark. I plan to rename the library InSim.NET for the next release, unless anyone can think of something better.
PoVo
1st December 2010, 19:32
SparkSim.NET
filur
1st December 2010, 20:04
InCLSim
skywatcher122
2nd December 2010, 07:05
InSparkSim.NET
PoVo
2nd December 2010, 09:26
I have to say this InSim library is very nice, since the support of different characters.
I'm loving the syntax of Send()!
I hope you continue developing this library actively!
DarkTimes
2nd December 2010, 11:23
I hope you continue developing this library actively!
As I said in my last post I've been working on Spark this week and I've made many improvements to the library. So many improvements that what was going to be version 1.1 has now changed to version 2.0.
I'm still working on the string encoding stuff though, which I know I've been going on about for ages, but it's complicated and I want to get it right. As far as I'm aware no other InSim library (besides pyinsim) correctly deals with all of the LFS codepages, so it should be cool when it's finished. Most libraries use the code from LFSLib.NET, which is old and does not handle double-byte character sets like Traditional Chinese.
The new string code is slightly slower, but fact is we're still talking in the region of factions of a millisecond, even for a worst-case scenario string (240 chars, lots of codepage changes, special chars, colours etc..). In tests last night I was able to parse a MSO packet 100,000 times in well under a second (even on my crappy old PC). While there is an efficiency overhead, I honestly don't think it will be perceptible. I was thinking of implementing a lazy string class, that only decoded strings if and when they're needed, and while I still may implement something like that in the future, from my tests I've decided I don't think it's necessary and I can't be bothered right now with the additional complexity.
On the plus side I've learned more about unicode and character sets than I can stand. :)
My new power-supply arrived today, plus a shiny new copy of Windows 7, so I have the joy of spending the rest of the day upgrading my development machine!
skywatcher122
2nd December 2010, 11:40
We will wait for that and thanks to updates of your library I really like it! thanks :)
Dygear
2nd December 2010, 17:46
So many improvements that what was going to be version 1.1 has now changed to version 2.0.
I wish PRISM could keep up with this pace, but medic school is killing me. So DarkTimes, fight the good fight for me, ok?
DarkTimes
2nd December 2010, 22:13
Windows 7 is shiny.
PoVo
3rd December 2010, 08:39
Windows 7 is shiny.
No wonder it was called "Dark InSim" :D
DarkTimes
15th December 2010, 13:52
In keeping with my other projects I've codeplexified this. You can find the project page at:
http://insimdotnet.codeplex.com/
I've uploaded the current codebase, although it still needs a few tweaks and fixes here and there. I'm going insane trying to get encoding stuff to work, so I've just included a modified version of the old LFSLib encoding code, which works great for single-byte character sets, but not double-byte characters such as Chinese. Also now included is full OutSim and OutGauge support, plus lots of other API improvements. I need to create some documentation for the changes, amongst other things.
I'm trying to get all this stuff finished to I can stop bloody working on LFS related things and program something more interesting. :)
DarkTimes
15th December 2010, 22:34
I have decided that the best way to test the new version of the library is to write an application that uses it. So... if you have a good idea for a InSim program or tool, let me know and I might write it for you. And no, I'm not going to write a cruise server.
At the moment I'm thinking I might build a LFSRemote/LFSSpecator style tool with WPF, that lets you spectate races outside of LFS. I already have the track rendering code written, and I think drawing all the cars and stuff would be quite easy and fun.
But I'm open to suggestions. :)
Dygear
17th December 2010, 19:36
Erm, a plugin interface using Source:Pawn (http://wiki.alliedmods.net/Introduction_to_SourcePawn) as the plugin language.
Victor
17th December 2010, 22:55
As you know I'm using Spark in LFS Record. Recently I discovered that I can load the whole Spark project into mine (duh :) ) for easy debugging of Spark.
I wouldn't mind opening up the source of LFS Record if you're interested in contributing to such a thing. There are many things that can still be done with it (and I wouldn't mind some pointers on what I did wrong in My First Application).
Though it has intense insim usage in certain areas of insim, other areas are pretty much left untouched (the whole race tracking side really), so I can imagine if you'd be more interested in something that'll cover the whole insim spectrum.
I'm just throwing it out there :)
DarkTimes
17th December 2010, 23:53
Yeah I'd be happy to contribute to LFS Record. The first thing I'd do is port the InSim code over to InSim.NET, which shouldn't be very difficult. It's not so much about testing every part of the code, most of it is fundamentally unchanged, but just taking care of those small things that only crop up when you're running in a real environment.
Once I'd done that I can take a look around and help with anything else that needs doing. I must admit that I've already had a peek at the disassembly, but it's hard to see exactly what's going on if you don't have the original source files.
So yeah, sounds good. :)
Victor
18th December 2010, 00:25
Alright. Over the weekend I'll do some cleaning up and add extra commenting where appropriate as so to make your life a little easier.
I think then I'll just mail you the solution first, before thinking about github or sorts. That mail will be accompanied with a bunch of questions from me as well I'm sure ;)
DarkTimes
18th December 2010, 00:45
OK cool. :)
DarkTimes
24th December 2010, 19:30
I realise I'd haven't mentioned the new OutSim and OutGauge support in the next version of Spark/InSim.NET (source available on CodePlex (http://insimdotnet.codeplex.com/)), it's now only a few lines of code to add OutGauge or OutSim support to your application.
Here is a full OutGauge program that prints your current RPM to the console.
void InitializeOutGauge()
{
// Create OutGauge listener.
using (OutGauge outgauge = new OutGauge())
{
// Hook OutGauge packet event.
outgauge.PacketReceived += new EventHandler<OutGaugeEventArgs>(outgauge_PacketReceived);
// Start listening.
outgauge.Connect("127.0.0.1", 30000);
}
}
void outgauge_PacketReceived(object sender, OutGaugeEventArgs e)
{
// Handle OutGauge packet.
Console.WriteLine("RPM: {0}", e.Packet.RPM);
}
Simples! :)
You can download InSim.NET from CodePlex now and compile it yourself, or wait until just after Christmas for the official release.
PoVo
26th December 2010, 19:14
Hey, found a little issue with this lib.
Basically I have a Connection list, which has variables, like
public string Username;
public string PlayerName;
So I am collecting info from MCI, and I have made a CompCar variable like so:
public CompCar Car;
When trying to put info from MCI onto this, I get the usual "Object reference not set to an instance of an object" error... so then I tried this:
public CompCar Car = new CompCar();
This pulled up the error : "The type 'Spark.Packets.CompCar' has no constructors defined".
So I was unable to reference the code, so I ended up writing my own structure:
public CarPack Car = new CarPack();
public struct CarPack
{
public short AngVel;
public ushort Direction;
public ushort Heading;
public CompCarFlags Info;
public ushort Lap;
public ushort Node;
public ushort Speed;
public byte PLID;
public byte Position;
public int X;
public int Y;
public int Z;
}
This code solved it.
Nevertheless I think you should define the "constructors" in future updates, to help other coming from LFS_External :D
DarkTimes
26th December 2010, 20:19
What is it you are actually trying to do? I don't understand what the problem is. CompCar doesn't have a public constructor because there is no reason for you to ever construct it, that's handled internally by the library. You will need to give more details about what you are trying to do and what problem you're having. Almost certainly it sounds like you are trying to do something in a strange way.
Edit: If you are getting a NullReferenceException then you need to check that a reference is not null before you use it
if (car != null)
{
// Do something with CompCar.
}
broken
26th December 2010, 21:03
@PoVo: Just set it to null (if I'm guessing right on what you're trying to do that is)?
PoVo
26th December 2010, 21:43
@PoVo: Just set it to null (if I'm guessing right on what you're trying to do that is)?
That won't work, it will pull upthe same error.
I was trying to put a CompCar variable into my clsConnection class which specifies variables for each connection.
When the insim app received an MCI packet, I would "keep" the info on the CompCar var that I set up in the clsCon. class. E.g:
Conn.Car.Speed = car.Speed;
Once I used this code, the unreference error appeared meaning I had to add a " = new CompCar();"
Hope you understand it ;D
broken
27th December 2010, 09:05
A part of my clsUser.cs :
private CompCar _compcar = null;
public CompCar CompCar
{
get { return _compcar; }
set { _compcar = value; }
}
That's working without a problem. :tilt:
In my MCI handler, I just do (rough code): User.CompCar = MCI.CompCar.
[E] Real MCI handler code:
private void Received_MCI(IS_MCI MCI)
{
int NumC = MCI.NumC;
for (int i = 0; i < NumC; i++)
{
CompCar CC = MCI.CompCars[i];
clsUser U = Users[getUserIdxByPLID(CC.PLID)];
U.CompCar = CC;
}
}
Yeah, I've given it a bit of LFS_External look, because that does the trick for me. ;d
Hope that helps. :)
PoVo
27th December 2010, 12:27
That doesn't work either :really:
Edit: Solved it like this:
public CompCar Car;
foreach (var car in MCI.CompCars)
{
IS_NPL npl;
if (_players.TryGetValue(car.PLID, out npl))
{
int idx = 0;
idx = ConnByPLID(car.PLID);
var Conn = Connections[idx];
Conn.Car = car; // Varies the variable with the whole structure instead of varying each variable in the structure.
MCI_Update(car.PLID); // Updates some information
}
}
DarkTimes
27th December 2010, 14:38
Where is the NullReferenceException being thrown in your code? That's where the actual problem is, all this stuff about CompCar is just getting in the way. You said in your first post:
When trying to put info from MCI onto this, I get the usual "Object reference not set to an instance of an object" error... so then I tried this:
It sounds to me like this is the actual problem we need to solve. I'm sorry, but I need to see more code. I'm not trying to be funny, but I do really believe that you're making the solution to this more complicated that it needs to be. :)
PoVo
27th December 2010, 14:45
Where is the NullReferenceException being thrown in your code? That's where the actual problem is, all this stuff about CompCar is just getting in the way. You said in your first post:
It sounds to me like this is the actual problem we need to solve. I'm sorry, but I need to see more code. I'm not trying to be funny, but I do really believe that you're making the solution to this more complicated that it needs to be. :)
The error was thrown at the line:
Conn.CompCar.Speed = car.Speed;
or any other line like :
Conn.CompCar.AngVel = car.AngVel;
So the fault was that "public CompCar CompCar;" wasn't referenced.
DarkTimes
27th December 2010, 15:04
OK here is a quick example I've written that shows saving the CompCar object in a connection object. It's a simple app that prints out the users location when the type the command '!location'.
using System;
using System.Collections.Generic;
using Spark;
using Spark.Helpers;
using Spark.Packets;
namespace ConsoleApplication4
{
class Program
{
// Class to store connection info.
class Connection
{
public CompCar Car { get; set; }
}
static Dictionary<int, IS_NPL> players = new Dictionary<int, IS_NPL>();
static Dictionary<int, Connection> connections = new Dictionary<int, Connection>();
static void Main(string[] args)
{
using (InSim insim = new InSim())
{
insim.Bind<IS_ISM>(InSimMulti);
insim.Bind<IS_NCN>(NewConnection);
insim.Bind<IS_NPL>(NewPlayer);
insim.Bind<IS_MCI>(MultiCarInfo);
insim.Bind<IS_MSO>(MessageOut);
// Connect to InSim.
insim.Connect("127.0.0.1", 29999);
insim.Send(new IS_ISI
{
Prefix = '!',
Interval = 1000,
Flags = InSimFlags.ISF_MCI,
});
// Request host packet.
insim.Send(new IS_TINY { ReqI = 1, SubT = TinyType.TINY_ISM });
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
static void InSimMulti(InSim insim, IS_ISM ism)
{
// Whenever we connect to a host request the player and connection lists.
insim.Send(new IS_TINY { ReqI = 1, SubT = TinyType.TINY_NCN });
insim.Send(new IS_TINY { ReqI = 1, SubT = TinyType.TINY_NPL });
}
static void NewPlayer(InSim insim, IS_NPL npl)
{
// Add new player.
players[npl.PLID] = npl;
}
static void NewConnection(InSim insim, IS_NCN ncn)
{
// Add new connection.
connections[ncn.UCID] = new Connection();
}
static void MultiCarInfo(InSim insim, IS_MCI mci)
{
foreach (CompCar car in mci.CompCars)
{
IS_NPL npl;
Connection conn;
if (players.TryGetValue(car.PLID, out npl) &&
connections.TryGetValue(npl.UCID, out conn))
{
// Update car on connection.
conn.Car = car;
}
}
}
static void MessageOut(InSim insim, IS_MSO mso)
{
if (mso.UserType == UserType.MSO_PREFIX)
{
// Parse command.
string args = mso.Msg.Substring(mso.TextStart);
if (args.Equals("!location", StringComparison.InvariantCultureIgnoreCase))
{
Connection conn = connections[mso.UCID];
// Check we have received a compcar for this connection yet.
if (conn.Car != null)
{
// Send location message.
string message = String.Format(
"X: {0:F2} Y: {1:F2} Z: {2:F2}",
MathHelper.LengthToMeters(conn.Car.X),
MathHelper.LengthToMeters(conn.Car.Y),
MathHelper.LengthToMeters(conn.Car.Z));
insim.Send(message, mso.UCID);
}
}
}
}
}
}
broken
27th December 2010, 16:47
[post above]
Isn't this the same thing I did? :razz:
Just copy the whole CompCar, and not the values one by one. <-- Think that's the problem(or ..solution), since the errors are thrown on these specific lines. :tilt:
PoVo
27th December 2010, 17:26
Isn't this the same thing I did? :razz:
Just copy the whole CompCar, and not the values one by one. <-- Think that's the problem(or ..solution), since the errors are thrown on these specific lines. :tilt:
Basically yes, the same thing as my solution is used on the Example.
DarkTimes
31st December 2010, 16:01
Basically yes, the same thing as my solution is used on the Example.
The purpose of my example was to show that what you are trying to do is possible without making the constructor for CompCar public. If you really wanna make CompCar constructable then you can edit the CompCar.cs class to add a blank public constructor and recompile the library.
But as I showed in my example you don't need to do this to be able to store a reference to the CompCar for access later, it currently works as it is. :)
Edit: The reason that CompCar has an internal constructor instead of a public one is because it requires a parameter that's an internal data-structure called PacketReader, which is not available outside of the assembly (for complicated reasons). At the time it was written I considered providing an alternative public constructor, but realized that if you are trying to create an instance of CompCar then either you are doing something wrong or something the library was never designed to do (in which case the library should be redesigned). The reason that you don't need to worry about constructors when using LFS_External is because all packets in that library are structs and not classes, so automatically provide default constructors like all value-types. However the reason that all packets are structs in LFS_External is an implementation detail and was not made because of a design decision.
DarkTimes
8th January 2011, 20:20
I have released InSim.NET 2.0.0 Beta to CodePlex project site. The download link can be found here:
http://insimdotnet.codeplex.com/releases/
Features in this release
Full InSim, InSim Relay, OutSim and OutGauge support
Better support for .NET languages other than C#
Improvements to string encoding/decoding
General API improvements
Mercurial source control repository
Changes
There are quite a few changes in this release, although most stuff will be familiar to people who have used to library before. There are too many changes to recount from the top of my head but I'll try to give the bullet-points.
InSim
Firstly the biggest change you'll notice is that you now initialize the InSim connection differently. To initialize the connection you now use the new InSim.Initialize(InSimSettings) method. Like so:
using System;
using InSimDotNet;
class Program
{
static void Main()
{
// Create new InSim object.
using (InSim insim = new InSim())
{
// Initialize InSim.
insim.Initialize(new InSimSettings
{
Host = "127.0.0.1",
Port = 29999,
Admin = String.Empty,
});
// Send message 'Hello, InSim!' to the game chat.
insim.Send("/msg Hello, InSim!");
// Stop program from exiting.
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
}
Also the way in which you bind packets has changed slightly, as you now must always specify a InSim parameter on the packet handler. Like this:
using System;
using InSimDotNet;
using InSimDotNet.Packets;
class Program
{
static void Main()
{
using (InSim insim = new InSim())
{
// Bind packet handler.
insim.Bind<IS_MSO>(MessageOut);
insim.Initialize(new InSimSettings
{
Host = "127.0.0.1",
Port = 29999,
Admin = String.Empty,
});
// Stop program from exiting.
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
// Packet handler now must specify a InSim parameter.
static void MessageOut(InSim insim, IS_MSO mso)
{
Console.WriteLine(mso.Msg);
}
}
With the changes to the way you initialize InSim, you can now specify a separate UDP port for MCI and NLP updates.
using System;
using InSimDotNet;
using InSimDotNet.Packets;
class Program
{
static void Main()
{
using (InSim insim = new InSim())
{
insim.Bind<IS_MCI>(MultiCarInfo);
insim.Initialize(new InSimSettings
{
Host = "127.0.0.1",
Port = 29999,
Admin = String.Empty,
UdpPort = 30000, // Specify UDP port
Interval = 1000, // Update interval (milliseconds)
Flags = InSimFlags.ISF_MCI, // Enable MCI updates
});
// Stop program from exiting.
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
// Handle MCI packet.
static void MultiCarInfo(InSim insim, IS_MCI mci)
{
foreach (CompCar car in mci.Info)
{
// Do something with CompCar.
}
}
}
InSim Relay
InSim relay works exactly as before, except now you initialize it by setting the InSimSettings.IsRelayHost property to true.
using System;
using InSimDotNet;
class Program
{
static void Main()
{
using (InSim insim = new InSim())
{
insim.Initialize(new InSimSettings
{
IsRelayHost = true, // Initialize InSim Relay.
});
// Stop program from exiting.
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
}
When IsRelayHost is set all other settings are ignored.
OutGauge and OutSim
There is now full OutSim and OutGauge support. Here is an example of using OutSim.
using System;
using InSimDotNet.Out;
class Program
{
static void Main()
{
// Create new OutSim object.
using (OutSim outsim = new OutSim())
{
// Bind OutSim packet event.
outsim.PacketReceived += new EventHandler<OutSimEventArgs>(outsim_PacketReceived);
// Start listening for packets sent from LFS.
outsim.Connect("127.0.0.1", 30000);
// Stop program from exiting.
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
static void outsim_PacketReceived(object sender, OutSimEventArgs e)
{
// Do something with packet.
OutSimPack packet = e.Packet;
}
}
Download
You can download the InSim.NET 2.0.0 Beta from CodePlex (http://insimdotnet.codeplex.com/releases/view/58810) right now!
DarkTimes
8th January 2011, 20:26
As you'll notice the old InSim.Run() method has been removed, as it was just confusing to most people. You now need to keep the application open yourself, which there are several ways to handle.
Firstly you can do it simply, like in my examples above.
Console.WriteLine("Press any key to exit...");
// Block until the user presses a key.
Console.ReadKey(true);
With this method it's easy to close the application by mistake, so it would be better to use a specific key combination. Here's an example of how you would do that.
Console.WriteLine("Press Ctrl+Z to exit...");
// Poll for the correct key combination.
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
}
while (!key.Modifiers.HasFlag(ConsoleModifiers.Control) && key.Key != ConsoleKey.Z);
Alternatively you can have the program stay open until the connection with LFS has been closed.
while (insim.IsConnected)
{
Thread.Sleep(200);
}
Of course if you're using the library from a GUI application then the program will stay open automatically.
DarkTimes
8th January 2011, 20:41
I've also created a simple help file with the documentation, that you can download separably. It's not perfect, a couple of small things are missing, but it works reasonably well.
Edit: help file removed, it is now a part of the official download.
DarkTimes
11th January 2011, 18:08
Here is an example that shows InSim.NET (http://www.lfsforum.net/showthread.php?p=1540683#post1540683) (Spark 2) running under IronPython. It's just a simple example that shows maintaining the connection list.
import clr
clr.AddReference('System')
clr.AddReference('InSimDotNet')
from System import *
from InSimDotNet import *
from InSimDotNet.Packets import *
connections = {}
def NewConnection(insim, ncn):
connections[ncn.UCID] = ncn
print 'Added connection: %s (%d)' % (ncn.UName, ncn.UCID)
def ConnectionLeft(insim, cnl):
del connections[cnl.UCID]
print 'Connection left: %d' % cnl.UCID
try:
# Create new InSim object.
with InSim() as insim:
# Bind packet-handlers.
insim.Bind(PacketType.ISP_NCN, NewConnection)
insim.Bind(PacketType.ISP_CNL, ConnectionLeft)
# Initialize InSim.
settings = InSimSettings()
settings.Host = '127.0.0.1'
settings.Port = 29999
settings.Admin = ''
insim.Initialize(settings)
# Request connections to be sent.
tiny = IS_TINY()
tiny.ReqI = 1
tiny.SubT = TinyType.TINY_NCN
insim.Send(tiny)
# Stop program from closing.
Console.WriteLine('Press any key to exit...')
Console.ReadKey(True)
except Exception as ex:
print 'InSim Error: %s' % ex
PoVo
20th January 2011, 07:20
One thing I've noticed with 2.0 Spark is that I'm unable to create buttons with Text containing 200+ characters :( Is this a bug or some kind of a limit by you? :(
broken
30th January 2011, 17:37
Is there any reason for the NCN.UCID to be an integer? If not, then.. this is a bug? :razz:
Victor
30th January 2011, 17:41
As far as I can tell, in .NET pretty much every publically accessible property is int (instead of sbyte / short / etc). I think Darktimes is just trying to get on par with such .NET regulations.
It's just like how every decimal value in .NET is a double and you won't see float.
broken
30th January 2011, 18:10
Thanks.
Needed to know if I have to make my functions compatible with that change. :)
(And now I do, obviously.)
broken
6th February 2011, 21:03
Sorry for double-posting.
I wanted to report a possible bug - I tried to connect to a server, which has a nice and strong password, but I couldn't. I re-checked my settings more than a few times, connected to other servers, connected other insim apps to the problematic server. Everything worked. Could the reason for this be the special symbols in the password? I'm going to do some testing locally and update this post if I find out if that's it, and if yes - which char exactly is causing it.
Oh yes, also - I did connect to another LFS server on the same machine(same IP), and it worked flawlessly (different password, obviously :razz:).
[E] So far, I found out that "?", "*", "<", ">", ":", "" (double quote)", "\" and "/" are causing problems.
Passwords "lol!@#$%^&", "lol[]{},." worked without a problem.
Also, symbols ";", "' (single quote)" don't seem to cause any problems.
** Double quote and backslash were properly escaped during the tests (\" , \\).
PoVo
27th February 2011, 20:48
Any progress with this library? Long time we haven't heard from you DarkTimes :)
Dygear
28th February 2011, 01:31
Any progress with this library? Long time we haven't heard from you DarkTimes :)
The last message from him was deleted on 12th February 2011 @ 15:08, by himself.
DarkTimes
28th February 2011, 11:58
Hey, sorry for not posting for a while.
I uploaded a new version of the library with some changes I made a while ago but didn't get around to uploading. I think I may have fixed the bugs with the string encoding.
DarkTimes
6th March 2011, 15:43
So, has anyone had a chance to try those changes I made? I think it should be working OK, but don't want to declare it so until povo and broken have signed off on it (as it was their bugs I was fixing).
broken
6th March 2011, 19:23
Sorry, I haven't had time for any off-work programming lately. I'll let you know as soon as I do test them though. :)
broken
7th March 2011, 21:20
Ok, the admin pass seems to be perfectly fine.
But I have 2 more reports:
1. The color codes I send to LFS, are being shown as text. I send ^1red, and I get a normal, green ^1red.
2 (better version of that explanation is available below). I might join povo's club about the button length. At some random points, my Queue thing (in case you are wondering, yes, Queue thing is how I like to call it :razz:) shoots out random errors when sending a button. At first I thought that was happening, because of my poorly-tested loop (which deletes buttons from a list after it hands them over to insim.net). But now, I suspect it's because of the length of the text on that button. There's this button of them all, that shows a typical car list (cruise insim style, because it's a cruise insim). And when I surrounded the Send code in a try expression(if it's an expression, if it's not I'm looking stupid, and I'm happy someone can have a laugh at my bs ;d) - that very same button was the only one that didn't show on the screen. (I'm going to need to rewrite that... All done, there it is - below!)
BETTER VERSION of 2: I am suspicious that buttons with long text sometimes don't get sent. I receive this when that happens:
Message: Index was outside the bounds of the array.
Source: InSimDotNet
StackTrace: at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 index, Int32 count)
at InSimDotNet.Packets.PacketWriter.Write(String value, Int32 length)
at InSimDotNet.Packets.IS_BTN.Pack()
at InSimDotNet.InSim.Send(ISendable packet)
at Dizplay_Cruise.Button.Processor.QueueProcessor_Ela psed(Object source, ElapsedEventArgs e) in D:\Loran\Programming\C#\Live for Speed\Dizplay\Cruise A.0.1\Dizplay Cruise\Dizplay Cruise\Button\Processor.cs:line 35
at System.Timers.Timer.MyTimerCallback(Object state)
Ok, after actually reading, and not just scanning through all of the values of the error, it looks like there's a problem with the color codes' encoding, not the length. Maybe, because something evil happened to the '^' char, which could have something to do with the admin passwords being all OK? But... I'm guessing it's something you would have found out before even reading this, and I might just be wrong as well, so, whatever.
PS: Sorry for the messy post.
PoVo
8th March 2011, 06:40
1. The color codes I send to LFS, are being shown as text. I send ^1red, and I get a normal, green ^1red.
Same problem for me :shy:
skywatcher122
8th March 2011, 07:12
1. The color codes I send to LFS, are being shown as text. I send ^1red, and I get a normal, green ^1red.
me either I tried any solutions but it shows incorrectly :shrug:
E: when I use the car list to show on the button (yh its a string I'm creating it by using cruise insim) it seems the button won't show up or the packet stops working after the line is being read by the connection
janne79_1
9th March 2011, 08:42
Hi all insim makers ,
i know i m here new person but i try to make buttons which disabled when user speed is someting and i have looked all help but not that work?
is that too much asked someone show me example how that can do.
Thanks if someone wanna use time and help new coder.
PoVo
9th March 2011, 12:34
Car Updates
The library also supports MCI updates, without the need for any hacks :). Here we check the speed of each player on track and spectate anyone who goes above 80 Kph.
using System;
using System.Collections.Generic;
using Spark;
using Spark.Packets;
using Spark.Helpers;
namespace Spark.Example5
{
class Program
{
static InSim _insim;
// We store the players in a dictionary.
static Dictionary<int, IS_NPL> _players = new Dictionary<int, IS_NPL>();
static void Main()
{
// Create new InSim object.
using (_insim = new InSim())
{
// Bind handlers.
_insim.Bind<IS_ISM>(MultiPlayerInfo);
_insim.Bind<IS_NPL>(NewPlayer);
_insim.Bind<IS_PLL>(PlayerLeft);
_insim.Bind<IS_MCI>(MultiCarInfo);
// Establish the InSim connection.
_insim.Connect("127.0.0.1", 29999);
// Initialize InSim.
_insim.Send(new IS_ISI { IName = "^3Example", Flags = InSimFlags.ISF_MCI, Interval = 500, Admin = string.Empty });
// Request for multiplayer info packet to be sent.
_insim.Send(new IS_TINY { SubT = TinyType.TINY_ISM, ReqI = 255 });
// Prevent program from exiting.
_insim.Run();
}
}
static void MultiPlayerInfo(IS_ISM ism)
{
// When joining multiplayer request for all connections and players to be sent.
_insim.Send(new IS_TINY { SubT = TinyType.TINY_NCN, ReqI = 255 });
_insim.Send(new IS_TINY { SubT = TinyType.TINY_NPL, ReqI = 255 });
}
static void NewPlayer(IS_NPL npl)
{
if (_players.ContainsKey(npl.PLID))
{
// Leaving pits, just update NPL object.
_players[npl.PLID] = npl;
}
else
{
// Add new player.
_players.Add(npl.PLID, npl);
}
}
static void PlayerLeft(IS_PLL pll)
{
// Remove player.
_players.Remove(pll.PLID);
}
static void MultiCarInfo(IS_MCI mci)
{
// Loop through each car on track.
foreach (var car in mci.CompCars)
{
// Get the player driving this car.
IS_NPL npl;
if (_players.TryGetValue(car.PLID, out npl))
{
// Check cars speed.
var kph = MathHelper.SpeedToKph(car.Speed);
if (kph > 80)
{
// Spectate player and send chat message.
_insim.Send("/spec {0}", npl.PName);
_insim.Send("{0} ^3spectated for speeding", npl.PName);
}
}
}
}
}
}
Use this code from DarkTimes. Where it says "// Spectate player and send chat message." output the "kph" variable on a button. :)
janne79_1
9th March 2011, 15:25
Oh thanks Povo. offcourse that make tricks thx , but i realy need help with this command IS_BFN
my problem is i can make that button when example speed is over 20 but i cant get that off when speed is lower than 20
ps i user spark 1.0.10 version this moment
if someone can give short example how i can remove buttons on screen pls.
DarkTimes
11th March 2011, 10:41
You need to send a BFN packet with a SubT of BFN_DEL_BTN to delete one button, or BFN_CLEAR to delete all of them.
// To delete one button.
insim.Send(new IS_BFN
{
SubT = ButtonFunction.BFN_DEL_BTN,
ClickID = 1, // ID of button to delete
UCID = 0, // User to delete the button for
});
// Delete them all
insim.Send(new IS_BFN
{
SubT = ButtonFunction.BFN_CLEAR,
UCID = 0, // User to delete the buttons for
});
DarkTimes
11th March 2011, 11:48
Ok, the admin pass seems to be perfectly fine.
But I have 2 more reports:
1. The color codes I send to LFS, are being shown as text. I send ^1red, and I get a normal, green ^1red.
2 (better version of that explanation is available below). I might join povo's club about the button length. At some random points, my Queue thing (in case you are wondering, yes, Queue thing is how I like to call it :razz:) shoots out random errors when sending a button. At first I thought that was happening, because of my poorly-tested loop (which deletes buttons from a list after it hands them over to insim.net). But now, I suspect it's because of the length of the text on that button. There's this button of them all, that shows a typical car list (cruise insim style, because it's a cruise insim). And when I surrounded the Send code in a try expression(if it's an expression, if it's not I'm looking stupid, and I'm happy someone can have a laugh at my bs ;d) - that very same button was the only one that didn't show on the screen. (I'm going to need to rewrite that... All done, there it is - below!)
BETTER VERSION of 2: I am suspicious that buttons with long text sometimes don't get sent. I receive this when that happens:
Message: Index was outside the bounds of the array.
Source: InSimDotNet
StackTrace: at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 index, Int32 count)
at InSimDotNet.Packets.PacketWriter.Write(String value, Int32 length)
at InSimDotNet.Packets.IS_BTN.Pack()
at InSimDotNet.InSim.Send(ISendable packet)
at Dizplay_Cruise.Button.Processor.QueueProcessor_Ela psed(Object source, ElapsedEventArgs e) in D:\Loran\Programming\C#\Live for Speed\Dizplay\Cruise A.0.1\Dizplay Cruise\Dizplay Cruise\Button\Processor.cs:line 35
at System.Timers.Timer.MyTimerCallback(Object state)
Ok, after actually reading, and not just scanning through all of the values of the error, it looks like there's a problem with the color codes' encoding, not the length. Maybe, because something evil happened to the '^' char, which could have something to do with the admin passwords being all OK? But... I'm guessing it's something you would have found out before even reading this, and I might just be wrong as well, so, whatever.
PS: Sorry for the messy post.
I've pushed a bug fix onto the repository (not ready to make a release) with a small fix for the color codes. It would be helpful if you could actually post an example of a button that doesn't get sent, as I'm not sure exactly what the problem is. The fix I've made should help things.
You can download the latest changeset from the repository.
http://insimdotnet.codeplex.com/SourceControl/list/changesets
janne79_1
11th March 2011, 16:35
thanks darktimes that work , and btw big big big thanks to make so nice library like this , this make insim making so easy.
mcgas001
11th March 2011, 18:14
Nice to see your still keeping things going for LFS, DarkTimes! :)
janne79_1
12th March 2011, 08:13
oh well , i learned much and now i can remove buttons too , next problem is how i can make button where is inside other buttons?
or i m total lost how i can make some sort list example players in server and all of them are own buttons?
So sorry for asking maybe stupid questions but i realy wanna learn make imsim stuff and best way how im learn try and try and try , but sometimes im out of ideas ;)
so if there is some nice ppl who can throw me with code
im so happy then
DarkTimes
12th March 2011, 15:22
OK, I think I've fixed the bug with the BTN text. What was happening is the BTN code wasn't correctly taking into account the NULL terminator when figuring out the length of the string. Because there was no NULL terminator LFS was discarding the string and not showing it, which is why some buttons appeared to not be sent.
I've uploaded a new release (http://insimdotnet.codeplex.com/releases/) of the BETA to CodePlex.
Note: Entertainingly this fix required the change of only a single-character in the source code, changing a 2 to a 3.
PoVo
12th March 2011, 15:36
Great work! Will test the 220 character button in a few mins. :thumbsup:
Edit: Long character buttons finally work!
One thing that doesn't work is, sending a button with no Text in it. e.g Text = "" or not declaring the Text at all, throws an exception:
System.ArgumentOutOfRangeException: Length cannot be less than zero.
Parameter name: length
at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length, Boolean fAlwaysCopy)
at System.String.Substring(Int32 startIndex, Int32 length)
at InSimDotNet.Packets.PacketWriter.Write(String value, Int32 length)
at InSimDotNet.Packets.IS_BTN.Pack()
at InSimDotNet.InSim.Send(ISendable packet)
at DriftProject.Button.Control.NewButton(Vars Conn, Int32 currentID, IS_BTN Button) in G:\Users\Povilas\documents\visual studio 2010\Projects\DriftProject\DriftProject\Button\Con trol.cs:line 20
at DriftProject.Packets.MCI.Update(Vars Conn) in G:\Users\Povilas\documents\visual studio 2010\Projects\DriftProject\DriftProject\Packets\MC I.cs:line 50
Setting the Text to " " (A simple space) solves the problem. Not much of a big deal, but it worked before :)
DarkTimes
12th March 2011, 15:53
OK, thanks - I've uploaded a fixed version to CodePlex.
http://insimdotnet.codeplex.com/releases/view/62453
PoVo
12th March 2011, 16:00
Working perfect :razz:
broken
12th March 2011, 17:00
Confirmed. :tilt:
Text colors are working flawlessly, and so are the buttons. No matter with long/normal or without any text.
Also, sorry for the late reply. If for whatever reason you still need the text of the (what used to be a) problematic button, there it is:
UF1 XFG ^7XRG LX4 LX6 RB4 ^8FXO XRT ^7RAC ^8VWS FZ5 ^7UFR XFR FXR XRR FZR ^8MRT
skywatcher122
13th March 2011, 07:05
thanks the long button character strings is now supported ;)
DarkTimes
13th March 2011, 12:38
OK - good to hear it's working OK. What you all won't be glad to hear is that I've just completely rewritten all the string encoding code! Yay, more bugs! :D
I suddenly had a brainwave about how to implement full string encoding support and it seems to be working well. I've pushed the changes onto the repository, but I'll hold back on pushing out a release until I've made sure it's all working OK.
The new string encoding now correctly handles all LFS codepages, including single-byte and double-byte character sets, which means full Japanese, Korean, Simplified Chinese and Traditional Chinese support. I had talked about this before, but in the version of the library I release I only included support for single-byte character sets. Obviously that sort of thing is not good enough.
In my previous attempts to write this code I had been performing the lookup myself (with giant hash tables), which was proving problematic, but I'm now p/invoking the WideCharToMultiByte function in kernel32.dll, which seems to provide a simple and fast lookup for the various encodings. It is slightly slower than the old string encoding, but we're still talking about fractions of a millisecond for even complex strings.
I'd appreciate it if anyone would be willing to pull the latest revision from the repository and report back if it's working OK.
PoVo
13th March 2011, 13:50
Well, I've downloaded the latest Source from repository. If any thing wrong pops up, I'll let you know.
Continue the speedy work :nod:
janne79_1
16th March 2011, 11:38
well i have learning more that c# plus insim stuff and i learn much ;)
but now i have stucked and if someone can help me somehow i m so glad
how i can list server players in buttons , ofcourse i can make that manual but i hope there is some trick that program look howmany players is online and if there is example 5 ppl online insim make 5 button in screen where is they usernames?
im glaad if i get any tip how to do that , and yeah im total noob in programming stuff but i realy wanna learn make good insim stuff
broken
16th March 2011, 11:55
well i have learning more that c# plus insim stuff and i learn much ;)
but now i have stucked and if someone can help me somehow i m so glad
how i can list server players in buttons , ofcourse i can make that manual but i hope there is some trick that program look howmany players is online and if there is example 5 ppl online insim make 5 button in screen where is they usernames?
im glaad if i get any tip how to do that , and yeah im total noob in programming stuff but i realy wanna learn make good insim stuff
That's not really the place to ask. But anyway.
First of all, you would need a list, or an array, or any other type of variable(or.. simply said - holder), with similar functionality. I am not aware of all the possibilities, tbh.
Then, you simply iterate(loop(do a for/foreach)) through that holder, and in that loop you simply send a button. It will be a good thing to declare a variable before the loop, which you will increase, so that each button you send, does not overlap the previous one. Also, ClickIds do not have to be the same, or the button will be overwritten on the screen.
DarkTimes
29th March 2011, 22:30
Pushed a few more changes to the repository (http://insimdotnet.codeplex.com/SourceControl/list/changesets), although not made a proper release yet.
Breaking Change:
As it's still a beta I've introduced a breaking-change, namely that you now send messages to InSim a bit differently. I really missed the old style of sending formatted messages, so I've reverted it back to the InSim.Send(string, params object[]) method of old.
// Send message
insim.Send("Hello!");
// Send formatted message
insim.Send("Hello, {0}", name);
// Send message to specific connection
insim.Send(ucid, "Hello!");
// Send formatted message to specific connection
insim.Send(ucid, "Hello, {0}", name);
// Send message to specific connection or player
insim.Send(ucid, plid, "Hello!";
// Send formatted message to specific connection or player
insim.Send(ucid, plid, "Hello, {0}", name);
// etc.. etc..
Here is a most general list of changes in the repository.
Changes
Can now set your own IPacketFactory and ISocket on the InSim class again, if you need to implement your own packet code (this is kinda advanced stuff, but very useful)
Improved and optimized the string handling code (yay more fun!)
Improved InSim.Send(IEnumerable<ISendable>) method, which allows you to batch send packets for improved performance (useful if you need to send lots of buttons or messages in one go) (see below)
Rewrote BindingCollection, making it cleaner and faster (although not something most people will notice)
Can now save/load InSimSettings (see below)
Fixed a few really big bugs in OutSim and OutGauge code.
To save the InSimSettings:
InSimSettings settings = new InSimSettings {
Host = "127.0.0.1",
Port = 29999,
Admin = "Whatever",
};
// Save to XML
InSimSettings.Save(settings, "mySettings.xml");
// Load from XML
InSimSettings settings = InSimSettings.Load("mySettings.xml");
// The InSimSettings are saved and loaded from disk using the
// XmlSerializer class, which is simple but effective.
To batch send packets (for extra network performance):
insim.Send(new List<ISendable> {
new IS_MST { Msg = "Hello" },
new IS_MST { Msg = "World" },
new IS_MST { Msg = "How" },
new IS_MST { Msg = "Are" },
new IS_MST { Msg = "You?" },
});
// All these packets get sent in a single call, instead of five
// separate calls, improving network throughput.
It is almost finished now, I only have a couple of small changes left to consider before I release InSim.NET 2.0 final. As always I invite and encourage people to pull the latest revision from CodePlex and let me known of any issues before I push it out to the world.
DarkTimes
29th March 2011, 23:50
As mentioned previously you can now set your own IPacketFactory, which allows you to reimplement the way packet are built.
public class CustomPacketFactory : IPacketFactory {
public IPacket BuildPacket(byte[] buffer) {
// Implement your own packet handling code here. You can
// create your own packets or do whatever you need to,
// so long as your new packet inherits from IPacket.
return null;
}
}
InSim insim = new InSim();
// Set your custom packet factory
insim.PacketFactory = new CustomPacketFactory();
// Exists here normal InSim.NET code...
DarkTimes
30th March 2011, 00:14
If you need to you can completely reimplement the socket code, by implementing ISocket on your own custom class.
public class CustomSocket : ISocket{
// Custom implementation of ISocket.
}
InSim insim = new InSim();
// Set your custom socket.
insim.Socket = new CustomSocket();
// Whatever...
Your custom socket could read InSim data from a file, or from a Windows Service, if you so choose. You can create any source you like, so long as you inherit from ISocket. This is one of the many things that make InSim.NET very flexible, as although it's designed to work with zero configuration, it's also designed to let you reimplement stuff that's important to your app.
Maybe you need to access the raw byte data from InSim? InSim.NET lets you do that...
InSim insim = new InSim();
// You have complete access to underlying socket.
insim.Socket.PacketDataReceived += insim_PacketDataReceived;
private void insim_PacketDataReceived(object sender, PacketDataEventArgs e) {
// Now you have raw byte data...
byte[] data = e.GetData();
}
Or maybe you'd like to ignore InSim.NET and go straight to the TCP socket itself?
// You can access the underlying socket without the InSim abstraction
TcpSocket sock = new TcpSocket();
// It handles the TCP receive stream for you, basically makes TCP act like UDP...
sock.PacketDataReceived += insim_PacketDataReceived;
// You can create a connection.
sock.Connect("127.0.0.1", 29999);
// And send raw packets...
sock.Send(new IS_ISI {
Admin = String.Empty;
IName = "Test!",
}.Pack());
private void insim_PacketDataReceived(object sender, PacketDataEventArgs e) {
// And handle them however you like...
byte[] data = e.GetData();
}
This should give you an idea of just how flexible InSim.NET is.
PoVo
30th March 2011, 06:18
Good work! :razz:
DarkTimes
1st April 2011, 15:54
Uploaded 2.0.4 Beta to CodePlex (http://insimdotnet.codeplex.com/releases/view/63633), this is one of the very, very last betas, honestly. As soon as I've finished the documentation it will go final.
Changes in this release
Support for double-byte character sets, for Japanese, Traditional Chinese, Simplified Chinese and Korean strings.
Fixed several bugs in OutGauge and OutSim support, plus cleaned up and improved reliability of the UDP timeout.
Can now save/load InSimSettings to/from XML (handy for implementing a quick config file)
Improved performance and reliability of packet binding (also improved packet binding for languages that do not support generics, like IronPython)
Added InSim.Send(IEnumerable<ISendable>) method that allows you to batch send packets (for improved network performance when sending lots of packets)
Improvements to PacketFactory, that now much better allows you to implement and configure your own packet-handling code
Changed the way InSim.NET handles CLS (Common Language Specification) compatibility, this means the return of bytes and short etc for many packets
Completely tweaked and improved documentation (fixed lots of typos and cleared up grammar)
Lots of small tweaks to packets to remove some oddities and generally cleanup the API
Lots, lots more!
DarkTimes
1st April 2011, 21:39
I've started typing up the documentation for this, but it's still a work in progress. If someone would like something explained, or thinks something should be in the (In)FAQ, then give us a shout.
You can view the documentation as a work in progress here: http://insimdotnet.codeplex.com/documentation
Dygear
2nd April 2011, 07:03
I really wish you would just go ahead and learn PHP, and then help with PRISM :). As always, great job.
PoVo
2nd April 2011, 15:03
I really wish you would just go ahead and learn PHP, and then help with PRISM :). As always, great job.
That means forcing many other people to learn PHP too :(:D
DarkTimes
2nd April 2011, 15:39
I really wish you would just go ahead and learn PHP, and then help with PRISM :). As always, great job.
Technically I do know PHP, I'm just really bad at it. PHP was one of the first languages I ever learnt, but I can't really remember much about it.
Dygear
3rd April 2011, 08:52
Technically I do know PHP, I'm just really bad at it. PHP was one of the first languages I ever learnt, but I can't really remember much about it.
Once you learn one programming language, you know them all really. Except ASM, because that's some odd stuff right there.
DarkTimes
7th April 2011, 19:01
I released the final version of InSim.NET 2.0 to CodePlex.
It's finished, more or less.
http://insimdotnet.codeplex.com/
I also updated the first page of this thread and changed the title.
Fin.
DarkTimes
7th April 2011, 21:15
Once you learn one programming language, you know them all really. Except ASM, because that's some odd stuff right there.
Well, this is certainly true for the C-family of languages, such a *PHP, Java, and C# (even Ruby), but not so much for functional programming languages, such as a Lisp and Haskell. The functional languages do require you to think is a new and different way about your code, especially if you've been stuck in the C-world for a long time. It's an eye opening experience to go code a bunch of Haskell for a while... and also worthwhile doing.
It is a mistake a lot of novice programmers make to worry about which language they should learn, as opposed to which language they should learn first. Once you've learnt a programming language picking up others is normally just a case of doing a mental bit-shift to a different syntax. All the fundamental ideas that underlie them are the same.
* I should probably note that my issue with PHP is that it just doesn't make sense to me when I code it, it doesn't flow off my fingers the way C#, Python and *Ruby do. I find there are so many oddities, so many small things that interrupt my flow and make me scratch my head. I'm sure all that would go away if I had more (recent) practice at it. To me PHP just has no aesthetic, no vision and no consistency. It's the perfect example of a language designed by a committee that couldn't agree about anything. That being said, it is one of the most used programming languages ever, half the internet is built on it, so maybe I don't know what I'm talking about. :p
* Incidentally if I had half an impulse to write a new InSim library, Ruby would be a pretty sound bet. I don't though. :)
Dygear
8th April 2011, 00:53
Funny you should say that, I was thinking about learning Ruby. But I digress back to the topic at hand.
DarkTimes
9th April 2011, 14:55
Pushed a small release out with a few corrections, mainly the documentation. I remembered I hadn't updated the help-file generator for a while, so I got the latest version with a bunch of fixes. I also improved the documentation generally and fixed a bunch of typos. In addition I cleaned-up some of the source code to make it 3.78% less crap overall.
http://insimdotnet.codeplex.com/releases/
DarkTimes
15th April 2011, 18:52
Hello InSim in VB.NET
Imports InSimDotNet
Module InSimExample
Sub Main()
' Create InSim object
Dim insim As New InSim()
' Initialize InSim with specified settings
insim.Initialize(New InSimSettings() With {.Host = "127.0.0.1", .Port = 29999, .Admin = String.Empty})
' Send message to chat
insim.Send("/msg Hello, InSim!")
' Keep program open
Console.WriteLine("Press any key to exit...")
Console.ReadKey(True)
End Sub
End Module
Hello InSim in C++/CLI
#include "stdafx.h"
using namespace System;
using namespace InSimDotNet;
int main(array<String ^> ^args)
{
// Create InSim object
InSim ^insim = gcnew InSim();
// Initialize InSim
InSimSettings ^settings = gcnew InSimSettings();
settings->Host = L"127.0.0.1";
settings->Port = 29999;
settings->Admin = String::Empty;
insim->Initialize(settings);
// Send message to chat
insim->Send(L"/msg Hello, InSim!");
// Stop program from exiting...
Console::WriteLine(L"Press any key to exit...");
Console::ReadKey(true);
return 0;
}
Hello InSim in IronPython
import clr
clr.AddReference('System')
clr.AddReference('InSimDotNet')
from System import *
from InSimDotNet import *
# Create InSim object
insim = InSim()
# Initialize InSim
settings = InSimSettings()
settings.Host = '127.0.0.1'
settings.Port = 29999
settings.Admin = String.Empty
insim.Initialize(settings)
# Send message to chat
insim.Send('/msg Hello, InSim!')
# Stop program from exiting
Console.WriteLine('Press any key to exit...')
Console.ReadKey(True)
Hello InSim in C#
using System;
using InSimDotNet;
class Program {
static void Main() {
// Create InSim object
InSim insim = new InSim();
// Initialize InSim
insim.Initialize(new InSimSettings {
Host = "127.0.0.1",
Port = 29999,
Admin = String.Empty,
});
// Send message to chat
insim.Send("/msg Hello, InSim!");
// Stop program from exiting
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
}
}
Dygear
16th April 2011, 04:32
Ok, now your just showing off.
broken
16th April 2011, 15:45
Hahaha.. :D
Though, you would do the same, Dygear, wouldn't you? :razz:
DarkTimes
16th April 2011, 16:04
Well, I wrote them for myself because I wanted to get an idea of how InSim.NET would look in the different .NET languages, so I figured I'd just post it. I thought it was quite interesting, although examples that showed receiving packets would probably be better, as that's where the languages seem to diverge the most.
Just to note that I haven't done IronRuby or F#, mainly because IronRuby has stopped working with VS2010 SP1 :( and I don't really understand F# yet.
PoVo
22nd April 2011, 20:23
Waiting for Z30 update of this library. :Looking_a
DarkTimes
22nd April 2011, 20:29
I've uploaded a new version for InSim 5 to the repository, but I haven't been able to test it yet. My graphics card is broken and these onboard graphics struggle to run Solitaire (seriously), so running LFS is a bit of a pain. I'll see what I can do tomorrow.
Feel free to try it and report any bugs in the meantime and I'll see what I can do (I also accept patches of course).
Note: the update is in the repository (http://insimdotnet.codeplex.com/SourceControl/list/changesets), there is no release yet.
PoVo
22nd April 2011, 20:43
Not sure what's wrong, but using the updated or the old library gives me this:
Apr 22 21:39:41 InSim - TCP : [LsC]
Apr 22 21:39:41 InSim guest closed : [LsC]
EDIT: I'm retarded, don't mind this post.
EDIT2: The new library update works perfect on LsC! Thanks DarkTimes for the quickest library update on LFS!
DarkTimes
23rd April 2011, 08:41
I pushed a new changeset onto CodePlex (http://insimdotnet.codeplex.com/SourceControl/list/changesets)with some fixes for the IS_CON support, it should now work correctly. I also just removed the version check for now, so this version should work with InSim 4 and 5.
PoVo
23rd April 2011, 08:47
Just a strange thing I've noticed: When there's more than 6~ players in the servers, it seems that the BTT packet is giving me wrong things.
I use it for a Send Cash function, and the text coming through is blank I think... E.G I enter "123", then I use the "Convert.ToInt32(BTT.Text);" and it returns me a "0".
It may be my code after the library change, or it could be a bug in the library itself.
I will try and investigate it today, to see if I can make a conclusion on why that's happening.
EDIT: Another thing I've noticed is, "InSim.Send(Conn.UniqueID, "^6> ^7Test");" doesn't get sent to the connection. I'm pretty sure the code doesn't fail while performing it e.g no "catch" etc. I know this because I have a Unit changer in the app, and the units change, but the message doesn't show up.
EDIT2: I'm currently making a separate application to read the outputs of the BTT packet while there are many players real time on my server. Will post back results later...
DarkTimes
23rd April 2011, 09:40
I uploaded a changset with a fix for the MTC bug.
In terms of the BTT packet, it works fine for me, that packet hasn't changed as far as I'm aware. I don't understand why it would fail after 6 players are on the server and I don't have the ability to test that myself right now.
PoVo
23rd April 2011, 09:43
I take back my words. After making a new app with the BTT packet, it seems to work fine.
Sorry for any trouble.
Will test the MTC now.
EDIT: Yep, IS_MTC works perfectly now. Still not understanding what's causing my BTT problem, as I haven't changed the code. It works up to 14 people :D Ah the nightmares........ :D
DarkTimes
23rd April 2011, 11:07
Just a reminder that you can attach an event to InSim.InSimError to see if any background exceptions are being thrown. You can also look at the Debug > Windows > Output window, as background exceptions are dumped to the debug output as well (handy for copy/paste). The packet handlers are called from a background thread so any exceptions thrown in the packet events will only get picked up by InSimError, that is if you don't catch them yourself.
PoVo
23rd April 2011, 11:58
Found the problem... :D
The fault is some characters from LFS cannot be displayed on buttons, so that catches the code and the cash is converted after the buttons.
The following name doesn't work:
¦¨¦×ÂÆùÇÆÍß¡¶
http://img546.imageshack.us/img546/9655/chars.jpg
Hope you can fix it. If not, just replace the special chars with "?" :shrug:
Thanks.
DarkTimes
23rd April 2011, 12:06
What's the exception that gets thrown? Also does the error occur when receiving a string or sending a string?
PoVo
23rd April 2011, 12:35
What's the exception that gets thrown? Also does the error occur when receiving a string or sending a string?
It occurs when sending a string.
I will check the exception in 15 mins. On the phone now.
PoVo
23rd April 2011, 12:59
System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 index, Int32 length) in G:\Users\Povilas\Desktop\InSimDotNet\EncodingHelpe r.cs:line 94
at InSimDotNet.PacketWriter.Write(String value, Int32 length) in G:\Users\Povilas\Desktop\InSimDotNet\PacketWriter. cs:line 108
at InSimDotNet.Packets.IS_BTN.GetBuffer() in G:\Users\Povilas\Desktop\InSimDotNet\Packets\IS_BT N.cs:line 121
at InSimDotNet.InSim.Send(ISendable packet) in G:\Users\Povilas\Desktop\InSimDotNet\InSim.cs:line 231
at LsCruise.Processor.QueueButton(String Text, ButtonStyles ButtonStyles, Byte ClickID, Byte H, Byte W, Byte T, Byte L, Byte ReqI, Byte UCID) in G:\Users\Povilas\Desktop\Visual Studio 2010\RC_new\ConsoleApplication1\Processor.cs:line 26
at LsCruise.Program.bttHandler(InSim InSim, IS_BTT BTT) in G:\Users\Povilas\Desktop\Visual Studio 2010\RC_new\ConsoleApplication1\eventHandlers\bttH andler.cs:line 48
The error :)
DarkTimes
23rd April 2011, 13:03
Try this version and see if it works any better.
Edit: removed.
PoVo
23rd April 2011, 13:06
Try this version and see if it works any better.
System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
at System.Buffer.BlockCopy(Array src, Int32 srcOffset, Array dst, Int32 dstOffset, Int32 count)
at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 index, Int32 length) in G:\Users\Povilas\Desktop\InSimDotNet\EncodingHelpe r.cs:line 94
at InSimDotNet.PacketWriter.Write(String value, Int32 length) in G:\Users\Povilas\Desktop\InSimDotNet\PacketWriter. cs:line 108
at InSimDotNet.Packets.IS_BTN.GetBuffer() in G:\Users\Povilas\Desktop\InSimDotNet\Packets\IS_BT N.cs:line 121
at InSimDotNet.InSim.Send(ISendable packet) in G:\Users\Povilas\Desktop\InSimDotNet\InSim.cs:line 231
at LsCruise.Processor.QueueButton(String Text, ButtonStyles ButtonStyles, Byte ClickID, Byte H, Byte W, Byte T, Byte L, Byte ReqI, Byte UCID) in G:\Users\Povilas\Desktop\Visual Studio 2010\RC_new\ConsoleApplication1\Processor.cs:line 26
at LsCruise.Program.bttHandler(InSim InSim, IS_BTT BTT) in G:\Users\Povilas\Desktop\Visual Studio 2010\RC_new\ConsoleApplication1\eventHandlers\bttH andler.cs:line 48
DarkTimes
23rd April 2011, 13:13
Is the guy with this name on your server, or do you have a replay with his name in it? I can't seem to figure this out, I need some debug info (a replay would be ideal).
The place where this error occurs is not where I would expect, it seems likely to be the symptom of an error somewhere else, but to find that place I need more information.
PoVo
23rd April 2011, 13:51
I don't have a replay directly from the user, but I know the characters that cause the same error, so I recreated the error.
It involves an IS_PLP, IS_NPL, 2 IS_BTT's (second one is the one that catches), lots of IS_MSO's.
Hopefully it's enough :thumb:
Good luck.
DarkTimes
23rd April 2011, 13:59
Great thanks, that causes the bug for me. You don't need all those packets by the way, just hook up an MSO handler that sends any messages received back to LFS. :)
I'll look into the exact cause later. :)
DarkTimes
24th April 2011, 10:40
I've figured out where the bug is, but it will take me some time to fix it, I need to think about it for a while.
PoVo
24th April 2011, 11:24
Great! Good luck :)
Can't wait for the release :thumb: If you need any testing drop a PM, I'll be more than happy to contribute. :shy:
DarkTimes
24th April 2011, 12:24
OK - I've pushed some fixes onto CodePlex (http://insimdotnet.codeplex.com/SourceControl/list/changesets), you can pull the latest version from the repository.
The bug was caused because the size of the BTN packet was being determined before the string had been converted into bytes, which meant that any string where the number of bytes > number of characters would cause it to crash. Anyway, I've fixed it, I hope.
I also fixed the new MTC packet to make it variable sized, plus made a couple of tweaks to IS_CON.
broken
24th April 2011, 12:44
I am just having my insim running on my client, on a server that's not mine. And when I crashed into the person with the following nickname: "GaZ" (quotes included in nickname) , I get the following error:
Message: Index was outside the bounds of the array.
StackTrace: at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 index, Int32 length) in C:\Users\Loran\Desktop\Random\InSimDotNet\insimdot net_6b678d6ab605\InSimDotNet\EncodingHelper.cs:lin e 92
at InSimDotNet.PacketWriter.Write(String value, Int32 length) in C:\Users\Loran\Desktop\Random\InSimDotNet\insimdot net_6b678d6ab605\InSimDotNet\PacketWriter.cs:line 121
at InSimDotNet.Packets.IS_MST.GetBuffer() in C:\Users\Loran\Desktop\Random\InSimDotNet\insimdot net_6b678d6ab605\InSimDotNet\Packets\IS_MST.cs:lin e 50
at InSimDotNet.InSim.Send(ISendable packet) in C:\Users\Loran\Desktop\Random\InSimDotNet\insimdot net_6b678d6ab605\InSimDotNet\InSim.cs:line 231
at InSimDotNet.InSim.Send(String message, Object[] args) in C:\Users\Loran\Desktop\Random\InSimDotNet\insimdot net_6b678d6ab605\InSimDotNet\InSim.cs:line 265
at Dizplay_Cruise.Dizplay.iSendMsg(String Message) in D:\Loran\Programming\C#\Live for Speed\Dizplay\Cruise A.0.1\Dizplay Cruise\Dizplay Cruise\Dizplay.cs:line 240
at Dizplay_Cruise.Dizplay.Received_CON(InSim InSim, IS_CON CON) in D:\Loran\Programming\C#\Live for Speed\Dizplay\Cruise A.0.1\Dizplay Cruise\Dizplay Cruise\Dizplay.cs:line 553
Target: Int32 GetBytes(System.String, Byte[], Int32, Int32)
Line 553 in Dizplay.cs:
iSendMsg("^7Crash: " + A.NCN.PName + " ^7>< " + B.NCN.PName + " ^7(" + Speed + " km/h)");
iSendMsg in Dizplay.cs:
public static void iSendMsg(string Message)
{
InSim.Send(Globals.MS + Message); // This is line 240
}
Is that you or me? :razz:
Edit: It happened before and after I updated to that last update in the repository. But I couldn't copy the error from the previous version. Also, if needed, I could save the replay and send it to you. In fact I will save it now, you say if you want me to upload it here. :)
DarkTimes
24th April 2011, 12:54
OK send me the replay.
Edit: It works fine for me, so the bug must be somewhere else, so I need the replay.
private static void Collision(InSim insim, IS_CON con) {
IS_NPL a = _players[con.A.PLID];
IS_NPL b = _players[con.B.PLID];
double speed = MathHelper.MpsToKph((con.SpClose & 0x00ff) * 0.1);
insim.Send("^7Crash: " + a.PName + " ^7>< " + b.PName + " ^7(" + speed + " km/h)");
}
Also what does the Globals.MS string contain?
MariusMM
24th April 2011, 14:29
Ehh nvm, it somehow sorted itself..
broken
24th April 2011, 22:18
Awhh! Sorry, forgot to save the replay.. :doh:
I've been distracted the whole day today, couldn't do a thing normally..
Globals.MS is simply the server message start character, to make the messages from the InSim app differ from normal text..:
public static readonly string MS = "^3» ";
But IS_CON fails rarely. Also, it used to disconnect from the host, before I decided to catch the exceptions thrown from it. And just that - it disconnected, without crashing my app.
Sorry for being zero help, really, I don't know how I forgot to do that! Just.. stupid.. ;d
Anyway, I'll make sure to get a replay if/when it happens again.
DarkTimes
24th April 2011, 22:46
Awhh! Sorry, forgot to save the replay.. :doh:
I've been distracted the whole day today, couldn't do a thing normally..
Globals.MS is simply the server message start character, to make the messages from the InSim app differ from normal text..:
public static readonly string MS = "^3» ";
Sorry for being zero help, really, I don't know how I forgot to do that! Just.. stupid.. ;d
Anyway, I'll make sure to get a replay if/when it happens again.
What I need to know is the name of the two players. The error occurs in part of the code that converts a string into bytes, so I need to know what the string actually was to figure out what happened.
But IS_CON fails rarely. Also, it used to disconnect from the host, before I decided to catch the exceptions thrown from it. And just that - it disconnected, without crashing my app.
That's probably because the error is being thrown on the background thread, as I've said before you need to hook up an event to InSim.InSimError to catch those. Once an error is thrown InSim.NET can't really continue, can it, it doesn't know what state the program is in any more, so it disconnects.
broken
24th April 2011, 23:05
Ah, could be my nickname too, yes.. Didn't think about that.
My nickname is this: ¡¸THC¡áBroken¡¸, OR http://www.lfsforum.net/attachment.php?attachmentid=113671&stc=1&d=1303685868
I even made a quick log to give me the nickname and the base64 value of it. There it is, all from the app, originally:
^7☆THC﹥^3Broken^7☆
Base64 encoded: XjfimIZUSEPvuaVeM0Jyb2tlbl434piG
Edit: If I need to hook up an event to InSim.InSimError, wouldn't that mean going into multithreading? I'll try... But after I get some sleep, because it's totally not my day today! :D
DarkTimes
24th April 2011, 23:25
What's the name of the other player in the crash? I need to know both of them.
If I need to hook up an event to InSim.InSimError, wouldn't that mean going into multithreading?
Um, no, the library is already multithreaded. If an exception gets thrown on a background thread you have no way of knowing. It will unwind that threads callstack and stops execution, but as each thread has its own callstack this won't affect your main program thread. Because of this I added the InSim.InSimError event that allows you to catch exceptions on background threads. You should pretty much always catch and log any errors raised by InSimError.
broken
24th April 2011, 23:30
"GaZ" (quotes included in nickname). I said that in a previous reply, as I was reporting this tho, but nevermind. :tilt:
DarkTimes
25th April 2011, 09:55
Ah, I musta missed that, sorry. Anyway I've recreated the string and it does indeed cause a crash, but I have no effing idea why. I'm looking into it.
^3» ^7Crash: ^7☆THC﹥^3Broken^7☆ ^7>< ^tGaz^t ^7(0.00 km/h)
I should save all these strings and make some unit tests or something.
DarkTimes
25th April 2011, 10:14
OK I think I've fixed the bug. It was another issue with the string length. You can get the latest revision from CodePlex (http://insimdotnet.codeplex.com/SourceControl/list/changesets).
The string encoding seems a little fragile, I'm thinking I may need to do something more to improve its robustness.
Edit: another push to CodePlex, fixed small bug introduced with this bug fix.
broken
25th April 2011, 15:45
I think that fixed it. Will reply if things get odd again. :razz:
NeOn_sp
25th April 2011, 23:31
I have started to port my InSim app from LFSExternal, to this.
Great lib, :thumb:
I have a trouble, and I don´t know why.
Reading MSO packets, if I write in server "!top" ( without slashes )
mso.Msg contains: "Player_Name ( without colours ) : !top" ( without slashes )..
I´m using 7d364ad0ddce (http://insimdotnet.codeplex.com/SourceControl/changeset/changes/7d364ad0ddce) with Z30 host.
And another question, If I want to send a MTC, it fails if lenght(msg)%4==0, and to solve this I have to add \0 at msg end. Wouldn´t be easier checking this internally, and add if necessary \0 in the own lib?
DarkTimes
26th April 2011, 03:03
I have started to port my InSim app from LFSExternal, to this.
Great lib, :thumb:
I have a trouble, and I don´t know why.
Reading MSO packets, if I write in server "!top" ( without slashes )
mso.Msg contains: "Player_Name ( without colours ) : !top" ( without slashes )..
Sorry, I don't understand what the problem is. Maybe you could try to go into more detail? As far as I can see that's working correctly.
If you want to process commands, you need to first set the Prefix char in InSimSettings.
insim.Initialize(new InSimSettings { Prefix = '!' });
Then to process the command:
void MessageOut(InSim insim, IS_MSO mso) {
if (mso.UserType == UserType.MSO_PREFIX) {
string command = mso.Msg.Substring(mso.TextStart);
if (command == "!top") {
// Do something...
}
}
}
And another question, If I want to send a MTC, it fails if lenght(msg)%4==0, and to solve this I have to add \0 at msg end. Wouldn´t be easier checking this internally, and add if necessary \0 in the own lib?
Sorry, that is a bug that was added in the latest revision, I've reverted the change (http://insimdotnet.codeplex.com/SourceControl/list/changesets).
Obviously if you pull the latest revision you should expect some bugs.
NeOn_sp
26th April 2011, 09:59
The problem is that mso.Msg should contain just my msg "!top" instead of "nickname : !top"
PoVo
26th April 2011, 10:08
The problem is that mso.Msg should contain just my msg "!top" instead of "nickname : !top"
The problem is your code.
I use the latest version from CodePlex on my cruise server 24/7 and everything works fine.
NeOn_sp
26th April 2011, 10:17
The problem is your code.
I use the latest version from CodePlex on my cruise server 24/7 and everything works fine.
Lastest oficial version or last uploaded to source code? Anyway, I'll recheck later
Edit:
With this code:
static void MessageOut(InSim insim, IS_MSO mso)
{
try
{
if (mso.UCID != 0)
{
var npl = players[mso.PLID];
var nco = players_info[mso.UCID];
if (mso.UserType == UserType.MSO_PREFIX)
{
insim.Send("/msg MSG=" + mso.Msg);
I write: "!info " and I get: MSG=NeoN Xspa™ : !info
Edit2: Downloaded new revision 801736de8371, MTC working fine now, thanks :) Waiting for MSO thing..
DarkTimes
26th April 2011, 12:38
The MSO packet works correctly, you need to use the TextStart property to get where the text starts. This is not InSim.NET, this is how the packet is sent by LFS.
var cmd = mso.Msg.SubString(mso.TextStart);
bvillersjr
26th April 2011, 12:40
Am I correct in assuming that the unit of OutSim Delay is ms and that I should expect approx 1000 events per sec from InSim.Net with an OutSim Delay of 1?
I have no idea what the internal Physics rate of LFS is, or what the rate of the outputs are. 1000Hz seems a bit unlikely :)
NeOn_sp
26th April 2011, 12:45
The MSO packet works correctly, you need to use the TextStart property to get where the text starts. This is not InSim.NET, this is how the packet is sent by LFS.
var cmd = mso.Msg.SubString(mso.TextStart);
So "nickname : " is part of the msg.. Okok
Sorry for the error. I thought that mso.Msg was supposed to be just the msg without nick and : separator..
NotAnIllusion
26th April 2011, 13:02
Am I correct in assuming that the unit of OutSim Delay is ms and that I should expect approx 1000 events per sec from InSim.Net with an OutSim Delay of 1?
I have no idea what the internal Physics rate of LFS is, or what the rate of the outputs are. 1000Hz seems a bit unlikely :)
http://www.lfsforum.net/showthread.php?p=278155#post278155
(take it as 100 Hz)
DarkTimes
27th April 2011, 10:02
I've pushed out a release for InSim.NET 2.0.8 (http://insimdotnet.codeplex.com/releases/view/65234).
Changes
Support for InSim 5, added IS_CON etc.. (now supports both InSim 4 and 5)
Fixed several bugs related to sending strings containing double-byte characters
Updated documentation help file with new packets
I've flagged it as a beta for now, in-case anyone finds more pressing bugs that need to be fixed.
As always you can get the latest release on CodePlex (http://insimdotnet.codeplex.com/releases).
PoVo
27th April 2011, 10:24
Great work! Thanks :razz:
DarkTimes
28th April 2011, 23:07
OK, I think I've fixed the bug with the BTN text. What was happening is the BTN code wasn't correctly taking into account the NULL terminator when figuring out the length of the string. Because there was no NULL terminator LFS was discarding the string and not showing it, which is why some buttons appeared to not be sent.
Although Scawen has fixed this bug in the latest LFS patch, I'm not going to change it in InSim.NET for the moment, as that would break backwards compatibly with old LFS versions (which still have the bug). For the time being the maximum length of the BTN text field will remain 239 bytes.
Nasty!
29th April 2011, 23:36
well now im out this new insimdotnet 2.0.8
thats start crash when player name contain japan fonts
i get this
Press Ctrl+Z to exit...
InSim Error: System.IndexOutOfRangeException: Index was outside the bounds of th
e array.
at InSimDotNet.EncodingHelper.GetBytes(String value, Byte[] buffer, Int32 ind
ex, Int32 length) in C:\Users\Alex\Documents\Visual Studio 2010\Projects\InSimDo
tNet\InSimDotNet\EncodingHelper.cs:line 89
at InSimDotNet.PacketWriter.Write(String value, Int32 length) in C:\Users\Ale
x\Documents\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\PacketWriter .cs:
line 121
at InSimDotNet.Packets.IS_MST.GetBuffer() in C:\Users\Alex\Documents\Visual S
tudio 2010\Projects\InSimDotNet\InSimDotNet\Packets\IS_M ST.cs:line 49
at InSimDotNet.InSim.Send(ISendable packet) in C:\Users\Alex\Documents\Visual
Studio 2010\Projects\InSimDotNet\InSimDotNet\InSim.cs:lin e 231
at InSimDotNet.InSim.Send(String message, Object[] args) in C:\Users\Alex\Doc
uments\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\InSim.cs:lin e 266
at SparkCruise.CruiseApp.Message(String message, Object[] args) in C:\Documen
ts and Settings\Janne\Työpöytä\NCRCruise\NCRCruise\Cruise App.cs:line 12286
at SparkCruise.CruiseApp.ClickId(InSim insim, IS_BTC btc) in C:\Documents and
Settings\Janne\Työpöytä\NCRCruise\NCRCruise\Cruise App.cs:line 3905
at InSimDotNet.PacketBinding`1.ExecuteCallback(InSim insim, IPacket packet) i
n C:\Users\Alex\Documents\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\Pa
cketBinding~.cs:line 14
at InSimDotNet.BindingManager.ExecuteCallbacks(InSim insim, IPacket packet) i
n C:\Users\Alex\Documents\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\Bi
ndingManager.cs:line 85
at InSimDotNet.InSim.RaisePacketEvent(IPacket packet) in C:\Users\Alex\Docume
nts\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\InSim.cs:lin e 432
at InSimDotNet.InSim.mainSocket_PacketDataReceived(Ob ject sender, PacketDataE
ventArgs e) in C:\Users\Alex\Documents\Visual Studio 2010\Projects\InSimDotNet\I
nSimDotNet\InSim.cs:line 416
at InSimDotNet.TcpSocket.OnPacketDataReceived(PacketD ataEventArgs e) in C:\Us
ers\Alex\Documents\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\TcpSocket
.cs:line 274
at InSimDotNet.TcpSocket.HandlePackets(SocketState state) in C:\Users\Alex\Do
cuments\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\TcpSocket.cs :line 22
8
at InSimDotNet.TcpSocket.ReceiveCallback(IAsyncResult asyncResult) in C:\User
s\Alex\Documents\Visual Studio 2010\Projects\InSimDotNet\InSimDotNet\TcpSocket.c
s:line 208
any idea what is wrong and where :D
my code work nice and smooth if player name is normal letters
broken
30th April 2011, 00:08
Although Scawen has fixed this bug in the latest LFS patch, I'm not going to change it in InSim.NET for the moment, as that would break backwards compatibly with old LFS versions (which still have the bug). For the time being the maximum length of the BTN text field will remain 239 bytes.
Just a Q: When an official/stable version of LFS arrives, what do you plan on doing? I think it would be better to keep it compatible only as far as stable versions are concerned. But, anyway, we have the source, so we can tweak-a-la-freak as much as we want. Which means, that in the end, it doesn't really matter.
@Nasty! : I think you would need to provide the exact string of the problematic nickname, or maybe a replay would work too. Though, I think, the string is preferred. :tilt:
Nasty!
30th April 2011, 00:41
forgot that i find what cause crash
that was this
User {0} blaaablaablaaaaaaablaaaa {1}", user.Playername, user.CurrentCar
Nasty!
5th May 2011, 20:32
well all start go good and many bugs has fixed
then i start get error with compar and i think i change that nothing any idea what cause this....
InSim Error: System.InvalidOperationException: EntityMemberChanged or EntityComp
lexMemberChanged was called without first calling EntityMemberChanging or Entity
ComplexMemberChanging on the same change tracker with the same property name. Fo
r information about properly reporting changes, see the Entity Framework documen
tation.
at System.Data.Objects.EntityEntry.EntityMemberChange d(String entityMemberNam
e, Object complexObject, String complexObjectMemberName)
at System.Data.Objects.EntityEntry.EntityMemberChange d(String entityMemberNam
e)
at System.Data.Objects.ObjectStateEntry.System.Data.O bjects.DataClasses.IEnti
tyChangeTracker.EntityMemberChanged(String entityMemberName)
at System.Data.Objects.DataClasses.EntityObject.Repor tPropertyChanged(String
property)
at SparkCruise.User.set_Distance(Double value) in C:\Documents and Settings\J
anne\Työpöytä\NCRCruise\NCRCruise\SparkCruise.Desi gner.cs:line 459
at SparkCruise.CruiseApp.UpdateDistance(CompCar car, User user) in C:\Documen
ts and Settings\Janne\Työpöytä\NCRCruise\NCRCruise\Cruise App.cs:line 870
at SparkCruise.CruiseApp.CarUpdate(InSim insim, IS_MCI mci) in C:\Documents a
nd Settings\Janne\Työpöytä\NCRCruise\NCRCruise\Cruise App.cs:line 833
at InSimDotNet.PacketBinding`1.ExecuteCallback(InSim insim, IPacket packet) i
n C:\Documents and Settings\Janne\Työpöytä\insimdotnet-8981182341c2\insimdotnet_
8981182341c2\InSimDotNet\PacketBinding~.cs:line 14
at InSimDotNet.BindingManager.ExecuteCallbacks(InSim insim, IPacket packet) i
n C:\Documents and Settings\Janne\Työpöytä\insimdotnet-8981182341c2\insimdotnet_
8981182341c2\InSimDotNet\BindingManager.cs:line 85
at InSimDotNet.InSim.RaisePacketEvent(IPacket packet) in C:\Documents and Set
tings\Janne\Työpöytä\insimdotnet-8981182341c2\insimdotnet_8981182341c2\InSimDotN
et\InSim.cs:line 432
DarkTimes
6th May 2011, 08:26
This exception is being thrown by the Entity Framework (http://msdn.microsoft.com/en-us/library/aa697427(v=vs.80).aspx), it's not got anything to do with InSim.NET. The reason InSim.NET reports the exception is because it's being thrown on the packet receive thread.
You need to look for this exception in reference to the Entity Framework, unfortunately I can't really help you fix it.
http://www.google.co.uk/search?q=entity+framework+invalidoperationexceptio n
Nasty!
6th May 2011, 09:00
yeah thanks again darktimes i figure that out my self
new istall c# whole program fix that somehow that come some database system error idk what happend but after reinstall c# not get anymore that :P
btw AGAIN big thanks to make "idiot proof"library so stupid like me can code insim stuff that :P
DarkTimes
11th May 2011, 14:33
I said ages ago that I'd release a quick example to show using InSim.NET in a Windows Forms application, but I never got round to it. So anyway, here is a small app that prints the contents of each MSO packet received to a text box.
You can find the VS2010 project and a screenshot below.
Nasty!
11th May 2011, 20:20
any fast and good idea to block player took over feature in sparkcruise , that make weird km run without move bug ?
all tips are welcome
thanks
DarkTimes
11th May 2011, 20:24
Just a Q: When an official/stable version of LFS arrives, what do you plan on doing? I think it would be better to keep it compatible only as far as stable versions are concerned. But, anyway, we have the source, so we can tweak-a-la-freak as much as we want. Which means, that in the end, it doesn't really matter.
Sorry, I didn't see this question before.
I will update InSim.NET to match the most stable release of LFS where I can. There is nothing in the current version of InSim.NET that stops you from using it with InSim 4 or 5, although there are a couple of small issues. For instance in the new patch Scawen has fixed the old BTN text bug. I could fix this in InSim.NET, but there are two reasons not to. Firstly, the old version of LFS still has the bug and fixing it would mean braking support for Z28. Secondly, it's actually easier for me to not fix it, as it would mean changing the way in which InSim.NET handles strings. This isn't laziness however, it's caution.
I normally would have no problem messing with this sort of stuff, but I've finally got to the point where the LFS string encoding is working reliably, and I'd prefer to leave it stable for a while rather than messing around with it and possibly breaking lots of new things. It will need attention at some point, as there are several issues that have built up that I would like resolve, but they all require the same bit of code to be refactored.
InSim.Send(byte, string, params object[]) became (possibly) much less efficient in a recent bug fix
InSim.NET still works around the text bug in IS_BTN (as mentioned above)
The EncodingHelper static class needs to be rewritten as an actual System.Text.Encoding derived object.
All of these issues are connected and require modification to the same piece of code, so I'm going to put it off for a while until I really feel like doing it. It's also the piece of code which has caused about 8 of the last 10 bugs in InSim.NET, so I don't really want to change it unless I have to (I'm also thinking about taking an entirely different approach to coding it).
To sum up, I will keep InSim.NET up-to-date with the most stable release of LFS, unless I have a reason not to, and that reason might not be immediately apparent. I won't break InSim.NET however.
broken
11th May 2011, 21:23
Sorry, I didn't see this question before.
Well no problem at all, I was just curious. :)
Thanks for all the explanations too, that sounds awesome. ^^
This library actually makes me want to program in a way, it's weird. If it was still named Spark, I'd probably say something stupid like "It gives me the Spark", or some lame flat joke like that. :D
DarkTimes
11th May 2011, 22:02
Thanks!
You should probably be asking how I've managed to write a class I'm afraid to touch incase I break it again. :x
broken
11th May 2011, 22:26
Well, this is (or at least used to be, we will see) my regular routine, so I don't find it strange at all. xD
But what I do find weird... this library's progress goes mindblowingly fast, and in the meantime, you just decide and update another library.. pssht, just a regular thing, right? :razz:
DarkTimes
11th May 2011, 22:32
Well, this is (or at least used to be, we will see) my regular routine, so I don't find it strange at all. xD
But what I do find weird... this library's progress goes mindblowingly fast, and in the meantime, you just decide and update another library.. pssht, just a regular thing, right? :razz:
I had thought about updating it for a while, but I couldn't be bothered. Then I realised that the free license for Reflector runs out at the end of May, so if I was going to do it I would have to do it now. The main point was to post the source for LFS_External, as once that is up anyone can change it, and I wouldn't have to worry about the license for Reflector being changed.. The changes I made took literally 30 minutes and could have been done by anyone in the last two years.
Nasty!
31st May 2011, 04:59
weird problem i cant get key press function work , any sample how example insim click number 7 via insim. Thanks for help.
DarkTimes
4th June 2011, 14:33
weird problem i cant get key press function work , any sample how example insim click number 7 via insim. Thanks for help.
Heya,
Sorry, I didn't see this before. To send a keypress you just send a IS_SCH packet, although you can also send a IS_MST with a /press command.
Anyway, here is an example of sending a IS_SCH to LFS.
using (InSim insim = new InSim()) {
insim.Initialize(new InSimSettings {
Host = "127.0.0.1",
Port = 29999,
Admin = String.Empty,
});
// Send IS_SCH packet.
insim.Send(new IS_SCH {
CharB = '7',
});
Console.ReadKey(true);
}
It should be noted that this doesn't do much, although if you open the chat box ('t') you can see the number being typed in game.
On a general note I'm waiting for Scawen to release the next patch with the planned InSim updates before I make a new version of this.
Nasty!
6th June 2011, 04:11
well, thanks i try test that. again good job with this lib this is rly awesome
DarkTimes
10th June 2011, 21:39
I'll try and release an updated InSim.NET tomorrow. I've added all the updates but I need to test them.
vBulletin® v3.8.6, Copyright ©2000-2012, Jelsoft Enterprises Ltd.