// //Drew's VERY basic guide to getting started with C# LFS InSIm programming. // When I decided to have a go at making my own InSim, I was pointed towards C# - here's a cheat sheet for people who are BRAND NEW to this stuff. More as a reference guide - information I have gleaned from a few different sources - thanks are at the end :-) This will help you build your own BRANDED RACE SERVER and give you a VERY basic grounding in InSim creation using C#. What you'll need: I strongly suggest you start with a 'base InSim', downloadable from the LFS forum (it's a program that has all the necessary coding in to connect to LFS, and stay connected. Apart from some helpful comments it is bare - so an ideal base for your own InSim. Download it from here > CAN’T FIND IT J OMG, I AM SO SORRY! NET framework 3.5. Needed to install VS – get it from Micro$oft here > http://download.microsoft.com/downlo...dotnetfx35.exe Micro$oft Visual Studio - you'll need something to edit your code. You can use any text editor, but to compile the code into an .exe file you will need a compiler. I strongly suggest you use Micro$oft Visual Studio. The express edition is free, has a built in text editor, interface editor and compiler and is available for download here > http://www.microsoft.com/exPress/ LFS dedicated host. I suggest that you get the dedicated host to run your InSim on throughout the editing process. It is available for download here > http://www.lfs.net/?page=addons Now you're ready to go. NOTE: C# IS CASE SENSITIVE. Getting started: Navigate to your downloaded base InSim. The file you are looking for is a .csproj file, and should be located here: Downloaded folder > lfs_external_insim_csf11 >lfs_external_insim_csf11 > ********.csproj When you've found it, double click it to open it in VS. Now you are faced with the source code for your InSim. Have a good look through it - and see if it makes ANY sense at all, it probably doesn't. But don't worry. The green lines preceded by // are comments, and are ignored by the computer. Let's make a 'button'. A button isn't really a button - more of a background shape that can receive text. When you are on a server and a box pops up with a message in it - that's a button. // // // Making InSim buttons in C# // // Navigate through the script until you find this bit: // A new client joined the server. private void NCN_ClientJoinsHost(Packets.IS_NCN NCN) { AddToConnectionsList(NCN); // Update Connections[] list // Your code here } The code you will be adding goes after: // Your code here (on a new line) but before the closing curly bracket > } The new code will look like this example button: InSim.Send_BTN_CreateButton("Example button", Flags.ButtonStyles.ISB_LIGHT, 001, 002, 003, 004, 005, NCN.UCID, 2, false); Looks like a right mouthful - and it's in programmer speak. So let's translate it. InSim.Send_BTN_CreateButton = tells the InSim to make a button. "Example button" = Text on button (inside the quotes). Flags.ButtonStyles.ISB_LIGHT = Assign a background style to the button (ISB_LIGHT is the bit to change - this is the style applied. There are a few, ISB_DARK is another one and all the ones I have discovered and a description are at the end of this document). Multiple styles can be used (for instance ISB_DARK and ISB_CLICK to make a button that is clickable and has a dark background. In this case, separate the styles with a | like this: Flags.ButtonStyles.ISB_CLICK | Flags.ButtonStyles.ISB_DARK ). 001 = Height of button (0-200). 002 = Width of button (0-200). 003 = Vertical co-ordinate (0-200, 200 = bottom) 004 = Left co-ordinate (0-200, 200 = right) 005 = Button ID (only numbers - letters aren't allowed). NCN.UCID = Who to send it to (NCN = connect packet (you see this in the lines above - it's different for each event), UCID = unique player id). See the appendix for variables here. 2 = Ignored false = inPitVisibility - whether or not the button disappears on the pit screen. So go ahead and type that into the indicated place - be sure to modify the text, size and position co-ordinate values from what is up there, because it'll just be silly if you don’t (try this... 5, 50, 2, 15, 001 – that’s: 5 high, 50 wide, 2 down from top, 15 right from the side and button ID 001). Now let's see if it worked. Running your InSim program for the first time: Go to line 14 (I think) of your code, it should look like this: // InSim connection settings InSimSettings Settings = new InSimSettings("127.0.0.1", 29999, 0, Flags.InSimFlags.ISF_MSO_COLS | Flags.InSimFlags.ISF_MCI, '!', 500, "testpass", "^3LFS External", 5); The bits that MAY need modifying are these: "127.0.0.1", 29999 and "testpass". 127.0.0.1 is the ip address of the server (127.0.0.1 because it's local). 29999 is the InSim port for LFS (MUST match the InSim port on the server. This can be set in the setup.cfg file for the host server). "testpass" is the admin password for your server (i suggest you change it - or leave it until you go live). Start your dedicated host up (I suggest just making it a local host - after all, we are just testing) making sure that the settings above match otherwise the InSim won't be able to connect to your server. Now fire up LFS and select Multiplayer game > local host and put in the settings that you specified a minute ago (ip address, password and port - port setting should match what is in the host config file). Now you should be connected to the dedicated host (two LFS's running - one dedicated host and one graphical client). To run the InSim, it needs to be compiled from the script to a format the computer understands - to an .exe file. But to save compiling over and over again VS has a 'debugging' feature. This allows the program to run as if it had been compiled to check for errors etc. So click the 'Debug' button at the top of the VS screen (looks like a 'play' button on a CD player). Now the InSim should start up, and on the LFS host some text should appear and on the graphical client (the one with the car on it) a box with "Example button' on it should appear at the top of the screen (as long as you have exited the pits - remember we set the InPitsVisibility to 'false'. If it doesn't work, go back through and see if you can spot what's wrong - VS will give an error if it notices anything wrong. Assuming all goes well - it's time to get your creative juices flowing, and see what other buttons you want to make! Jump back into VS and click on 'Debug > Stop Debugging' (if you don't, you won't be able to edit your code). Congratulations - now the real basic stuff is covered, you can make a start on customising your server. @TIP@ Hinty tip type thing @TIP@ I had no end of issues getting the messages to show to the right person (the NCN.UCID bit). I found that just by changing the NCN part didn’t do what I expected it to (if you see the appendix, you will see the different codes used for different events). I was using this: InSim.Send_BTN_CreateButton("Example button", Flags.ButtonStyles.ISB_LIGHT, 001, 002, 003, 004, 005, NCN.UCID, 2, false); … for a button that was sent upon a new connection (NCN.UCID – NCN is the code for a new connection). So it made sense to me to make a button that appeared when a player resets their car to use this… InSim.Send_BTN_CreateButton("^1You reset your car!", Flags.ButtonStyles.ISB_LIGHT, 001, 002, 003, 004, 005, CRS.UCID, 2, false); … as CRS is the code for a car reset. This doesn’t work. The correct synax for this is in fact: InSim.Send_BTN_CreateButton("^1You reset your car!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID, 2, false); The underlined section is the changed part, and the bold is the code for the trigger action. I’m still working on when you use each type. More button stuff. Making a button disappear. Not every button that appears is a permanent one – for instance the “car reset” one discussed earlier. If all the buttons we make stay for ever – we’ll run out of room. So we need a way of getting rid of them. Here’s the syntax for deleting the car reset button: InSim.Send_BFN_DeleteButton(0, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID); The first value (0) we can ignore but the second (0010) is the button ID. You can use this to delete a button when an action triggers it – or make it display for a certain amount of time (preferred a lot of the time for information, such as the “car reset example). To make it wait, the simple (if heavy handed) way of doing it is this: System.Threading.Thread.Sleep(3000); Which tells the insim to stop for the predetermined amount of time (in this instance 3 seconds – C# works in milliseconds where 3000 = 3 seconds) before continuing. My completed code for the reset button is this (remember, everything after a // is ignored): // A player resets the car private void CRS_PlayerResetsCar(Packets.IS_CRS CRS) { // A button is created with text: “You reset your car!” InSim.Send_BTN_CreateButton("^1You reset your car!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID, 2, false); //The InSim is told to sleep for 3 seconds System.Threading.Thread.Sleep(3000); //The button is deleted InSim.Send_BFN_DeleteButton(0, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID); } So you get an idea of how it works. Creating messages from player inputs: Many, many InSims (if not all InSims) use some kind of player provoked message sysyem (!rules is the obvious example). So the player inputs: !rules And the InSim responds with something like: Here are the rules on this server: No ramming. If you spin – SPECTATE! No swearing. You get the picture. To make your own rules command, you need to be adding !case commands – scroll through your base InSim code until you find it – there should be a few in there already. The syntax looks like this: case "!rules": InSim.Send_MST_Message("Here are the rules on this server:"); InSim.Send_MST_Message("No ramming."); InSim.Send_MST_Message("If you spin – SPECTATE!"); InSim.Send_MST_Message("No swearing."); break; You can add as many of these as you wish – but the !case commands must all begin with an exclamation mark (!) and each one must be preceded with: case “!commandGOEShere”: And end with: break; Creating a button from a player input: You can also make a button appear when a player prompts it – so instead of having your help commands appear in the LFS chat area – you can make them appear wherever you like. Here’s an example: case "!button": InSim.Send_BTN_CreateButton("^1Made this button with !button!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 112, (Connections[GetConnIdx(MSO.UCID)].UniqueID), 2, false); break; You see the command is defined with: case “!button”; The button is defined with: InSim.Send_BTN_CreateButton("^1Made this button with !button!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 112, (Connections[GetConnIdx(MSO.UCID)].UniqueID), 2, false); And the section is finished with: break; Again, a permanent button may not be required – so if we apply a little bit of logic to proceedings, we can make it disappear… case "!button": InSim.Send_BTN_CreateButton("^1Made this button with !button!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 112, (Connections[GetConnIdx(MSO.UCID)].UniqueID), 2, false); System.Threading.Thread.Sleep(3000); InSim.Send_BFN_DeleteButton(0, 112, Connections[GetConnIdx(Players[GetPlyIdx(MSO.PLID)].UniqueID)].UniqueID); break; Final compiling. Here’s the exciting bit! Now you are happy with how your InSim is working, you need to compile it into an executable (.exe) file that you can run or distribute. VS makes this very simple – go to Build > Build Solution With any luck – you won’t notice anything happen. But at he bottom of the window just above the taskbar on the left hand side will be a small message – Build Succeeded. If you now navigate to the folder where you saved your project (in my case E:\InSim Stuff\SAMPLE INSIM\lfs_external_insim_csf11\lfs_external_csf11\bin\Release – the bin\Release is the important bit) you will find a new program. It’s the one you just made. Double click it and revel in the good feeling that comes from your first ever finished scratch built InSim. ////////////////////////////////////////////////////////////// Appendix ////////////////////////////////////////////////////////////// Button styles: ISB_LIGHT = Light coloured background. ISB_DARK = Dark coloured background. ISB_CLICK = Makes button clickable. ISB_LEFT = ISB_RIGHT = ISB_C1 = ISB_C2 = ISB_C4 = Coloured text: To create coloured text, use the following codes in front of the text you want to color: ^0 - black ^1 - red ^2 - green ^3 - yellow ^4 - blue ^5 - violet ^6 - cyan ^7 - white ^8 - no color Example: ^0Hello ^1and welcome ^4to my server! Gives you: Hello and welcome to my server! Event triggers: These are the codes to identify an action that can trigger an event. ISP_ISI, insim initialise ISP_VER, version info ISP_TINY, multi purpose ISP_SMALL, multi purpose ISP_STA, state info ISP_SCH, single character ISP_SFP, state flags pack ISP_SCC, set car camera ISP_CPP, cam pos pack ISP_ISM, start multiplayer ISP_MSO, message out ISP_III, hidden /i message ISP_MST, type message or /command ISP_MTC, message to a connection ISP_MOD, set screen mode ISP_VTN, vote notification ISP_RST, race start ISP_NCN, new connection ISP_CNL, connection left ISP_CPR, connection renamed ISP_NPL, new player (joined race) ISP_PLP, player pit (keeps slot in race) ISP_PLL, player leave (spectate - loses slot) ISP_LAP, lap time ISP_SPX, split x time ISP_PIT, pit stop start ISP_PSF, pit stop finish ISP_PLA, pit lane enter / leave ISP_CCH, camera changed ISP_PEN, penalty given or cleared ISP_TOC, take over car ISP_FLG, flag (yellow or blue) ISP_PFL, player flags (help flags) ISP_FIN, finished race ISP_RES, result confirmed ISP_REO, reorder (info or instruction) ISP_NLP, node and lap packet ISP_MCI, multi car info ISP_MSX, type message ISP_MSL, message to local computer ISP_CRS, car reset ISP_BFN, delete buttons / receive button requests ISP_AXI, autocross layout information ISP_AXO, hit an autocross object ISP_BTN, show a button on local or remote screen ISP_BTC, sent when a user clicks a button ISP_BTT, sent after typing into a button ISP_RIP, replay information packet ISP_SSH, screenshot ////////////////////////////////////////////////////////////// Thank you ////////////////////////////////////////////////////////////// I wouldn’t have been able to compile this guide without a LOT of help from the LFS community. Special thanks go out to: The fella that made the base InSim I used for this – I don’t know who you are and I lost the link to the base InSim. I’m sorry, contact me and I’ll credit you. MaruisMM [TC]>Marius< – For constant help via MSN, access to his [TC] Citydriving training InSim source code and access to the Marryland server for testing. Degats [TC]>Elmo< - Helping me out with coding advice on the LFS forums. Gai Luron – For creating the Lapper software that taught me about the first steps of programming and putting up with my constant questions on the LFS forums. Sinanju – For helping me out a lot on the LFS forums with coding questions – and creating the inspirational DriftMeter. //////////////////////////////////////////////////////// Step by step to make your own branded (but useless) race server. //////////////////////////////////////////////////////// FOR THE LAZY ASS PEOPLES. Once you have opened your base InSim and got at the code, copy and paste these into the relevant sections to create your own branded race server with personalised messages etc. Format: // Identifier for section <> Compile and enjoy. ----------------------------------------------------------------------------------------------- // InSim connection settings InSimSettings Settings = new InSimSettings("<>", 29999, 0, Flags.InSimFlags.ISF_MSO_COLS | Flags.InSimFlags.ISF_MCI, '!', 500, "<>", "<>", 5); -------------------------------------------------------------------------------------------------- AddToConnectionsList(NCN); // Update Connections[] list // Your code here // Top bar buttons InSim.Send_BTN_CreateButton("<>", Flags.ButtonStyles.ISB_LIGHT, 5, 50, 2, 15, 0001, NCN.UCID, 2, false); InSim.Send_BTN_CreateButton("<>", Flags.ButtonStyles.ISB_LIGHT, 5, 50, 2, 135, 0003, NCN.UCID, 2, false); InSim.Send_BTN_CreateButton("", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 0004, NCN.UCID, 2, false); -------------------------------------------------------- // Get a ! command to make a button :-S case "!<>": InSim.Send_BTN_CreateButton("<>", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 112, (Connections[GetConnIdx(MSO.UCID)].UniqueID), 2, false); System.Threading.Thread.Sleep(3000); InSim.Send_BFN_DeleteButton(0, 112, Connections[GetConnIdx(Players[GetPlyIdx(MSO.PLID)].UniqueID)].UniqueID); break; ---------------------------------------------------------- // A player resets the car private void CRS_PlayerResetsCar(Packets.IS_CRS CRS) { InSim.Send_BTN_CreateButton("<>!", Flags.ButtonStyles.ISB_LIGHT, 7, 66, 2, 67, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID, 2, false); System.Threading.Thread.Sleep(3000); InSim.Send_BFN_DeleteButton(0, 0010, Connections[GetConnIdx(Players[GetPlyIdx(CRS.PLID)].UniqueID)].UniqueID); } REMEMBER! I’m not even close to a programmer – in fact, even as a newb, you probably know more than me. I was just trying to help J By: Drew 555 Contact: turboturtle555@yahoo.co.uk