Skip to main content
Topic: Understanding the workings of ware_t (Read 4885 times) previous topic - next topic

Understanding the workings of ware_t

I am currently working on the new revenue system for Simutrans-Experimental. Because, in the system that I am developing, the speed bonus will depend on the average speed of vehicles on the line (or in the convoy if there is no line), and the total distance of the journey that the packet of goods (i.e., the ware_t object), rather than the distance between hops (the idea is that the relationship between the speed and comfort (if applicable) of the journey and its length are important in calculating the revenue.

What I have tried to do is add a new accumulated_distance field to the ware_t cl****, calculate the euclidean distance every hop, and add that distance to ware_t::accumulated_distance, then, when it comes time for it to be unloaded, use that distance to calculate the revenue, rather than calculating the revenue every hop. I have changed the merging code so that only ware_t instances from the same origin halt will merge together, and set accumulated_distance and the origin halt to save.

The problem that I am having is that, for some reason that I cannot fathom, accumulated_distance is resetting after every hop. The only accumulated_distance = 0 lines that I have in the code are in the constructor, the rdwr() method (for loading and saving), and in a void reset_accumulated_distance() method, which is never called. The only thing that I can think is causing that is that all of the ware packets are somehow destroyed and re-created at each halt; but, I cannot see how that can be, since the origin data is saved.

Can anyone with intimate knowledge of the code point me in the right direction?
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.

Re: Understanding the workings of ware_t

Reply #1
total distance of the journey that the packet of goods (i.e., the ware_t object), rather than the distance between hops
I guess that you aware of the recent:
Code: (simuconf.tab) [Select]
# three modes (default = 0)
# 1: the payment is only relative to the distance to next interchange, 2 to the trips destination (default is distance since last stop)
pay_for_total_distance = 0
Quote
(the idea is that the relationship between the speed and comfort (if applicable) of the journey and its length are important in calculating the revenue.
Of course, that change still doesn't use real speed and any QoS rating. There have been several discussions regarding approaches to a more detailed revenue system.

One idea (mine?) was to use - per packet - a base value and a dynamic value (some kind of QoS metric), the latter deteriorating over time, depending on delays and low comfort rating. Another value could be attached to each convoy, measuring its transport performance in some kind of metric (as opposed to the revenue that it generates, which can even be negative with the settings above).

Oh, and if you are going to change revenue to use QoS, why shouldn't routing be changed to use QoS and the cost, too? :)

Quote
The only thing that I can think is causing that is that all of the ware packets are somehow destroyed and re-created at each halt; but, I cannot see how that can be, since the origin data is saved.
Try vereinige_waren() - it tries to merge the packet with one that is already waiting at the stop.

Re: Understanding the workings of ware_t

Reply #2
Whoami,

thank you for your reply. I am indeed aware of the pay_for_total_distance setting - in fact, it is not used in Simutrans-Experimental, because it is unrealistic: in reality, people pay for the route distance, not the straight line distance between their origin and destinations. I am aware that this was introduced to prevent an exploit, but I consider it as going too far the other way, and making the game unrealistic  most of the time to avoid a problem that only happens occasionally. My plan to deal with this is instead to have limit, so that, if the journey distance is more than X times the straight line distance, the revenue will be limited to X times the straight line distance. X might be set to decrease the longer the journey, such that one might be able to earn revenue for a route distance thirce as long as the straight line distance for a very local journey, but only 1.3 times as long for a very long distance journey, with a sliding scale in between.

I do indeed plan to use real speed, not the maximum speed of the vehicle: I already have working code which will give the average speed of each convoy and each line, and display it on the convoy's and line's statistics graph. The plan is to use the speed bonus code, but with those average speeds, rather than the maximum speeds. The values in speedbonus.tab will of course have to be adjusted downwards considerably. The idea is to calculate the revenue for each leg of the journey (i.e., the part of a journey between each loading and unloading of a means of transport), rather than for each hop, which is why I need to accumulate the distance so far travelled in the ware_t cl****. I have already changed the vereinige_waren() method to stop it from merging packets with different origins as well as different destinations, which should make sure that the accumulated distance value remains accurate (because all packets coming from the same origin taking the same route on the same leg of their journey will have travelled the same distance). However, the problem is not that the packets are being merged with new joining packets, but that all of the values in the packets are reset to 0 somewhere along the way - every single one, without exception. I cannot track down what is causing that behaviour.

The advantage of that method over the method that you suggest is that it only requires the revenue calculation to be made once, whereas your method would require the revenue calculation to be made lots of times, which would be computationally expensive. The distance per hop is already calculated for the average speed timings, so that value can easily be re-used for the accumulated distance. The idea, incidentally, is to base the revenue on the last month's average speed per line (or convoy, if the convoy is not part of a line), not the speed of each individual journey, for two reasons: (1) because it is more realistic (people do not negotiate the price of their tickets at the end of the journey after they have found out how long that it takes; instead, ticket prices are based on what the transport company calculates that people will be prepared to pay, based on their experiences of past performance), and (2) because it makes it more comprehensible for the player, who can see the statistics and predict in advance the basis for the revenue calculations.

I do not, incidentally, plan to have a variable somewhere representing "quality of service" in the abstract, since this would not be a very meaningful value: instead, I intend to use average speed, comfort, catering level (or the provision of travelling post offices for mail traffic) for vehicles, and the ratio of unhappy to happy p****engers for stations as individual metrices which all combine together to produce (1) the revenue, and (2) choices about which routes to use. This is, again, both more realistic and more comprehensible to a player, who can see graphs representing the values and understand clearly how each relates to choices made in the game, rather than trying to work out how to influence a generic "quality of service" metric.

Finally, as to the cost, I am not sure that I understand that suggestion: do you mean the price charged by the player's transport company for transporting the goods/p****engers? If so, I am not planning to add that. The reason is that, if price were to be a factor, players would have to have the ability to set the price manually, as it would create bizarre and perverse incentives if any given route could, under any circumstances, lose traffic as a result simply of being improved, without the player having any say in the matter. However, that would introduce an unacceptably high degree of micromanagement, with players effectively having to take constant number-crunching decisions to balance price, profit margins and service quality. Simutrans has always worked on the basis - perfectly realistically - that the player is the overall manager of the transport company, and more junior staff do the number crunching, and always set the prices to the optimum level to balance market share with profit margins, that being simulated through the differential price paid for different distances and different qualities of transport. That model I intend to preserve with Simutrans-Experimental.

But, returning to the original topic, do you (or anyone else) have any idea why my accumulated_distance variable seems to be resetting to 0 all the time?
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.

Re: Understanding the workings of ware_t

Reply #3
because it is unrealistic: in reality, people pay for the route distance, not the straight line distance between their origin and destinations.
There have been earlier discussions about this. In reality, transport companies may charge more for faster connections, but not all people may choose these (depending on whether they can afford them), and may instead trade travelling time for cost.

Quote
But, returning to the original topic, do you (or anyone else) have any idea why my accumulated_distance variable seems to be resetting to 0 all the time?
IIRC, vereinige_waren() does not move the packets to the station, but creates new ones (or merges them with existing ones). I don't know why it is handled this way (perhaps because it is easier to hand over the contents instead of correctly keeping track of references to each ware_t instance), but the copying of packets may neglect the data that you added.

Re: Understanding the workings of ware_t

Reply #4
Whoami,

thank you again for your reply :-) I explained why adding in costings would create too much micromanagement in the last post. As to the ware_t mystery, still no nearer solving it: the problem is not that data is lost on transfer (i.e., when the packets are loaded and unloaded from vehicles), but at each hop. The way that it should work is that, for a packet travelling from station A to station D on one convoy, which also calls at intermediate stations B and C, at station B, the distance between A and B is measured and added to the accumulated_distance value, then at station C, the distance between B and C is measured and added to the accumulated_distance value, and finally at station D the distance between stations C and D is measured and added to the accumulated distance value, whereupon the revenue for that trip is calculated using that value, and the value is then reset to 0.

What actually happens is that the accumulated distance value is set at station B to the distance between stations A and B, but by the time that the convoy gets to station C, the value has mysteriously reset to 0. It does this in every case without fail. I cannot see anything in the code that makes new copies of each packet at each stop (although perhaps I am missing something), nor code that copies everything but the accumulated distance variable. In any event, I do not think that the contents are copied, because ware_t does not define an "=" operator. The vereinige_waren() method copies pointers to instances of ware_t, and merges them if they have the same destination (in standard Simutrans) or the same origin and destination (in Simutrans-Experimental).
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.

 

Re: Understanding the workings of ware_t

Reply #5
You do not need a = operator, if simple copying is ok, c++ will copy the whole data. You can define one private and then see where all copying occurs.

Re: Understanding the workings of ware_t

Reply #6
Prissi,

thank you for replying :-) What do you mean by "you can define one private and then see where all copying occurs" - ****ign one private what?
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.

Re: Understanding the workings of ware_t

Reply #7
I interpret that as "One overloaded operator whose doings include some kind logging."

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!

Re: Understanding the workings of ware_t

Reply #8
Ahh, I see. I'll have a look for that. Thank you. Yes, I'd forgotten about the default shallow copy.

Edit: Finally solved it! I had not twigged that vehikel_t::fracht was not a collection of pointers to instances of ware_t objects, but a collection of those objects themselves - therefore, when I declared ware_t ware = iter_cargo.get_current(); and then ****igned to ware_t, I was not actually changing the data in the collection object at all! Changing the code to iter_cargo.access_current().add_distance(journey_distance); worked. Thank you all for the help :-)
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.