News:

Simutrans.com Portal
Our Simutrans site. You can find everything about Simutrans from here.

Proposal: Simutrans DevGuide

Started by IgorEliezer, December 20, 2008, 06:43:57 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

IgorEliezer

Hi,

Some months ago, I felt the need of having a guide for programmers who want to get involved with development of Simutrans.

Say, you are a programmer; you discover Simutrans right now, and desire to contribute. But you don't know where to start from. What you could do? Where you have to go? What are the rules and/or standards you have to follow? Where's the code? Where you can release patches? Etc and so on... seems you have to discover the paths yourself.

I know there are some texts spread out there, but I think we could facilitate the things...

I hope you have understood me. :)

Combuijs

Good idea!!! Might take some time now from for instance Prissi, but it will surely spare time in the future.
Bob Marley: No woman, no cry

Programmer: No user, no bugs



jamespetts

That's an excellent idea! It would be very helpful in particular to know what part of the code does what so that people who want to change a specific function do not have to try to work out where that function can be found in the code...
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

Go ahead. I do not have any time for that too. You know simutrans is a fun project. ANd writing documentations and reports is my job. Go figure ...

IgorEliezer

Again, I'm "quoting" blender.org as example to be followed.

When you open blender.org site, you'll see a "Get involved" link:

Get involved
http://www.blender.org/community/get-involved

As you see, there's a list of all project you can participate in. For each project, there are instructions and links for guides and so. I think you all can get a idea of what I'm speaking. That's my idea for http://simutrans.sourceforge.net too.

isidoro

Though it is a nice idea, the main problem I find when trying to help is language of the source code.  An effort towards translating into English old functions and comments would be a big step for people to be able to contribute.

VS

Well, step 1 is then translation of all gib and setze to get and set!

This should be probably done in a period when nothing else changes. Because this changes everything.

My projects... Tools for messing with Simutrans graphics. Graphic archive - templates and some other stuff for painters. Development logs for most recent information on what is going on. And of course pak128!

jamespetts

I have found Google translator (or Yahoo! Babelfish - if one translation does not work, I try the other) to be very helpful in translating bits of the source code: whenever I find a translation of something that I might need there, I add it to the comments.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

Combuijs

QuoteGood idea!!! Might take some time now from for instance Prissi, but it will surely spare time in the future.

QuoteGo ahead. I do not have any time for that too. You know simutrans is a fun project
.

Prissi, I don't want you to write a full documentation set for Simutrans. Apart from being too much work and you not liking it, Simutrans is changing too fast to keep documentation up to date. That would not make sense.

What I had in mind is the following:
1) Descriptions how to compile the program (can be found in several forum topics)
2) Description of the Simutrans programming standard (there is one somewhere)
3) A small overview what each file (or set of files) is doing to get another programmer started. Should be no longer than one A4-page, if possible even shorter. There is no such thing now.
4) A collection of answers (mostly given by you as you are the expert) to to-the-point Simutrans programming questions, like the ones you've given for example isidoro and jamespetts.

What we are missing is the 3rd item. I think that might take you 30 minutes (= one day!) to accomplish. And I think, all other programmers would benefit a lot from it.
Bob Marley: No woman, no cry

Programmer: No user, no bugs



IgorEliezer

#9
Look at I've just found!

Coding rules
:arrow: http://www.simugraph.com/simutrans-web/en/history/coding_styles.txt

Found at: http://www.simugraph.com/simutrans-web/en/history/index.html

This could be improved and included into DevGuide, if Hajo doesn't mind...

(thanks to my memory  ::) )

isidoro

#10
Quote from: VS on December 21, 2008, 10:32:44 AM
Well, step 1 is then translation of all gib and setze to get and set!

This should be probably done in a period when nothing else changes. Because this changes everything.

With modern IDE refactoring tools, that wouldn't be so complicated.  It is more complicated to translate remarks, descriptions of functions and so on.  Sometimes, automatic translation doesn't even work for that, because "strasse" instead of "straße" or "fuer" instead of "für" or some casual short for a word are used...

On the other hand, now you can know what code is old or new at a glance...  ;)

EDIT: BTW, once you manage to translate the comments, Simutrans is well documented and you can easily guess what's going on.  A seasoned programmer would be able to contribute with little effort.


prissi

I am sure gib and setze are not the highest hurdles here. And the svn contains an entire folder documentations, including an updated coding styles. And there is a readme too.

Giving more hints on how to set up an evironment for compiling is pretty useless, since everyone has its on preferences. And if you really want to contribute, you should be able to set up a compiler.

(Nice that aparently people do not even look at stuff they download. :(


All this rules are written as the code should be. Simutrans does not
yet conform 100% to this rules, but it should.


1. General coding rules:
-----------------------

- Use always the simplest working solution.
  -> The solution must work, and should be safe and robust. Try to use the
     simplest (not shortest!) piece of code which gives the needed result.
  -> So called hacks and tricks most often break this rule.

- Use always the same name for the same thing (i.e. give variables with same
  semantics the same name)
  -> This rule tries to avoid confusion and reduces the amount of things
     one has to remember while coding

- Use meaningful names. Method names should describe actions (i.e.
  use "scrollbar_moved" instead of "scrollbar_callback"). Class names
  should be nouns, method names should be verbs or include action descriptions.
  -> A method named "holy_hand_grenade()" may be useful, but what does it do?
     Try to give the reader as much information as possible about what's going
     on there.
  -> Class names should be nouns because classes are static elements
  -> Method names should be verbs because methods are dynamic elements

  There are some standard prefixes used throughout the program:
   get_ gib_ return a value
   set_ setze_ will set a value
   is_ ist_ will test a conditions
  For new functions, the first (english) form should be used. Function names
  should never start with uppercase letters.

- Use const wherever possible
  -> This helps the reader of the program (he sees which values are intended
     not to be changed) and the compiler (to optimize the code)

- Keep as much class members as possible private
  -> This reduces dependencies between classes. Therefore the program
     can be changed easier and the probability of errors reduces.

- Always initialize all member variables in all constructors
  -> Even if it seems easy, often it is forgotten - particularly if
     a class has several constructors

- It is preferred to have class and member variables private and
  public gib_/setze_ methods instead of public variables.
  -> This allows adding actions to value changes and retrievals.
  -> Read the section about extern variables for more benefits of using
     getter/setter methods. There are strong advantages!

- Avoid public member variables. Never use "protected" variables, rather
  make the variable private and use public or proteted gib_xxx() and
  setze_xxx() methods.
  -> protected variables can be changed in subclasses. The super class
     doesn't see this changes and can't react to them. This is likely
     to produce errors and makes the code harder to maintain.
  -> sometimes it's neccesary to bind actions to value assignments to
     variables later on in development. Public variables don't support
     this change of protocol and impose much work on the programmer if
     such a change is needed later.
  -> (prissi:) However, do not hide too much. Especially with virtual
     functions the use of protected members is also advisable.

- Avoid extern variables. Global variables make programs harder to change
  and make some bugs harder to find. Sometimes it gets necessary to bind
  actions to variable access. Use getter/setter procedures and static
  variables instead.
  -> this rule reduces direct coupling and thus enhances the chance for
     reusing a component.
  -> using getter/setter methods allows to bind actions to read/write
     access later on
  -> using getter/setter methods allows checking for valid values in
     assignments
  -> using only one of getter/setter allows to make a variable read only or
     write only for other parts of the program. Read only is not the same as
     constant, and can't be replaced with a const vaiable. Write only is
     also not expressible with language features themselves.

- References are preferred instead of pointers.
  -> References can be NULL and add safety and robustness to a program.
     Many problems with pointers don't occur when references are used.
     Unfortunatley references can't be used alwys isntead of pointers.
  -> Don't complicate code. Use pointers if the use of references would
     complicate things.
  -> Also reference can hide the fact, that a variable is changed. Thus
     again, use const when possible.

- Avoid casts if possible.
  -> casts can lead to errors which are very hard to find, especially
     if pointers to onects are casted.
  -> try to use dynamic_cast<type>(expression) if you need to cast
     (even though this eats performance)

- Don't cast const'ness away. Use mutable copies of the objects or think
  about another design if you run into problems with const.
  -> Program maintainers and compiler rely on things declared const to be
     immutable. Both run into trouble if you cast const away.

- If you need to cast use dynamic_cast<type>() to get type checking support
  from the compiler.
  On static pointers, also a static_cast<type>() can do the trick.

- Avoid void * if possible. This is especially dangerous when used for
  pointers to objects, because the compiler can't call the destructor of the
  object through a void pointer. Also all type checks are impossible on
  void *. Use of void* is tolerated in C code, but not in C++ code.
  -> try using templates instead of void pointers.

- Keep code readable. Spaces and formatting help the reader. I.e. space
  between methods shows clearly the end of one method and the beginning
  of another. On the other hand spaces can destroy readability if used wrong.
  -> Use spaces where the visual separation of things reflects separate
     entities in the code.
  -> Unreadable code is hard to maintain. Time is a valuable resource.
     Spaces and newlines are cheap. Use the cheap resource to save the
     valuable.

- Avoid includes in header files. Use forward declarations
  "class xyz_t" where possible.
  -> This rule tries to reduce coupling of code and compile time.

- use inline methods just for very small methods (1 to 3 lines max.)
  -> This rule tries to reduce coupling of code and compile time.

- use the size defined type like sint8, sint16, sint32, sint64 and uint8,
  uint16, uint32 and image_id (for image numbers)
  Different compilers/platforms use different rules for values. If your code
  depends on signedness, write this explicitely down.
  Note, that this errors don't show up on your platform/with your compiler
  but perhaps only on your teammates systems. Be very careful about this
  because you can't test for this problems in your own development environment.
  i.e. Linux/PPC treats chars as unsigned, whereas Linux/Intel treats chars
  as signed values!
  -> This rule tries to increase robustness of the code
  There is one exections to this rule:
  If you really ever need to cast a pointer to an int, cast it to "long". All
  C compiler will guarantee, that a pointer fits into a long.

- take care of boundary violations. Simutrans offers bounds checked
  templates (arrays, vectors, lists). Use them where possible. If you have
  to use plain arrays, always double check the values. Never trust a
  parameter! The caller might be erroneous, or a dangling pointer trashed
  some memory. I feel urged to write: ever and always check index values
  before accessing a plain array.
  -> This rule tries to increase robustness of the code

- keep class interfaces minimal
  Classes should have only the minimal set of methods that are needed
  to cover all requirements. Convenience methods should go into other
  modules or subclasses.
  -> Small interfaces enhance the readability and understandability of
     a class.
  -> Small interfaces also enhance the reuseability.
  -> Separating convenience from core methods helps to understand the
     structure of the design.

  Try to comment all classes and methods in header files. Don't hesitate
  to write comments for variables, too.
  -> Class and method comments are found in the header files rather than
     the code files. Code files carry comments on algorithms and operations.

  Class comments should include:
  1.) Purpose of the class.
  2.) Relations of this class to others.
  3.) What are the duties of this class (what are not?)
  4.) Creator and creation date (if modified by someone else add a note too!)


  Method comments should answer the following questions:
  1.) What does this method do?
  2.) How does it do it?
  3.) Why is it done that way?
  4.) What is valid input (what not?)
  5.) What are the results for valid input
  6.) How does it react on invalid input?
  7.) In which context should/may/can't this method be used? (If appropriate)
  8.) Creator and creation data (if modified by someone else add a note too!)


  Class/Instance variable comments should state:
  1.) Purpose of this variable
  2.) Range of valid values, maybe a list of 'special' values if there are any
  3.) Creator and creation data (if modified by someone else add a note too!)


  I know, many existing things in Simutrans are not commented in full detail,
  but new things should be! Rather add coments on old parts than leave out
  comments on new parts, if you want to have consistency.


- Header comments: Include files which define classes do not need header
  comments, because the class comment can serve as a header comment.
  Other files should carry header comments like the example shown below:

  /* boden.cc                        <- name of the file
   *
   * Natur-Untergrund für Simutrans. <- Short description of file contents
   * Erstellt am ????                <- Creation date (if known)
   * Überarbeitet Januar 2001        <- Additional history information
   * von Hj. Malthaner               <- author/creator of the file
   */

  If you found an outdated version (very likely) it would be great if you
  update it.

2. Coding styles
----------------

Always use braces. Even is there is only one line in that block!
An example:

if(condition) {
   // do something here
}
else {
   // do something else here
}

Or K&R if you really like this more

if(condition) {
...
} esle {
...
}

No other styles of using braces are allowed. This rule applies to loops and
other compound statements, too.


Do not forget brackets along comparisons and use double spaces around
logical operators. Avoid spaces before the comparison operator:
if((i&3)==1   &&  ptr==NULL) {

You may also use double spaces after/before the brackets:
if(  (i&3)==1   &&  ptr==NULL  ) {

No space between if/while/for and bracket is allowed.

Use spaces in for loops like in ifs:
for(  int i=0;  i<10;  i++  ) {


Use spaces in parameters list. For example:

call(x, y, count); instead of call(x,y,count);


Also a space between type and pointer mark is preferred:
use char *bla_t::get_text() instead char* bla_t::get_text()

For function definitions, put the return type in the previous line:
const slist_tpl<const gebaeude_t *> *
stadt_t::get_all_buildings() const
{
...

Do not use macros; if possible use inlines.

If you use macros, then list all parameters like
#define bla(s,t) ((s)+(t))
and don't forget the brackets around each parameter! (Again, better use inline)


3. Tables and detailed information
----------------------------------

According to the rule "Use always the same name for the same thing" we
need a list of common names to avoid confusion. Unfortunately the program
was started with many german terms in use, so many of the names are german
names:

Preferred variable names:

Loop counters (int): i, j, n
Indices (int):          i, index, n
Coordinates:  pos (position), k (arbitrary coordinate)
Screen positions:       x, y (short form), xpos, ypos (long form, preferred)
Convoi: cnv
Vehicles: v
Rail signals:           sig
Rail blocks:            bs (obsolete)
Grounds:                gr (often also bd (from boden))
Roads:                  str
Railroads:              sch
Generic way:            weg
Buildings:              gb
Factories:              fab
UI components: komp, c (temporary component variables) seldom directly used
UI windows: ??? (win is preferred)
UI events:              ev
Button:                 button
Button lists/vectors:   buttons
Scrollable list:        scl
Temporary int value:    t
Temporary char value:   c
Temp. general value:    tmp
Temporary result:       r, res, result ('result' is preferred)


Variable pre-/suffixes:

Offsets to a base value: xxx_off


Method pre-/sufffixes:

Retrieving a member variable value: [obsolete: gib_xxx()] use get_xxx()
Setting a member variable value:        [obsolete: setze_xxx()] use set_xxx()
Adding a listener to a component:       add_listener(xxx_listener_t *)
Remove a listener from a component:     remove_listener(xxx_listener_t *)


Class per-/suffixes:

Standard class names get the suffix "_t" (for "Type")
Template classes get the suffix "_tpl" (for "template")
GUI (windows) classes carry a "_gui_t" suffix

Classes of the new, component-oriented UI carry a gui_ prefix instead
of the _gui_t suffix.


Written by Hj. Malthaner
Initial version: November 2000


MFC-coding styles:

For being able to compile simutrans with MSVC v6.00, some additional rules
are necessary: (these are more suggestions, since it does not compile with VC6.0)

1.
Change the following construct from:

class myclass {
    ...
        static const int MY_CONST = 77;
    ...
};

to:

class myclass {
    ...
        enum { MY_CONST = 77 };
    ...
};

Reason:
VC cannot compile the first. Both constructs archieve the same result.


2.
Do not use:

any_type *x = new any_type[0];

Reason:
VC code crashes when deleting a zero sized array.



4. How the UI works (prissi)
----------------------------

If you want to add a new dialoge, I strongly recommend to derive it from the
gui_frame class. Then add components out of the gui/components folder. You
will find almost all components there you could need. Scroll bars are best
used as scroll panes: the containing component will be clipped and can be
drawn as normal.

After initializing a component you have to add it to your dialog using
add_komponente(). Failing to do so will just not show it. Certain active
things like buttons and many more can give a feedback. Use action_listener
for them, you do not need to handle events for them yourself. Comboboxes
are an exception, since you have to close them, when you get a mouse click
event outside of them.

If you use only components from gui/components, you just have to init your
dialog and you are done, you do not need to define drawing or action
routines. It can be as easy as that.


Written by prissi
Initial version: June 2006


And then there is a readme.txt in trunk:


How to compile
--------------

Congratulations, you checked out the simutrans source. To compile it,
you have two options, either using Microsoft Visual C++ Express (which
is free in Version 7.0) or GCC.

To compile you will need the following libraries:
libz (http://www.zlib.net/)
libpng (http://www.libpng.org/pub/png/) for makeobj

For the recommended SDL-support you need
libSDL (http://www.libsdl.org/)
libSDL_mixer (link from the same page)

The link for allegro lib is:
http://www.talula.demon.co.uk/allegro/
or
http://alleg.sourceforge.net/index.de.html

To make life easier, you can follow the instructions to compile OpenTTD.
A system set up for OpenTTD will also compile simutrans without problems.

If you are on a MS Windows machine, download either MS VC Express or
MingW. The latter is easier to use as part of the DEV-C++ IDE, which
makes the installation of additional libraries like libz and libsdl and so
on very easy. However, to compile the command line is easier.

For all other systems, it is recommended you get the latest GCC and
matching zlib, and libpng and a game library. For unix system you may
have to use tools like apt-get or yast.

Check out the latest source from the SVN or check out a certain revision.
I recommend always to use the latest source, since it does not make any
sense to work with buggy code.


IMPORTANT:
----------

If you want to contribute, read the coding guidelines in
sim/documentation/coding_styles.txt


The following instructions are for GCC systems:
-----------------------------------------------

Go to Simutrans/sim.

Then copy the file sim/config.template to sim/config.default and edit the
file. You need to specify:
- frontend (gdi, allegro, sdl)
- color depth (usually 16)
- system (you should know it)

I recommend to uncomment #DEBUG=1 and #OPTIMISE = 1 (i.e. removing the #).

For allegro or libsdl you may need to define the path of the config file
(or at least on win98 and empty path).

Finally type make. If you want a smaller program and do not care about error
messages, you can comment out #DEBUG=1 and run strip sim resp. strip sim.exe
after compile and linking.

For users on window systems:
To debug, I recommend to run drmingw -i once in a shell. You will get a
caller history in case of an error. gdb does not really work well and is a
pain to use with the text interface.


The following instructions are for MS Visual C Express:
-------------------------------------------------------

For MS VC Express you have to hunt the matching zlib. Any version
which is compatible with VC will do. Take a look at the instructions for
compiling OpenTTD, which contains a libpng and a libz suited for
simutrans too:
http://wiki.openttd.org/index.php/MicrosoftVisualCExpress

You can compile without zlib, just make sure you disabled support for
compressed savegames in your simuconf.tab. But you will not able to
load compressed savegames then.

For debugging, you have to set the correct working directory, i.e. the
directory where the pak/ folders are located and use the -use_workdir
command line option.

Berlin, Mai 2007


isidoro

Quote from: prissi on December 21, 2008, 05:45:46 PM
I am sure gib and setze are not the highest hurdles here.

That's for sure.  If done, it should be done gradually.  Whenever a piece of code is altered, translate the comments, name of the function and main variables.  But that is a big effort to ask the people who can:  programmers with fluent knowledge of German and English...

I'm not a native speaker of neither, and know no German.  German people wouldn't forgive any of my translations...   ;)



Ormac

Quote from: Combuijs on December 21, 2008, 02:15:03 PM
What I had in mind is the following:
1) Descriptions how to compile the program (can be found in several forum topics)
2) Description of the Simutrans programming standard (there is one somewhere)
3) A small overview what each file (or set of files) is doing to get another programmer started. Should be no longer than one A4-page, if possible even shorter. There is no such thing now.
4) A collection of answers (mostly given by you as you are the expert) to to-the-point Simutrans programming questions, like the ones you've given for example isidoro and jamespetts.

What we are missing is the 3rd item. I think that might take you 30 minutes (= one day!) to accomplish. And I think, all other programmers would benefit a lot from it.


Vilvoh mentioned to me around November  in an email he sent me this little thing


Quote from: Vilvoh
BTW, I'm trying to write a short guide to introduce people in Simutrans code. In fact, it's a compilation of a set of articles from my blog and I've to translate them, yet. Anyway, when I have time I'll send you a preview of Dive in Simutrans (that's its name)

From what I guess it's a collection of articles from his blog about compiling code and I'm assuming he's needing to translate it into English for me first.

I have not yet seen a preview of it.
And I have not heard anything further on it from Vilvoh.

So I don't know If what he has is close to what your asking for or what sort of condition it's in.

Ormac 8)
Simutrans Reference Material Blog SRM very wet ink
Download Simutrans Reference Material from http://docs.simutrans.com

prissi

I enabled the sourceforge wiki for a wiki for programming simutrans code.
http://simutrans.wiki.sourceforge.net/

jamespetts

Prissi,

the wiki is very useful! Thank you.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.

prissi

So far I even did not complete copied in the readme that come with the svn check out though ...

Spike

#17
Quote from: IgorTekton on December 21, 2008, 03:00:52 PM
Look at I've just found!

Coding rules
:arrow: http://www.simugraph.com/simutrans-web/en/history/coding_styles.txt

This could be improved and included into DevGuide, if Hajo doesn't mind...

Sure, go ahead :) Some of the rules need to be updated, but the document might be a good start overall.

References can be NULL and ...

This definitely needs to read "cannot be NULL"

prissi

THis is already included. THat and the readme are just what this development wiki is made of.

Combuijs

Quotes from the coding rules

QuoteNames must be meaningful. Not i for an iterator but iter.

QuotePreferred variable names:
Loop counters (int):    i, j, n
Indices (int):    i, index, n

Isn't that a contradiction? Or am I missing something?

And by the way: very useful information. I hope it will be extended in the future.
Bob Marley: No woman, no cry

Programmer: No user, no bugs



VS

Iterator is a special kind of object which is like an oop-type head for an array or something. Typically you use iterators to hide what operations and data structures are used - iterators are used all the same. Usually they get overloaded ++ operator to advance and overloaded typecast where they return the "current" value ... or something similar. Then you just ask the container for iterator and do the for-loop with it. Hence the need to distinguish between plain int and iterator.

My projects... Tools for messing with Simutrans graphics. Graphic archive - templates and some other stuff for painters. Development logs for most recent information on what is going on. And of course pak128!

prissi

Well, there is no need for the compiler. But I thing the iterator with ++ overloaded is one of the very bad things of OOP, i.e. hiding what actually goes on. i.next() is imho much more ovious than ++i. (Not to mention that ++i and i++ may be different in case of iterators ... )

This is one reason I prefer iter.next() of simutrans. (And for the same reason those cout >> i >>str >> "bal"; printf-replacement is also not to my personal liking.)