MAP REWRITE patch 0.9

Forum for technical discussions regarding development. If you have a general suggestion, problem or comment, please use one of the other forums.

Moderator: OpenTTD Developers

User avatar
mkxx
Engineer
Engineer
Posts: 65
Joined: 06 Jun 2005 22:15
Location: Czech Republic, Prague

Post by mkxx »

I know, but in GetRailType(...) you still use GET_M2(...) or _m[tile].tt.rail.type

If we replace all _m[tile].m2 occurences with GET_m2(...), we can then alter data structure (and GET_M2) with no pain. (Or with less pain than without GET_M2)
ValHallA|SW
Engineer
Engineer
Posts: 36
Joined: 24 Aug 2003 18:10

Post by ValHallA|SW »

It is unnecessary. BEFORE the switch to the new map array, GetRailType(...) should be implemented instead of GET_M2(...).

GET_M2(...) adds ABSOLUTELY nothing, as you can change it to GetRailType with the same effort, giving much more readable code. Give me one good reason to use GET_M2 instead of GetRailType?
User avatar
mkxx
Engineer
Engineer
Posts: 65
Joined: 06 Jun 2005 22:15
Location: Czech Republic, Prague

Post by mkxx »

ValHallA|SW: 'Cause you are not changing only GetRailType but you change A LOT (100...200) occurences of _m[tile].m2 -> you think that better work is to change all of them manually? (Yes, we need to change them manually. But until we change them manually and we do not have GET_M2(), we will not be able to run ottd 'cause of incompatible data structures)
ValHallA|SW
Engineer
Engineer
Posts: 36
Joined: 24 Aug 2003 18:10

Post by ValHallA|SW »

mkxx wrote:But until we change them manually and we do not have GET_M2(), we will not be able to run ottd 'cause of incompatible data structures)
Why not? While the change is happening ottd will still use the old data structure and both GetRailType() and _m[tile].m2 will work. Before the new map array is introduced, all changes will have to be made.

Your step is a pretty useless one imnsho, and would only be useable if the new map array would arrive really soon.


and it won't :p
egladil
OpenTTD Developer
OpenTTD Developer
Posts: 188
Joined: 07 Nov 2005 17:10
Location: Sweden

Post by egladil »

Yes, it is better to change them all manually. There are many reasons for this. The most obvious one is that it would make the code much more easy to read.

-edit-
Removed since i didn't see ValHallA|SW post until after i pressed submit.
Last edited by egladil on 08 Dec 2005 22:37, edited 1 time in total.
User avatar
Graphite
Engineer
Engineer
Posts: 84
Joined: 17 Nov 2005 20:56
Location: Netherlands
Contact:

Post by Graphite »

Right... regardless of the implementation, at some point _m[tile].tt.rail.type will have to be referenced. From what I can tell the differences between mkxx's suggestion and the others are the following:

mkxx:
- uses two functions containing huge switch-statements that select the correct return-value based on a parameter, thus centralising any access to _m[tile].tt.rail.type and any other map-implementation specific data.
- if the internal representation is changed, the respective portions of the switch-statements are changed to fit the new representation.

others:
- use lots of simple functions with descriptive names that centralise any access to _m[tile].tt.rail.type and any other map-implementation specific data.
- if the internal representation is changed, the respective functions are changed to fit the new representation.

See the pattern, mkxx? Both centralise any reference to the internal representation of the map-array into a single location. Yours are in two big functions, theirs are in lots of tiny ones. The main difference between the two is that their version uses functions with descriptive names, so wherever they are used, you can immediately see what they're to access. This is NOT the case with your solution.

From a practical point of view, the other solution is faster too as the overhead for the function call is the same, but in your case it has to process this huge switch-statement as well.
A computer scientist is someone who, when told to "Go to Hell," sees the "go to," rather than the destination, as harmful.
User avatar
Korenn
Tycoon
Tycoon
Posts: 1735
Joined: 26 Mar 2004 01:27
Location: Netherlands
Contact:

Post by Korenn »

mkxx wrote:Yes :o) You are near :))
[..code..]
You do not have to touch whole sourcecode, couse everywhere you have only GET_M2(tile). Or you can then replace GET_M2(tile) with proper name of desired variable ("_m[tile].tt.rail.type" for example)

(New data structure is not correct, it was only an example)
but we WANT to touch the whole sourcecode, because it's a whole lot of chaotic crappy spaghetti at the moment. You're missing a large part of the point of the map rewrite.
Yes a new map array needs to be introduced, BUT at the same time, the code accessing the map array needs to be made more readable.

The net result of your code is that only the bits accessing the arrays directly (so _m) are changed, but the bit shifting and other nonsense in there is not changed at all. Which makes your code more or less a waste of time.

[edit: typo]
Last edited by Korenn on 08 Dec 2005 23:38, edited 1 time in total.
User avatar
LordOfThePigs
Route Supervisor
Route Supervisor
Posts: 435
Joined: 01 Jul 2004 10:28
Location: Jura/Switzerland

Post by LordOfThePigs »

The point is, this has been discussed at the last developper meeting, and the approach chosen has been unanimously accepted by all coders. And I guess OTTD coders are pretty experienced.

On a final note, I'd like to mention that the code is *already* in the process of beeing rewritten as decided. There is still a lot of work to do, but to the code still works and compiles. The snippet I posted on the first page is an actual bit of code that is waiting to be commited into SVN.

Beleive me. This matter has been discussed thouroughly and the way the devs have chosen is clearly the best.

And Korenn is perfectly right!

@graphite: The point isn't there. What we want isn't only to abstract the access to the map array from it's internal structure, but also the whole code. Right now, huge portions of OTTD's code are totally linked to internal structure of the map array (through weird bit-masking and bit-shifting and all sorts of other crappy tricks). Whole loops depend on that kind of nastly stuff to run correctly. All that code HAS to be rewritten, one day or another, and mkxx way doesn't solve the problem.
Sometimes I'm told "Brilliant"...
Sometimes I'm told "Charming"...
And Often I'm told "Shut Up"!
User avatar
Brianetta
Tycoon
Tycoon
Posts: 2566
Joined: 15 Oct 2003 22:00
Location: Jarrow, UK
Contact:

Post by Brianetta »

mkxx wrote:see Brianetta's post on first page.
We need temporary RAW getter and setter for introduce new map array structure.
I never once said temporary. I think direct map access should be avoided if at all possible. Encapsulation is a Good Thing - I was taught that at university, and I still think that reasoning is sound.

One day, in the distant future, the map might be rewritten again. This would be much less painful if we don't reverse the good encapsulation work.
PGP fingerprint: E66A 9D58 AA10 E967 41A6 474E E41D 10AE 082C F3ED
User avatar
Darkvater
Tycoon
Tycoon
Posts: 3053
Joined: 24 Feb 2003 18:45
Location: Hong Kong

Post by Darkvater »

mkxx wrote:

Code: Select all

Get_M2(tile) {
   switch(GetTileType(tile)) {
      case MP_GROUND: return _m[tile].tt.ground.foo | (_m[tile].tt.ground.bar<<4); break;
      case MP_WATER: return _m[tile].tt.water.barfoo; break;
      ...
   }
}
You do not have to touch whole sourcecode, couse everywhere you have only GET_M2(tile). Or you can then replace GET_M2(tile) with proper name of desired variable ("_m[tile].tt.rail.type" for example)
Something like that will kill performance, so it is not going to happen.

The question is whether we want Get/Set/Is-sers for everything or something like tile.track_info[1].reserved is enough. Yes, getsetters are nicer and you can go wild with assertions (most of them useless). Once the format is fixed the second, direct access is enough (you can freely increase 'reserved' size without changing anything else).
However if the format changes, getset is a lot easier to maintain. But do we really want ~200-300 accessor functions (tile.h from map/ branch, with Get/Set/Is for every member of the Tile struct)? It is a valid question.
TrueLight: "Did you bother to read any of the replies, or you just pressed 'Reply' and started typing?"
<@[R-Dk]FoRbiDDeN> "HELP, this litte arrow thing keeps following my mouse, and I can't make it go away."
User avatar
mkxx
Engineer
Engineer
Posts: 65
Joined: 06 Jun 2005 22:15
Location: Czech Republic, Prague

Post by mkxx »

to Darkwater: this was thought like temporary solution. When devs will change OTTD data structure, it will take lot of time to rewrite all accessors like IsTileType, GetTileTrack, SetGroundType, GetFooBar, SetBar, ...
for use new data structure (that means: not "GB(_m[t].m3,0,3)", but _m[t].tt_bar.foo). Until the code will be compeltely rewritten to be compatible with new data structure, nobody will be able to compile OTTD source.
- For this state of map_rewrite, we should replace all direct accesses to map array (= occurences of _m[t].xx in accessors) with one global accessor (like GetVarInOldMapStyle(t,MAP_M3)).
(GetVarInOldMapStyle returns variable, which looks like old m3 variable. But that variable is build from new data structure vars (like "return _m[t].bar << 3 || _m[t].foo;")).
Then programmers need to replace occurences of "GetVarInOldMapStyle" uses with direct accesses to new data structure ("GetVarIn...(t,MAP_M3)" => "_m[t].foo.bar.some_value").

- I understand that rewrite all accesses to this global wrapper - as I said before - will take A LOT of time. But I have written simple application, which does this action for us automatically. (That means: replacing all occurences of "_m[t].xx" to something like "Get/SetVarInOldMapStyle(...)" will take maximally 10minutes.) Then we need only to maintain functions Get/SetVarInOldMapStyle, which sets/gets variable in same syntax like in old map array. Advantage of this global wrapper is when ottd-team will change data structure, devs need to rewrite only one function (that wrapper) and OTTD runs normally (little bit slower, 'cause of wrapper). But this is not final state. Then we need to manually rewrite all occurences of Get/SetVarInOldMapStyle with direct access (without wrapper) to new data structure. After source code rewrite - when new data structure is used (and no m1,m2,... variable is demanded), the wrapper Get/SetVarInOldMapStyle should be removed.

Sounds little bit crazy, but it saves lot of time and work.
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

mkxx wrote:When devs will change OTTD data structure, it will take lot of time to rewrite all accessors like IsTileType, GetTileTrack, SetGroundType, GetFooBar, SetBar, ...
Until the code will be compeltely rewritten to be compatible with new data structure, nobody will be able to compile OTTD source.
WRONG!![0] The accessors will change *as* the data structure changes. That's why they exist. To hide the actual structure from the program. If you have to hide the data structure from the accessors, then they aren't doing their job properly, and the program might as well use the sub-accessors instead.

[0] Be thankful there's no [blink] tag; I'd be using it if it existed. Anything to make mkxx see this word.
mkxx wrote:(GetVarInOldMapStyle returns variable, which looks like old m3 variable. But that variable is build from new data structure vars
How does this make it unnecessary to change the accesses in-sync with the data-structure changes? Sure, the accesses are only in one function, but they still have to be changed in-sync.
And how do you eliminate the massive, performance killing switch statement? (The only way you're going to satisfy me on this one is to post (pseudo)code for GetVarInOldMapStyle.)
mkxx wrote:like "return _m[t].bar << 3 || _m[t].foo;"
That code will never work. Go away. And don't come back until you can explain what's wrong, and how to fix it.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
richk67
Tycoon
Tycoon
Posts: 2363
Joined: 05 Jun 2003 16:21
Location: Up North
Contact:

Post by richk67 »

DaleStan wrote:Go away. And don't come back until you can explain what's wrong, and how to fix it.
Way, way, way out of order.
OTTD NewGRF_ports. Add an airport design via newgrf.Superceded by Yexo's NewGrf Airports 2
Want to organise your trains? Try Routemarkers.
--- ==== --- === --- === ---
Firework Photography
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Just to clarify, I'm not talking about the variable widths there.
It is perfectly valid C, and I know what it does, I just fail to comprehend how it could be useful. And I stand by my statement, at least until someone can explain how that construct is useful.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
ebik
Engineer
Engineer
Posts: 83
Joined: 19 Jul 2005 08:14
Location: Prague, Czech Republic

Post by ebik »

DaleStan wrote:Just to clarify, I'm not talking about the variable widths there.
It is perfectly valid C, and I know what it does, I just fail to comprehend how it could be useful. And I stand by my statement, at least until someone can explain how that construct is useful.
The only usefullness of what mkxx proposed is to introduce new data structures now, instead of waiting after all the code is purified. (I don't know how it will do with loadgame (i didn't see the code yet...), but other things should go well). So developers waiting for new map array can start their work sooner !, while the others will be hunting and killing the temporary getters and setters.
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

I was not talking about mkxx's concept either. (Well, I was other places, but not there.)

I was talking about the "return _m[t].bar << 3 || _m[t].foo;" statement.

It is valid, but it has no logical meaning.
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
ebik
Engineer
Engineer
Posts: 83
Joined: 19 Jul 2005 08:14
Location: Prague, Czech Republic

Post by ebik »

Sorry, I just did wrong quotation.

And double sorry that I did not see New Map Rewrite effort thread before.
User avatar
Korenn
Tycoon
Tycoon
Posts: 1735
Joined: 26 Mar 2004 01:27
Location: Netherlands
Contact:

Post by Korenn »

DaleStan wrote:I was not talking about mkxx's concept either. (Well, I was other places, but not there.)

I was talking about the "return _m[t].bar << 3 || _m[t].foo;" statement.

It is valid, but it has no logical meaning.
if you really want to nickpick like that, yes it does have logical meaning. shifting by 3 bits can mean you shift out 3 bits.
so then it would be equivalent to

return _m[t].bar & 0x1F || _m[t].foo

if _m[t].bar is an 8 bit variable.
Still horrible style, but it definitely has logical meaning. So go away and come back when you've learned some manners.
User avatar
prissi
Chief Executive
Chief Executive
Posts: 647
Joined: 15 Nov 2004 19:46
Location: Berlin, Germany
Contact:

Post by prissi »

Just to point to the oviously not really clear thing (although it should burn in your eyes; even more since crappy compilers accept this without warnings):

return _m[t].bar << 3 || _m[t].foo;

is equal to

return (_m[t].foo!=0);

due to the accidental use of the logical or which has only 0 and not zero (most compiler reutrn 1, few -1) here. Since the lower bits of the shifts are zero, most compilers that are not completely draindead will remove the first part.

Not complety bad, but still risky is the use of the shift operator without brackets around. Especially next to an arithmetic or invertation they will do domething completely different.

And now, back to topic ...
DaleStan
TTDPatch Developer
TTDPatch Developer
Posts: 10285
Joined: 18 Feb 2004 03:06
Contact:

Post by DaleStan »

Korenn wrote:so then it would be equivalent to

return _m[t].bar & 0x1F || _m[t].foo
No, that's just a proof that it is valid. To prove "logical meaning", you have to come up with a situation where that would be a useful operation.

prissi: Sorry, no. _m[t].bar<<3 is not guaranteed to be 0. It's equivalent to "return (_m[t].bar<<3)!=0 || _m[t].foo!=0;"
To get a good answer, ask a Smart Question. Similarly, if you want a bug fixed, write a Useful Bug Report. No TTDPatch crashlog? Then follow directions.
Projects: NFORenum (download) | PlaneSet (Website) | grfcodec (download) | grfdebug.log parser
Post Reply

Return to “OpenTTD Development”

Who is online

Users browsing this forum: No registered users and 2 guests