Skip to content

Commit

Permalink
Switch the routing method for goods category
Browse files Browse the repository at this point in the history
  • Loading branch information
teamhimeh committed Jan 5, 2025
1 parent 96ab2bc commit 2626cf1
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 93 deletions.
4 changes: 2 additions & 2 deletions dataobj/settings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,8 @@ settings_t::settings_t() :
citycar_route_weight_speed = 0;

advance_to_end = true;
first_come_first_serve = false;
MEMZERON(is_time_based_routing_enabled, 256);
goods_routing_policy = GRP_NF_RC;
waiting_limit_for_first_come_first_serve = 500000;

routecost_wait = 8;
Expand Down Expand Up @@ -1658,7 +1658,7 @@ void settings_t::parse_simuconf( tabfile_t& simuconf, sint16& disp_width, sint16
citycar_route_weight_speed = contents.get_int("citycar_route_weight_speed", citycar_route_weight_speed);

advance_to_end = contents.get_int("advance_to_end", advance_to_end);
goods_routing_policy = (goods_routing_policy_t)contents.get_int("goods_routing_policy", goods_routing_policy);
first_come_first_serve = contents.get_int("first_come_first_serve", first_come_first_serve);
waiting_limit_for_first_come_first_serve
= contents.get_int("waiting_limit_for_first_come_first_serve", waiting_limit_for_first_come_first_serve);

Expand Down
20 changes: 2 additions & 18 deletions dataobj/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,6 @@ struct citycar_routing_param_t
sint16 weight_speed;
};

// The policy of how to route and loads the goods at stops.
enum goods_routing_policy_t {
// The goods routing is based on route cost.
// At stops, the goods to the nearest destination are loaded first.
GRP_NF_RC = 0,

// The goods routing is based on route cost.
// At stops, the goods are loaded in the order of the arrival.
GRP_FIFO_RC = 1,

// The goods routing is based on the estimated time to reach the destination.
// At stops, the goods are loaded in the order of the arrival.
GRP_FIFO_ET = 2,
};

/**
* Game settings
*/
Expand Down Expand Up @@ -346,7 +331,6 @@ class settings_t
// The flag whether the time based goods routing is enabled for the goods.
// The array index is the goods category index.
bool is_time_based_routing_enabled[256];
goods_routing_policy_t goods_routing_policy;

// When the amount of waiting goods/passengers exceeds this value,
// goods are loaded with "nearest first" policy to reduce the calculation load.
Expand Down Expand Up @@ -713,8 +697,8 @@ class settings_t

bool get_advance_to_end() const { return advance_to_end; }
void set_advance_to_end(bool b) { advance_to_end = b; }
goods_routing_policy_t get_goods_routing_policy() const { return goods_routing_policy; }

bool get_first_come_first_serve() const { return first_come_first_serve; }
uint32 get_waiting_limit_for_first_come_first_serve() const
{ return waiting_limit_for_first_come_first_serve; }

Expand Down
2 changes: 1 addition & 1 deletion gui/halt_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,6 @@ void gui_halt_detail_t::update_connections( halthandle_t halt )
new_component_span<gui_label_t>("Direkt erreichbare Haltestellen", 2);

bool has_stops = false;
const bool is_tgbr_enabled = world()->get_settings().get_goods_routing_policy() == goods_routing_policy_t::GRP_FIFO_ET;

for (uint i=0; i<goods_manager_t::get_max_catg_index(); i++){
vector_tpl<haltestelle_t::connection_t> const& connections = halt->get_connections(i);
Expand All @@ -683,6 +682,7 @@ void gui_halt_detail_t::update_connections( halthandle_t halt )
sorted.insert_unique_ordered(conn, gui_halt_detail_t::compare_connection);
}
}
const bool is_tgbr_enabled = world()->get_settings().get_time_based_routing_enabled(i);
FOR(vector_tpl<haltestelle_t::connection_t>, const& conn, sorted) {

has_stops = true;
Expand Down
4 changes: 2 additions & 2 deletions gui/route_search_frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ void route_search_frame_t::append_connection_row(haltestelle_t::connection_t con
// construct weight text
char text[16];
uint32 weight;
if( world()->get_settings().get_goods_routing_policy()==GRP_FIFO_ET ) {
// weight is in ticks. We have to convert it to the OTRP departure time unit.
if( world()->get_settings().get_time_based_routing_enabled(0) ) {
// When TBGR is enabled for pax, weight is in ticks. We have to convert it to the OTRP departure time unit.
weight = (uint64)connection.weight * world()->get_settings().get_spacing_shift_divisor() / world()->ticks_per_world_month;
} else {
// weight is in route cost.
Expand Down
6 changes: 2 additions & 4 deletions gui/schedule_gui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1271,14 +1271,12 @@ void schedule_gui_t::extract_advanced_settings(bool yesno) {
bt_transfer_interval.set_visible(yesno);
lb_departure_slot_group.set_visible(yesno);
departure_slot_group_selector.set_visible(yesno);
lb_tbgr_waiting_time.set_visible(yesno);
numimp_tbgr_waiting_time.set_visible(yesno);

const bool coupling_waytype = schedule->get_waytype()!=road_wt && schedule->get_waytype()!=air_wt && schedule->get_waytype()!=water_wt;
bt_wait_for_child.set_visible(coupling_waytype && yesno);
bt_find_parent.set_visible(coupling_waytype && yesno);
bt_reverse_convoy.set_visible(coupling_waytype && yesno);
bt_reverse_coupling.set_visible(coupling_waytype && yesno);

const bool is_tbgr_enabled = world()->get_settings().get_goods_routing_policy() == goods_routing_policy_t::GRP_FIFO_ET;
lb_tbgr_waiting_time.set_visible(is_tbgr_enabled && yesno);
numimp_tbgr_waiting_time.set_visible(is_tbgr_enabled && yesno);
}
3 changes: 1 addition & 2 deletions gui/schedule_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,7 @@ void schedule_list_gui_t::update_lineinfo(linehandle_t new_line)
line = new_line;
bt_withdraw_line.set_visible( line.is_bound() );
bt_show_journey_time.set_visible( line.is_bound() );
const bool is_tbgr_enabled = world()->get_settings().get_goods_routing_policy()==goods_routing_policy_t::GRP_FIFO_ET;
bt_goods_waiting_time.set_visible( is_tbgr_enabled && line.is_bound() );
bt_goods_waiting_time.set_visible( line.is_bound() );

reset_line_name();
}
Expand Down
16 changes: 0 additions & 16 deletions gui/settings_stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,6 @@ void settings_display_stats_t::read(settings_t* const)
READ_BOOL_VALUE( env_t::player_finance_display_account );
}

static char const * const goods_routing_policy_string[] =
{
"loading nearest first, routing with route cost",
"loading in arrival order, routing with route cost",
"loading in arrival order, routing with estimated time"
};

void settings_routing_stats_t::init(settings_t const* const sets)
{
INIT_INIT
Expand Down Expand Up @@ -253,14 +246,6 @@ void settings_routing_stats_t::init(settings_t const* const sets)
SEPERATOR
INIT_BOOL( "advance_to_end", sets->get_advance_to_end() );
INIT_BOOL( "first_come_first_serve", sets->first_come_first_serve );
// combobox for trees generator
goods_routing_policy.clear_elements();
for( uint32 i=0; i<lengthof(goods_routing_policy_string); i++ ) {
goods_routing_policy.new_component<gui_scrolled_list_t::const_text_scrollitem_t>( goods_routing_policy_string[i], SYSCOL_TEXT ) ;
}
goods_routing_policy.set_selection( sets->get_goods_routing_policy() );
goods_routing_policy.set_focusable( false );
add_component( &goods_routing_policy, 2);
INIT_NUM( "waiting_limit_for_first_come_first_serve", sets->get_waiting_limit_for_first_come_first_serve(), 100, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false );
SEPERATOR
INIT_NUM ( "base_waiting_ticks_for_rail_convoi", sets->base_waiting_ticks_for_rail_convoi, 0, 0x7FFFFFFFul, gui_numberinput_t::POWER2, false );
Expand Down Expand Up @@ -302,7 +287,6 @@ void settings_routing_stats_t::read(settings_t* const sets)
READ_NUM_VALUE( sets->routecost_halt );
READ_BOOL_VALUE( sets->advance_to_end );
READ_BOOL_VALUE( sets->first_come_first_serve );
sets->goods_routing_policy = (goods_routing_policy_t)::clamp(goods_routing_policy.get_selection(), (int)GRP_NF_RC, (int)GRP_FIFO_ET );
READ_NUM_VALUE( sets->waiting_limit_for_first_come_first_serve );

READ_NUM_VALUE( sets->base_waiting_ticks_for_rail_convoi );
Expand Down
3 changes: 0 additions & 3 deletions gui/settings_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,6 @@ class settings_display_stats_t : protected settings_stats_t, public gui_aligned_

class settings_routing_stats_t : protected settings_stats_t, public gui_aligned_container_t
{
private:
gui_combobox_t goods_routing_policy;

public:
void init(settings_t const*);
void read(settings_t*);
Expand Down
10 changes: 4 additions & 6 deletions simconvoi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3871,19 +3871,17 @@ void convoi_t::hat_gehalten(halthandle_t halt, uint32 halt_length_in_vehicle_ste

uint16 convoi_t::fetch_goods_and_load(vehicle_t* vehicle, const halthandle_t halt, const vector_tpl<halthandle_t> destination_halts, uint32 requested_amount) {
slist_tpl<ware_t> fetched_goods;
const goods_routing_policy_t goods_routing_policy = welt->get_settings().get_goods_routing_policy();
if( goods_routing_policy==goods_routing_policy_t::GRP_NF_RC ) {
halt->fetch_goods_nearest_first(fetched_goods, vehicle->get_cargo_type(), requested_amount, destination_halts);
} else {
// GRP_FIFO_ET or GRP_FIFO_RC
if( welt->get_settings().get_first_come_first_serve() ) {
halt->fetch_goods_FIFO(fetched_goods, vehicle->get_cargo_type(), requested_amount, destination_halts);
} else {
halt->fetch_goods_nearest_first(fetched_goods, vehicle->get_cargo_type(), requested_amount, destination_halts);
}
return vehicle->load_cargo(fetched_goods);
}


void convoi_t::push_goods_waiting_time_if_needed() {
if( welt->get_settings().get_goods_routing_policy()!=GRP_FIFO_ET || fetched_fresh_goods.empty() ) {
if( fetched_fresh_goods.empty() ) {
// No need to calculate and push the goods waiting time.
return;
}
Expand Down
74 changes: 35 additions & 39 deletions simhalt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,15 @@ void haltestelle_t::step_all()
last_reconnection_started_ticks = welt->get_ticks();
}

const bool is_tgbr_enabled = welt->get_settings().get_goods_routing_policy()==GRP_FIFO_ET;
if( status_step==0 && is_tgbr_enabled && welt->get_ticks() > last_reconnection_started_ticks + WEIGHT_UPDATE_INTERVAL_TICKS ) {
// Regurally update the connection weight only when time based routing is used.
bool is_tbgr_used = false;
for( uint8 catg_idx = 0; catg_idx < goods_manager_t::get_max_catg_index(); catg_idx++ ) {
if( welt->get_settings().get_time_based_routing_enabled(catg_idx) ) {
is_tbgr_used = true;
break;
}
}
if( status_step==0 && is_tbgr_used && welt->get_ticks() > last_reconnection_started_ticks + WEIGHT_UPDATE_INTERVAL_TICKS ) {
status_step = WEIGHT_UPDATE;
last_reconnection_started_ticks = welt->get_ticks();
}
Expand Down Expand Up @@ -1248,9 +1255,6 @@ sint32 haltestelle_t::rebuild_connections()
// previous halt supporting the ware categories of the serving line
halthandle_t previous_halt[256];

// true if the estimated time based goods routing is enabled. false if we use route cost calculation.
const bool is_tbgr_enabled = welt->get_settings().get_goods_routing_policy() == goods_routing_policy_t::GRP_FIFO_ET;

// first, remove all old entries
if( staged_all_links ) {
// rebuild_connections() is called before the staged links are commited.
Expand Down Expand Up @@ -1351,16 +1355,14 @@ sint32 haltestelle_t::rebuild_connections()
// now we add the schedule to the connection array
const schedule_entry_t start_entry = schedule->entries[start_index-1];

// aggregate_weight: When TBGR is enabled, (average goods waiting time) + (median journey time)
// When TBGR is disabled, it is route cost. e.g. WEIGHT_HALT + WEIGHT_WAIT * (stops count)
sint32 aggregate_weight;
if( is_tbgr_enabled ) {
// the journey time of the first entry contains the stopping time at the starting point, which should be excluded.
aggregate_weight = estimated_waiting_ticks(schedule, start_index-1) - start_entry.get_median_convoy_stopping_time();
}
else {
aggregate_weight = WEIGHT_WAIT;
}
// We calculate the connection weight by both route cost and journey time,
// because it depends on the routing configuration for the goods category.
sint32 aggregate_weight_rc; // weight by route cost. WEIGHT_HALT + WEIGHT_WAIT * (stops count)
sint32 aggregate_weight_jt; // weight by journey time. (average goods waiting time) + (median journey time)

// the journey time of the first entry contains the stopping time at the starting point, which should be excluded.
aggregate_weight_jt = estimated_waiting_ticks(schedule, start_index-1) - start_entry.get_median_convoy_stopping_time();
aggregate_weight_rc = WEIGHT_WAIT;

bool no_load_section = start_entry.is_no_load();
force_transfer_search |= (start_entry.is_unload_all() || start_entry.is_no_load() || start_entry.is_no_unload());
Expand All @@ -1372,9 +1374,7 @@ sint32 haltestelle_t::rebuild_connections()
if( !current_halt.is_bound() ) {
// ignore way points.
// just count the journey time
if( is_tbgr_enabled ) {
aggregate_weight += schedule->get_median_journey_time(current_entry_index, speedbonus_kmh);
}
aggregate_weight_jt += schedule->get_median_journey_time(current_entry_index, speedbonus_kmh);
continue;
}
if( current_halt == self ) {
Expand All @@ -1387,23 +1387,17 @@ sint32 haltestelle_t::rebuild_connections()
}
}
// reset aggregate weight and no_load_section
if( is_tbgr_enabled ) {
aggregate_weight = estimated_waiting_ticks(schedule, current_entry_index) - current_entry.get_median_convoy_stopping_time();
} else {
aggregate_weight = WEIGHT_WAIT;
}
aggregate_weight_jt = estimated_waiting_ticks(schedule, current_entry_index) - current_entry.get_median_convoy_stopping_time();
aggregate_weight_rc = WEIGHT_WAIT;
force_transfer_search |= (current_entry.is_unload_all() || current_entry.is_no_load() || current_entry.is_no_unload());
no_load_section = current_entry.is_no_load();
interval = 0;
continue;
}

// Add weight
if( is_tbgr_enabled ) {
aggregate_weight += schedule->get_median_journey_time(current_entry_index, (uint32)speedbonus_kmh);
} else {
aggregate_weight += WEIGHT_HALT;
}
aggregate_weight_jt += schedule->get_median_journey_time(current_entry_index, (uint32)speedbonus_kmh);
aggregate_weight_rc += WEIGHT_HALT;

if( current_entry.is_no_unload() || no_load_section ) {
// do not add connection if this halt is set no_unload or if the previous self stop is set no_load.
Expand All @@ -1429,6 +1423,7 @@ sint32 haltestelle_t::rebuild_connections()
previous_halt[catg_index] = current_halt;

// either add a new connection or update the weight of an existing connection where necessary
const uint32 aggregate_weight = welt->get_settings().get_time_based_routing_enabled(catg_index) ? aggregate_weight_jt : aggregate_weight_rc;
connection_t *const existing_connection = staged_all_links[catg_index].connections.insert_unique_ordered( connection_t( current_halt, aggregate_weight, traveler ), connection_t::compare );
if( existing_connection && aggregate_weight<existing_connection->weight ) {
existing_connection->weight = aggregate_weight;
Expand Down Expand Up @@ -2436,7 +2431,7 @@ bool haltestelle_t::vereinige_waren(const ware_t &ware)
// merge cargos only when "load nearest first" policy is applied.
const settings_t &settings = world()->get_settings();
const bool* wefl = waiting_amount_exceeds_FIFO_limit.access(ware.get_desc()->get_catg_index());
if( settings.get_goods_routing_policy()!=GRP_NF_RC && (wefl==NULL || !*wefl) ) {
if( settings.get_first_come_first_serve() && (wefl==NULL || !*wefl) ) {
return false;
}

Expand Down Expand Up @@ -2478,10 +2473,8 @@ std::shared_ptr<halt_waiting_goods_t> haltestelle_t::add_goods_to_halt(halt_wait
cargo_item_t goods_ref = cargo_item_t(new halt_waiting_goods_t(wg));
warray->append(goods_ref);

// Add the goods to fresh_cargo_ids if needed
if( world()->get_settings().get_goods_routing_policy()==goods_routing_policy_t::GRP_FIFO_ET ) {
fresh_cargo[wg.goods.get_desc()->get_catg_index()].push_back(std::weak_ptr<halt_waiting_goods_t>(goods_ref));
}
// Add the goods to fresh_cargo for the waiting time statistics
fresh_cargo[wg.goods.get_desc()->get_catg_index()].push_back(std::weak_ptr<halt_waiting_goods_t>(goods_ref));
return goods_ref;
}

Expand Down Expand Up @@ -4256,23 +4249,26 @@ void haltestelle_t::calc_destination_halt(inthashtable_tpl<uint8, vector_tpl<hal
} else {
traveler = cnv;
}
const bool is_tbgr_enabled = welt->get_settings().get_goods_routing_policy()==goods_routing_policy_t::GRP_FIFO_ET;
const schedule_t* schedule = std::visit(
[&](const auto &t) { return t->get_schedule(); }, traveler
);
if( !is_tbgr_enabled || cnv->get_schedule()->is_temporary() || unregistered_journey_time_exists(schedule, cnv->get_owner()) ) {
// We accept all halts in reachable_halts
FOR(const minivec_tpl<uint8>, const& i, goods_category_indexes) {
const bool accept_all_halts = schedule->is_temporary() || unregistered_journey_time_exists(schedule, cnv->get_owner());
FOR(const minivec_tpl<uint8>, const& i, goods_category_indexes) {
// Temporary schedule or route cost is used -> Accept all halts.
if( accept_all_halts || !welt->get_settings().get_time_based_routing_enabled(i) ) {
FOR(const vector_tpl<reachable_halt_t>, const& rh, reachable_halts) {
destination_halts.access(i)->append(rh.halt);
}
}
return;
}

const uint32 additional_ticks_by_schedule = (uint64)schedule->get_additional_base_waiting_time() * world()->ticks_per_world_month / world()->get_settings().get_spacing_shift_divisor();
const uint32 base_waiting_ticks = world()->get_settings().get_base_waiting_ticks(schedule->get_waytype()) + additional_ticks_by_schedule;
FOR(const minivec_tpl<uint8>, const& g_index, goods_category_indexes) {
if( !destination_halts.access(g_index)->empty() ) {
// The destination halts are already filled above.
continue;
}
FOR(const vector_tpl<reachable_halt_t>, const& rh, reachable_halts) {
connection_t connection;
FOR(const vector_tpl<connection_t>, const& j, all_links[g_index].connections) {
Expand Down Expand Up @@ -4309,7 +4305,7 @@ void haltestelle_t::calc_destination_halt(inthashtable_tpl<uint8, vector_tpl<hal
// Returns if the route search is needed for the given ware.
// When TBGR is enabled, the route search is needed only when the next transfer halt is not valid.
bool haltestelle_t::is_route_search_needed(const ware_t &ware) const {
if( world()->get_settings().get_goods_routing_policy()!=goods_routing_policy_t::GRP_FIFO_ET ) {
if( !world()->get_settings().get_time_based_routing_enabled(ware.get_index()) ) {
// Not using time based goods routing -> Always reroute
return true;
}
Expand Down

0 comments on commit 2626cf1

Please sign in to comment.