Skip to content

Passenger and mail generation

MatthewForrester edited this page Nov 22, 2020 · 18 revisions

The passenger and mail generation code is found in simworld.cc.

Calling code

In a normal game it is called by this function:

void *step_passengers_and_mail_threaded(void* args)

That function initializes threads, including ensuring that the random seed for each thread is network-safe. The comments note that

The generate passengers function is called many times (often well > 100) each step; the mail version is called only once or twice each step, sometimes not at all.

The actual passenger and mail generation code is called by one of two loops, selected by a complex series of preprocessor branches. If I have followed then the paths correctly, then if the code is not in FIXED_PASSENGER_NUMBERS_PER_STEP_FOR_TESTING mode, this loop does the calling:

		for (uint32 i = 0; i < 2; i++)
		{
			karte_t::world->generate_passengers_or_mail(goods_manager_t::passengers);
			karte_t::world->generate_passengers_or_mail(goods_manager_t::mail);
		}

karte_t::generate_passengers_or_mail

Declaration

sint32 generate_passengers_or_mail(const goods_desc_t * wtyp);

So this function returns a signed 32-bit integer [why? an error code?]

It is passed a single parameter to determine whether it is dealing with passengers or mail. Then is a pointer labelled as wtyp, which you would expect to mean 'way type', but that makes no sense here. As the data type of the point is goods_desc_t, perhaps it originally meant `Wagen Typ' (vehicle class)?

The pointer is defined as const so that the function can access the goods type, but not modify it.

Definition

As an appetizer, some mechanism for recording statistics needs to know whether the function is being used for passengers or mail.

const city_cost history_type = (wtyp == goods_manager_t::passengers) ? HIST_PAS_TRANSPORTED : HIST_MAIL_TRANSPORTED;

Now we start with the important stuff. We generate the size of the passenger or mail packet:

const uint32 units_this_step = simrand((uint32)settings.get_passenger_routing_packet_size(), "void karte_t::generate_passengers_and_mail(uint32 delta_t) passenger/mail packet size") + 1;

This implies that the loop calls this function once for each packet. [Why is it handled as a loop rather than processing batches of packets?]

Then,

	// Pick the building from which to generate passengers/mail
	gebaeude_t* gb;

This declares and initializes a variable gb of type gebaeude_t, presumably a building.

	if(wtyp == goods_manager_t::passengers)
	{
		// Pick a passenger building at random
		const uint32 weight = simrand(passenger_origins.get_sum_weight() - 1, "void karte_t::generate_passengers_and_mail(uint32 delta_t) pick origin building (passengers)");
		gb = passenger_origins.at_weight(weight);
	}

That variable is filled with a building chosen at random. The maximum value of the random number is drawn from passenger_origins, which is [possibly] a pointer to a weighted vector template of all buildings. A vector is a variable-length array; I do yet understand in what sense it is "weighted". This template is used to hold a number of the game's key lists (all buildings and all cities) and appears to be one of the more low-level parts of the code. Hopefully the random number is something like an offset to an array of building co-ordinates? Also, what is get_sum_weight()?

	else
	{
		// Pick a mail building at random
		const uint32 weight = simrand(mail_origins_and_targets.get_sum_weight() - 1, "void karte_t::generate_passengers_and_mail(uint32 delta_t) pick origin building (mail)");
		gb = mail_origins_and_targets.at_weight(weight);
	}

	stadt_t* city = gb->get_stadt();

	// We need this for recording statistics for onward journeys in the very original departure point.
	gebaeude_t* const first_origin = gb;

	if(city)
	{
		// Mail is generated in non-city buildings such as attractions.
		// That will be the only legitimate case in which this condition is not fulfilled.
#ifdef MULTI_THREAD
		int mutex_error = pthread_mutex_lock(&karte_t::step_passengers_and_mail_mutex);
		assert(mutex_error == 0);
		(void)mutex_error;
#endif
		city->set_generated_passengers(units_this_step, history_type + 1);
		add_to_debug_sums(5, units_this_step);
#ifdef MULTI_THREAD
		mutex_error = pthread_mutex_unlock(&karte_t::step_passengers_and_mail_mutex);
		assert(mutex_error == 0);
		(void)mutex_error;
#endif
	}