The online racing simulator
Searching in All forums
(921 results)
DarkTimes
S2 licensed
Quote from broken :but C becomes 2 times faster than C# in the current case.

The C version will not be two times faster than the C# version. I'm not sure that the C version would be faster at all.

Warning: the stuff below is my own opinion and other people might not agree with me.

Quote :I know that sometimes taking too much time on optimization can just have the opposite impact on your creation, but my simplistic brain tells me that this is quite not the case. And, yes - not 'not quite the case', but indeed 'quite not the case'.

This isn't really a question of optimisation it's a question of having good coding practices. The whole "premature optimisation is the root of all evil" thing is a misquote lazy programmers come out with as an excuse for writing bad code.

There are three kinds of optimisation:
  • Optimisation that comes from good coding practices (like above)
  • Optimisation that comes from having a good design
  • Optimisation that comes from measuring performance and focusing on the slowest areas
Only the third item can be considered a premature optimisation if you do it too early, the first is something you should be thinking about all the time and the second you should be thinking about before you write a line of code. Now all this is not to say that you should sacrifice readability for performance, first and foremost you should write code that's easy to read, but if you are finding it hard to optimise your code while maintaining legibility that would suggest that there is something wrong with your design or your algorithms.

So basically I would not consider the (C/C#) code examples above to be a symptom of premature optimisation, I consider them to be examples of fundamental good coding practice.
DarkTimes
S2 licensed
Wouldn't it be O(n²)? I'm not good with Big O either.
DarkTimes
S2 licensed
Quote from broken :The question was: Would it be more efficient if I made a reference(if that's the right term to use.. my terminology sucks) to the connection, or if I iterate through it every time. (yes, now that I think of it, it's pretty obvious, but back then I didn't have the knowledge I do now)

Yes you can refer to it as a reference, as it's a reference to an object on the heap. You are making a copy of the reference and storing it inside a variable.

It is a common mistake many programmers make to perform expensive operations multiple times. It is however dependent on your domain knowledge, that is, your knowledge of what is happening beneath the covers in a language. Take these two programs that both take a string and print out each character on a separate line.

string str = "Hello, world!";

for (int i = 0; i < str.Length; i++)
{
Console.WriteLine(str[i]);
}

int i;
char str[] = "Hello, world!";

for (i = 0; i < strlen(str); i++)
{
printf("%c\n", str[i]);
}

The first program is C# and the second is C. Both of these programs look similar and both have fundamentally the same code, except that the C# version will run many times faster than the C version (yes even through C is C and supposed to be SUPER FAST OMG!)

The reason for this is how they each handle strings internally. In both languages string are just arrays of chars, but what differs is how each language determines the length of the string. In C strings are NULL terminated, meaning that the last character of each string is NULL (or '\0'). In the example above that fact is hidden from you, as the compiler is smart enough to add that NULL character automatically.

The actual array of chars that the compiler initialises looks like this, with a NULL char appended on the end:

char str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', [b]'\0'[/b] };

So how does strlen figure out the length of a string?

int strlen(char* str)
{
int i = 0;
while (str[++i]);
return i;
}

It loops through the str counting each character until it finds a NULL (which is the same as false in C) and then returns the count. So each time the for loop in the example calls strlen is has to loop through the entire string to find the NULL. What if the string was thousands of characters long? That would take a long time.

C# however is a different beast. The .NET framework doesn't use NULL terminating characters to deliminate strings, instead it uses a system known as PASCAL strings, or length-prefixed strings. What that means is that each string in .NET is prefixed with a hidden int that contains the the length of the string that follows it. You can imagine it like this:

HEAD | TAIL
1101 | 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'

This is a gross simplification as .NET actually uses 16-bit wide unicode strings to store text and the header is way more complicated, but anyway... So how does the .NET framework get the string length? Simple, it just returns the header. So as you can see, two pieces of code which appear to do the same thing, actually have massively different consequences depending on how the underlying function calls are implemented.

The basic point is that there is no "right-way" to do these kinds of things, it depends on the language, the framework and the implementation. The only way you can decide whether its OK to call a function or a property in a loop or multiple times is by having as much domain knowledge of the underlying architecture as possible.

(Note: In the .NET Framework library as rule of thumb properties such as length are almost always pretty efficient and expensive operations are normally wrapped in function calls).
Last edited by DarkTimes, .
DarkTimes
S2 licensed
For the stat types I would use an enum:

enum StatType
{
Cadet,
Officer,
TowTruck,
Member,
}

if (Connections[GetConnIdx(CPR.UCID)].Stat == StatType.Officer)
{
// Do something.
}

This makes the code easier to read and also safer, as you now get compile-time checking of the stat property.

While I'm at it this sort of code is incredibly inefficent:

if (Connections[[b]GetConnIdx(CPR.UCID)[/b]].Stat == 2)
{
InSim.Send_MTC_MessageToConnection("^2•^7 You are a On-Duty cop so FOLLOW THE RULES!", CPR.UCID, 0);
Connections[[b]GetConnIdx(CPR.UCID)[/b]].IsOfficer = 1;
}
else
{
InSim.Send_MST_Message("/spec " + Connections[[b]GetConnIdx(CPR.UCID)[/b]].Username);
InSim.Send_MTC_MessageToConnection("^1You are Not a Officer!", CPR.UCID, 0);
Connections[[b]GetConnIdx(CPR.UCID)[/b]].IsOfficer = 0;
}

GetConnIdx() iterates through the entire connection list each time you call it and in this short section of code it's being called four times! Instead you should do this:

[b]var conn = Connections[GetConnIdx(CPR.UCID)][/b];

if ([b]conn[/b].Stat == 2)
{
InSim.Send_MTC_MessageToConnection("^2•^7 You are a On-Duty cop so FOLLOW THE RULES!", CPR.UCID, 0);
[b]conn[/b].IsOfficer = [b]true[/b]; // Make IsOfficer a bool!!
}
else
{
InSim.Send_MST_Message("/spec " + [b]conn[/b].Username);
InSim.Send_MTC_MessageToConnection("^1You are Not a Officer!", CPR.UCID, 0);
[b]conn[/b].IsOfficer = false;
}

Not only is this much much faster it also makes the code easier to read. Of course a better solution is to make Connections a hash table, then you don't need to loop through the list at all.
DarkTimes
S2 licensed
Quote from amp88 :InSim does operate in single player mode.

Yup - it even works if you just play back a replay.
DarkTimes
S2 licensed
Quote from boothy :A version that wrote the exported files with the filter in place would be good as well would be great

Yeah, I think that was what it was supposed to do originally, not sure why I didn't update it. Anyway I uploaded a new version that exports only the filtered packet list. There is a option in the options dialog to revert back to the old functionality.

Sorry for derailing the thread. Proceed.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Uploaded 1.1.2 to the first post. Only a single change:

Changes
  • Export now only exports the filtered packets list instead of the full packet list.
There is an option to renable the old functionality (export all packets no matter what) in the options dialog. That is all.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
I imagine the UI would be flooded with packets if you left it on for days. Still it's heartening to know it still works after running for so long. Maybe a version that wrote packets to log files would be better?
DarkTimes
S2 licensed
Just to note a couple of things:
  • LFSPoints isn't a InSim addon
  • Spark, pyinsim and CInSim are not addons, they're libraries that people to use to create addons.
  • I really hope no one is running InSimSniffer 24/7
DarkTimes
S2 licensed
I don't really know PHP (as I'm sure everyone has worked out ), but I think your syntax is a bit mixed up. I think you have the registerPacket parameters the wrong way round. Also in PHP you don't need to specify the type of the param (maybe it's optional though, I dunno). Try this:

public function __construct()
{
$this->registerPacket('ConConnects', ISP_NCN);
}

public function ConConnects($NCN)
{
$MTC = new IS_MTC();
$MTC->UCID($NCN->$UCID)->Msg(sprintf('%s ^7Welcome to %s', self::PreMsgStl, self::GameName))->Send();
return PLUGIN_CONTINUE;
}

DarkTimes
S2 licensed
Well if that's what he means his post doesn't say that. It says he's getting 'host: ^7red' when he wants 'host: red'.
DarkTimes
S2 licensed
Quote from Mountaindewzilla :I feel embarrassed asking, but how to you send colored messages?
Doing this:
insim.send(pyinsim.ISP_MST, Msg='^1Red')

Gives me the in-game result:
Host:^1Red

instead of

Host:Red

Based on what I read in LFSLapper, my assumption is that what I did above should work.

Yup, that's correct. They are special characters that tell LFS to switch font colour.

Note: this also works in the game itself, in fact back in S1 this was the only way to change the text colour in the game

Quote from PoVo :
insim.send(pyinsim.ISP_MST, Msg='[B]/msg[/B] ^1Red')


The /msg command is optional.
DarkTimes
S2 licensed
Quote from misiek08 :Can you show example, how to send it. In C# or PHP?

It's basically just about setting the bits to turn the colours on and off. For instance if you wanted to make a button that was clickable, had a light background and used the title colour (colour 1), you would do this:

BStyle = ISB_CLICK | ISB_LIGHT | [b]1[/b]

Or if you wanted to use the cancel colour (colour 5):

BStyle = ISB_CLICK | ISB_LIGHT | [b]5[/b]

Here is a pyinsim example which sends a button with one of those bits set:

import pyinsim

insim = pyinsim.insim('127.0.0.1', 29999, Admin='', IName='Example')

insim.send(pyinsim.ISP_BTN,
ReqI=255,
ClickID=1,
[b]BStyle=pyinsim.ISB_CLICK | pyinsim.ISB_LIGHT | 5[/b],
T=60,
L=10,
W=40,
H=10,
Text='Button Example')

pyinsim.run()

Which creates a button like below.
DarkTimes
S2 licensed
This Saturday night on ITV, I'm a celebrity... winch me out of here!

But yeah, awesome to see them come out. A great result.
DarkTimes
S2 licensed
This isn't an InSim related question, it's a C# question. To format output you can use the String.Format method.

To format an integer with thousands commas, you can do this:

string.Format("{0:n0}", 3536453);

// Output: 3,536,453

DarkTimes
S2 licensed
I thought it was a great race! Lots of action, accidents and great driving.
DarkTimes
S2 licensed
Japanese, Korean, Traditional and Simplified Chinese are double-byte (or really multi-byte) character sets. You can check by typing a Japanese character into LFS and comparing the lead and tail bytes to the CP932 codepage.
DarkTimes
S2 licensed
Quote from Dygear :Is there a good online resource for looking this information up that might be a good to post so people can help them self first, and ask questions later?

Yes, it's called MSDN. Here is the System.String class.

Note in Visual Studio if you place your mouse over a class and press F1 it will take you to the documentation for that object automatically.
DarkTimes
S2 licensed
Bah why does Hamilton keep driving into walls? It's getting silly now! Walls == bad!
Last edited by DarkTimes, .
DarkTimes
S2 licensed
Quote from morpha :To extend this, MSDN's codepage list made me wonder if the codepages used by LFS are really the ISO equivalents or indeed the Windows code pages. In other words, shouldn't it be:
J -> Japanese CP932 (Shift-JIS)
S -> Simplified Chinese CP936 (PRC, Singapore, GB2312)
K -> Korean CP949 (Unified Hangul Code)
H -> Traditional Chinese CP950 (Taiwan, Hong Kong SAR, PRC, Big5)
E -> Central European CP1250 (instead of CP28592 -> ISO-8859-2)
C -> Cyrillic CP1251 (instead of CP28595 -> ISO-8859-5)
L -> Latin 1 CP1252 (instead of CP28591 -> ISO-8859-1)
G -> Greek CP1253 (instead of CP28597 -> ISO-8859-7)
T -> Turkish CP1254 (instead of CP28599 -> ISO-8859-9)
B -> Baltic CP1257 (instead of CP28594 -> ISO-8859-4)

Thoughts?

Yeah, I'm slow.

I realised the other day that the codepage for each language is listed at the top that language's translation file in the LFS directory. Using this source I can confirm that these are correct. I see no reason to presume that the translation files within LFS would specify anything other than the correct codepage.

LFS Translation file (Japanese)
Translated by: AE100, gilles_jpn, highbridge, Sae Kazamori, takaryo, yamakawa

[B]tx_codepage 932[/B]
tx_langname “ú–{Œê
tx_noun_adj an
3g_tr_selct TRAINING
3g_tr_title Select Lesson

...

I've been messing around with the encodings over the last few days and to be honest I've learned more about single-byte and double-byte character sets than I can stand .

Budda bless UTF8 and long may it reign supreme.
Last edited by DarkTimes, .
DarkTimes
S2 licensed
I've noticed some people are still downloading the old version of the library. The old < 2.0 version has been left for archive purposes only. For all new pyinsim programs you should use the most recent stable version, which is always available on CodePlex. The only reason you would ever need to download the old version of library is if you need to work with legacy code.

To summarise: do not download the old version of pyinsim unless you have a very good reason to. In almost all cases the latest stable release is what you want.
DarkTimes
S2 licensed
Quote from Dygear :When is that ever useful in a language? That just seems to be overtly obtuse and for no reason then to just be obtuse! This is another area that I feel that PHP excels, comparing data. == checks that the bits are the same, whereas === checks that the bits and the data type are the same.

Well the reason it won't work is because "Flowers" is seven characters in length, but he's only checking the first six characters of the substring.

Substring has its uses, mainly for slicing ranges out of strings, but in C# you would normally do:

if (line.StartsWith("Flowers"))
{

}

Or if you're worried about internationalisation:

if (line.StartsWith("Flowers", StringComparison.InvariantCulture))
{

}

C# doesn't need '===' because it is strongly typed. We have '==' for reference comparison and 'is' for type comparison.
DarkTimes
S2 licensed
Ah OK, I got a little confused by the wording, I see that now.
DarkTimes
S2 licensed
Can I ask why the setup screen asks me for my LFS account password?
DarkTimes
S2 licensed
Quote from AndroidXP :If you're not totally set on putting up with C++, and as you've mentioned possibly using .NET components, it might be worthwhile to consider using C# in conjunction with SlimDX instead.

For C# there is XNA too of course, but that's a complete game development framework, rather than a wrapper round DirectX.
FGED GREDG RDFGDR GSFDG