OpenTTD Source 20250312-master-gcdcc6b491d
cargopacket.h
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef CARGOPACKET_H
11#define CARGOPACKET_H
12
13#include "core/pool_type.hpp"
14#include "economy_type.h"
15#include "station_type.h"
16#include "order_type.h"
17#include "cargo_type.h"
18#include "source_type.h"
19#include "vehicle_type.h"
20#include "core/multimap.hpp"
21#include "saveload/saveload.h"
22
25struct CargoPacket;
26
31
32struct GoodsEntry; // forward-declare for Stage() and RerouteStalePackets()
33
34template <class Tinst, class Tcont> class CargoList;
35class StationCargoList; // forward-declare, so we can use it in VehicleCargoList.
37
41struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> {
42private:
43 /* A mathematical vector from (0,0). */
44 struct Vector {
45 int16_t x;
46 int16_t y;
47 };
48
49 uint16_t count = 0;
50 uint16_t periods_in_transit = 0;
51
53
56
58
59#ifdef WITH_ASSERT
60 bool in_vehicle = false;
61#endif /* WITH_ASSERT */
62
63 StationID first_station = StationID::Invalid();
64 StationID next_hop = StationID::Invalid();
65
67 template <class Tinst, class Tcont> friend class CargoList;
68 friend class VehicleCargoList;
69 friend class StationCargoList;
72public:
74 static const uint16_t MAX_COUNT = UINT16_MAX;
75
79 CargoPacket(uint16_t count, Money feeder_share, CargoPacket &original);
80
83
84 CargoPacket *Split(uint new_size);
85 void Merge(CargoPacket *cp);
86 void Reduce(uint count);
87
93 {
94 this->next_hop = next_hop;
95 }
96
112 {
113 if (this->source_xy == INVALID_TILE) {
114 this->source_xy = tile;
115 }
116
117#ifdef WITH_ASSERT
118 assert(!this->in_vehicle);
119 this->in_vehicle = true;
120#endif /* WITH_ASSERT */
121
122 /* We want to calculate the vector from tile-unload to tile-load. As
123 * we currently only know the latter, add it. When we know where we unload,
124 * we subtract is, giving us our vector (unload - load). */
125 this->travelled.x += TileX(tile);
126 this->travelled.y += TileY(tile);
127 }
128
135 {
136#ifdef WITH_ASSERT
137 assert(this->in_vehicle);
138 this->in_vehicle = false;
139#endif /* WITH_ASSERT */
140
141 this->travelled.x -= TileX(tile);
142 this->travelled.y -= TileY(tile);
143 }
144
149 void AddFeederShare(Money new_share)
150 {
151 this->feeder_share += new_share;
152 }
153
158 inline uint16_t Count() const
159 {
160 return this->count;
161 }
162
168 inline Money GetFeederShare() const
169 {
170 return this->feeder_share;
171 }
172
179 inline Money GetFeederShare(uint part) const
180 {
181 return this->feeder_share * part / static_cast<uint>(this->count);
182 }
183
191 inline uint16_t GetPeriodsInTransit() const
192 {
193 return this->periods_in_transit;
194 }
195
200 inline Source GetSource() const
201 {
202 return this->source;
203 }
204
210 {
211 return this->first_station;
212 }
213
220 inline uint GetDistance(TileIndex current_tile) const
221 {
222 assert(this->source_xy != INVALID_TILE);
223#ifdef WITH_ASSERT
224 assert(this->in_vehicle);
225#endif /* WITH_ASSERT */
226
227 /* Distance is always requested when the cargo is still inside the
228 * vehicle. So first finish the calculation for travelled to
229 * become a vector. */
230 auto local_travelled = travelled;
231 local_travelled.x -= TileX(current_tile);
232 local_travelled.y -= TileY(current_tile);
233
234 /* Cargo-movement is a vector that indicates how much the cargo has
235 * actually traveled in a vehicle. This is the distance you get paid
236 * for. However, one could construct a route where this vector would
237 * be really long. To not overpay the player, cap out at the distance
238 * between source and destination.
239 *
240 * This way of calculating is to counter people moving cargo for free
241 * and instantly in stations, where you deliver it in one part of the
242 * station and pick it up in another. By using the actual distance
243 * traveled in a vehicle, using this trick doesn't give you more money.
244 *
245 * However, especially in large networks with large transfer station,
246 * etc, one could actually make the route a lot longer. In that case,
247 * use the actual distance between source and destination.
248 */
249
250 uint distance_travelled = abs(local_travelled.x) + abs(local_travelled.y);
251 uint distance_source_dest = DistanceManhattan(this->source_xy, current_tile);
252 return std::min(distance_travelled, distance_source_dest);
253 }
254
259 inline StationID GetNextHop() const
260 {
261 return this->next_hop;
262 }
263
264 static void InvalidateAllFrom(Source src);
265 static void InvalidateAllFrom(StationID sid);
266 static void AfterLoad();
267};
268
273template <class Tinst, class Tcont>
275public:
277 typedef typename Tcont::iterator Iterator;
279 typedef typename Tcont::reverse_iterator ReverseIterator;
281 typedef typename Tcont::const_iterator ConstIterator;
283 typedef typename Tcont::const_reverse_iterator ConstReverseIterator;
284
286 enum MoveToAction : uint8_t {
287 MTA_BEGIN = 0,
292 MTA_END,
293 NUM_MOVE_TO_ACTION = MTA_END
294 };
295
296protected:
297 uint count = 0;
299
300 Tcont packets{};
301
302 void AddToCache(const CargoPacket *cp);
303
304 void RemoveFromCache(const CargoPacket *cp, uint count);
305
306 static bool TryMerge(CargoPacket *cp, CargoPacket *icp);
307
308public:
311
312 ~CargoList();
313
314 void OnCleanPool();
315
320 inline const Tcont *Packets() const
321 {
322 return &this->packets;
323 }
324
329 inline uint PeriodsInTransit() const
330 {
331 return this->count == 0 ? 0 : this->cargo_periods_in_transit / this->count;
332 }
333
334 void InvalidateCache();
335};
336
337typedef std::list<CargoPacket *> CargoPacketList;
338
342class VehicleCargoList : public CargoList<VehicleCargoList, CargoPacketList> {
343protected:
346
348 uint action_counts[NUM_MOVE_TO_ACTION];
349
350 template <class Taction>
351 void ShiftCargo(Taction action);
352
353 template <class Taction>
354 void PopCargo(Taction action);
355
359 inline void AssertCountConsistency() const
360 {
361 assert(this->action_counts[MTA_KEEP] +
362 this->action_counts[MTA_DELIVER] +
363 this->action_counts[MTA_TRANSFER] +
364 this->action_counts[MTA_LOAD] == this->count);
365 }
366
367 void AddToCache(const CargoPacket *cp);
368 void RemoveFromCache(const CargoPacket *cp, uint count);
369
370 void AddToMeta(const CargoPacket *cp, MoveToAction action);
371 void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
372
373 static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
374 StationID current_station, bool accepted, StationIDStack next_station);
375
376public:
378 friend class StationCargoList;
380 friend class CargoList<VehicleCargoList, CargoPacketList>;
381 /* So we can use private/protected variables in the saveload code */
382 friend class SlVehicleCommon;
383
384 friend class CargoShift;
385 friend class CargoTransfer;
386 friend class CargoDelivery;
387 template <class Tsource>
388 friend class CargoRemoval;
389 friend class CargoReturn;
390 friend class VehicleCargoReroute;
391
397 {
398 return this->count == 0 ? StationID::Invalid() : this->packets.front()->first_station;
399 }
400
405 inline Money GetFeederShare() const
406 {
407 return this->feeder_share;
408 }
409
415 inline uint ActionCount(MoveToAction action) const
416 {
417 return this->action_counts[action];
418 }
419
425 inline uint StoredCount() const
426 {
427 return this->count - this->action_counts[MTA_LOAD];
428 }
429
434 inline uint TotalCount() const
435 {
436 return this->count;
437 }
438
443 inline uint ReservedCount() const
444 {
445 return this->action_counts[MTA_LOAD];
446 }
447
452 inline uint UnloadCount() const
453 {
454 return this->action_counts[MTA_TRANSFER] + this->action_counts[MTA_DELIVER];
455 }
456
461 inline uint RemainingCount() const
462 {
463 return this->action_counts[MTA_KEEP] + this->action_counts[MTA_LOAD];
464 }
465
466 void Append(CargoPacket *cp, MoveToAction action = MTA_KEEP);
467
468 void AgeCargo();
469
470 void InvalidateCache();
471
472 bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
473
479 inline void KeepAll()
480 {
481 this->action_counts[MTA_DELIVER] = this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_LOAD] = 0;
482 this->action_counts[MTA_KEEP] = this->count;
483 }
484
485 /* Methods for moving cargo around. First parameter is always maximum
486 * amount of cargo to be moved. Second parameter is destination (if
487 * applicable), return value is amount of cargo actually moved. */
488
489 template <MoveToAction Tfrom, MoveToAction Tto>
490 uint Reassign(uint max_move);
491 uint Return(uint max_move, StationCargoList *dest, StationID next_station, TileIndex current_tile);
492 uint Unload(uint max_move, StationCargoList *dest, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
493 uint Shift(uint max_move, VehicleCargoList *dest);
494 uint Truncate(uint max_move = UINT_MAX);
495 uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
496
504 static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2)
505 {
506 return cp1->source_xy == cp2->source_xy &&
508 cp1->first_station == cp2->first_station &&
509 cp1->source == cp2->source;
510 }
511};
512
514typedef std::map<StationID, uint> StationCargoAmountMap;
515
519class StationCargoList : public CargoList<StationCargoList, StationCargoPacketMap> {
520protected:
523
525
526public:
529 /* So we can use private/protected variables in the saveload code */
530 friend class SlStationGoods;
531
532 friend class CargoLoad;
533 friend class CargoTransfer;
534 template <class Tsource>
535 friend class CargoRemoval;
536 friend class CargoReservation;
537 friend class CargoReturn;
538 friend class StationCargoReroute;
539
540 static void InvalidateAllFrom(Source src);
541
542 template <class Taction>
543 bool ShiftCargo(Taction &action, StationID next);
544
545 template <class Taction>
546 uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid);
547
548 void Append(CargoPacket *cp, StationID next);
549
555 inline bool HasCargoFor(StationIDStack next) const
556 {
557 while (!next.IsEmpty()) {
558 if (this->packets.find(StationID{next.Pop()}) != this->packets.end()) return true;
559 }
560 /* Packets for StationID::Invalid() can go anywhere. */
561 return this->packets.find(StationID::Invalid()) != this->packets.end();
562 }
563
569 {
570 return this->count == 0 ? StationID::Invalid() : this->packets.begin()->second.front()->first_station;
571 }
572
578 inline uint AvailableCount() const
579 {
580 return this->count;
581 }
582
587 inline uint ReservedCount() const
588 {
589 return this->reserved_count;
590 }
591
597 inline uint TotalCount() const
598 {
599 return this->count + this->reserved_count;
600 }
601
602 /* Methods for moving cargo around. First parameter is always maximum
603 * amount of cargo to be moved. Second parameter is destination (if
604 * applicable), return value is amount of cargo actually moved. */
605
606 uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
607 uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
608 uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr);
609 uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
610
618 static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2)
619 {
620 return cp1->source_xy == cp2->source_xy &&
622 cp1->first_station == cp2->first_station &&
623 cp1->source == cp2->source;
624 }
625};
626
627#endif /* CARGOPACKET_H */
Types related to cargoes...
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
CargoPacketPool _cargopacket_pool
The actual pool with cargo packets.
SaveLoadTable GetCargoPacketDesc()
Wrapper function to get the CargoPacket's internal structure while some of the variables itself are p...
Action of final delivery of cargo.
Definition cargoaction.h:39
Simple collection class for a list of cargo packets.
Tcont::reverse_iterator ReverseIterator
The reverse iterator for our container.
void OnCleanPool()
Empty the cargo list, but don't free the cargo packets; the cargo packets are cleaned by CargoPacket'...
Tcont packets
The cargo packets in this list.
~CargoList()
Destroy the cargolist ("frees" all cargo packets).
const Tcont * Packets() const
Returns a pointer to the cargo packet list (so you can iterate over it etc).
Tcont::const_iterator ConstIterator
The const iterator for our container.
uint count
Cache for the number of cargo entities.
CargoList()
Create the cargo list.
uint64_t cargo_periods_in_transit
Cache for the sum of number of cargo aging periods in transit of each entity; comparable to man-hours...
static bool TryMerge(CargoPacket *cp, CargoPacket *icp)
Tries to merge the second packet into the first and return if that was successful.
Tcont::iterator Iterator
The iterator for our container.
MoveToAction
Kind of actions that could be done with packets on move.
@ MTA_KEEP
Keep the cargo in the vehicle.
@ MTA_DELIVER
Deliver the cargo to some town or industry.
@ MTA_LOAD
Load the cargo from the station.
@ MTA_TRANSFER
Transfer the cargo to the station.
Tcont::const_reverse_iterator ConstReverseIterator
The const reverse iterator for our container.
uint PeriodsInTransit() const
Returns average number of cargo aging periods in transit for a cargo entity.
void AddToCache(const CargoPacket *cp)
Update the cache to reflect adding of this packet.
void InvalidateCache()
Invalidates the cached data and rebuilds it.
void RemoveFromCache(const CargoPacket *cp, uint count)
Update the cached values to reflect the removal of this packet or part of it.
Action of loading cargo from a station onto a vehicle.
Definition cargoaction.h:83
Abstract action of removing cargo from a vehicle or a station.
Definition cargoaction.h:20
Action of reserving cargo from a station to be loaded onto a vehicle.
Definition cargoaction.h:93
Action of returning previously reserved cargo from the vehicle to the station.
Action of shifting cargo from one vehicle to another.
Action of transferring cargo from a vehicle to a station.
Definition cargoaction.h:73
Hand-rolled multimap as map of lists.
Definition multimap.hpp:225
Minimal stack that uses a pool to avoid pointers.
bool IsEmpty() const
Check if the stack is empty.
CargoList that is used for stations.
CargoList< StationCargoList, StationCargoPacketMap > Parent
The (direct) parent of this class.
uint TotalCount() const
Returns total count of cargo at the station, including cargo which is already reserved for loading.
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
Routes packets with station "avoid" as next hop to a different place.
uint ReservedCount() const
Returns sum of cargo reserved for loading onto vehicles.
uint AvailableCount() const
Returns sum of cargo still available for loading at the sation.
void Append(CargoPacket *cp, StationID next)
Appends the given cargo packet to the range of packets with the same next station.
uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile)
Reserves cargo for loading onto the vehicle.
uint Truncate(uint max_move=UINT_MAX, StationCargoAmountMap *cargo_per_source=nullptr)
Truncates where each destination loses roughly the same percentage of its cargo.
bool ShiftCargo(Taction &action, StationID next)
Shifts cargo from the front of the packet list for a specific station and applies some action to it.
uint reserved_count
Amount of cargo being reserved for loading.
static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2)
Are the two CargoPackets mergeable in the context of a list of CargoPackets for a Station?
uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile)
Loads cargo onto a vehicle.
bool HasCargoFor(StationIDStack next) const
Check for cargo headed for a specific station.
StationID GetFirstStation() const
Returns first station of the first cargo packet in this list.
Action of rerouting cargo in a station.
CargoList that is used for vehicles.
uint Shift(uint max_move, VehicleCargoList *dest)
Shifts cargo between two vehicles.
void AddToMeta(const CargoPacket *cp, MoveToAction action)
Adds a packet to the metadata.
uint UnloadCount() const
Returns sum of cargo to be moved out of the vehicle at the current station.
void PopCargo(Taction action)
Pops cargo from the back of the packet list and applies some action to it.
Money GetFeederShare() const
Returns total sum of the feeder share for all packets.
uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
Routes packets with station "avoid" as next hop to a different place.
uint ActionCount(MoveToAction action) const
Returns the amount of cargo designated for a given purpose.
uint Truncate(uint max_move=UINT_MAX)
Truncates the cargo in this list to the given amount.
void AssertCountConsistency() const
Assert that the designation counts add up.
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count)
Removes a packet or part of it from the metadata.
uint Return(uint max_move, StationCargoList *dest, StationID next_station, TileIndex current_tile)
Returns reserved cargo to the station and removes it from the cache.
static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2)
Are the two CargoPackets mergeable in the context of a list of CargoPackets for a Vehicle?
uint TotalCount() const
Returns sum of cargo, including reserved cargo.
uint action_counts[NUM_MOVE_TO_ACTION]
Counts of cargo to be transferred, delivered, kept and loaded.
uint ReservedCount() const
Returns sum of reserved cargo.
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next, StationID current_station, bool accepted, StationIDStack next_station)
Choose action to be performed with the given cargo packet.
uint RemainingCount() const
Returns the sum of cargo to be kept in the vehicle at the current station.
CargoList< VehicleCargoList, CargoPacketList > Parent
The (direct) parent of this class.
Money feeder_share
Cache for the feeder share.
void Append(CargoPacket *cp, MoveToAction action=MTA_KEEP)
Appends the given cargo packet.
void RemoveFromCache(const CargoPacket *cp, uint count)
Update the cached values to reflect the removal of this packet or part of it.
uint Reassign(uint max_move)
Moves some cargo from one designation to another.
void InvalidateCache()
Invalidates the cached data and rebuild it.
void AddToCache(const CargoPacket *cp)
Update the cache to reflect adding of this packet.
void KeepAll()
Marks all cargo in the vehicle as to be kept.
StationID GetFirstStation() const
Returns the first station of the first cargo packet in this list.
bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
Stages cargo for unloading.
void AgeCargo()
Ages the all cargo in this list.
uint StoredCount() const
Returns sum of cargo on board the vehicle (ie not only reserved).
uint Unload(uint max_move, StationCargoList *dest, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
Unloads cargo at the given station.
void ShiftCargo(Taction action)
Shifts cargo from the front of the packet list and applies some action to it.
Action of rerouting cargo staged for transfer in a vehicle.
Types related to the economy.
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:424
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:414
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
Multimap with deterministic ordering of items with equal keys.
Types related to orders.
Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle,...
Functions/types related to saving and loading games.
std::span< const struct SaveLoad > SaveLoadTable
A table of SaveLoad entries.
Definition saveload.h:520
@ Split
track merge/split found
Type for the source of cargo.
@ Industry
Source/destination is an industry.
Types related to stations.
Container for cargo from the same location and time.
Definition cargopacket.h:41
void Reduce(uint count)
Reduce the packet by the given amount and remove the feeder share.
uint16_t Count() const
Gets the number of 'items' in this packet.
Money GetFeederShare(uint part) const
Gets part of the amount of money already paid to earlier vehicles in the feeder chain.
~CargoPacket()
Destroy the packet.
Definition cargopacket.h:82
void Merge(CargoPacket *cp)
Merge another packet into this one.
Money feeder_share
Value of feeder pickup to be paid for on delivery of cargo.
Definition cargopacket.h:52
static const uint16_t MAX_COUNT
Maximum number of items in a single cargo packet.
Definition cargopacket.h:74
TileIndex source_xy
The origin of the cargo.
Definition cargopacket.h:54
void SetNextHop(StationID next_hop)
Sets the station where the packet is supposed to go next.
Definition cargopacket.h:92
StationID next_hop
Station where the cargo wants to go next.
Definition cargopacket.h:64
Source source
Source of the cargo.
Definition cargopacket.h:57
void UpdateLoadingTile(TileIndex tile)
Update for the cargo being loaded on this tile.
friend SaveLoadTable GetCargoPacketDesc()
We want this to be saved, right?
void AddFeederShare(Money new_share)
Adds some feeder share to the packet.
static void AfterLoad()
Savegame conversion for cargopackets.
StationID GetNextHop() const
Gets the ID of station the cargo wants to go next.
uint16_t count
The amount of cargo in this packet.
Definition cargopacket.h:49
CargoPacket()
Create a new packet for savegame loading.
Money GetFeederShare() const
Gets the amount of money already paid to earlier vehicles in the feeder chain.
StationID GetFirstStation() const
Gets the ID of the station where the cargo was loaded for the first time.
uint GetDistance(TileIndex current_tile) const
Get the current distance the cargo has traveled.
StationID first_station
The station where the cargo came from first.
Definition cargopacket.h:63
Vector travelled
If cargo is in station: the vector from the unload tile to the source tile. If in vehicle: an interme...
Definition cargopacket.h:55
uint16_t GetPeriodsInTransit() const
Gets the number of cargo aging periods this cargo has been in transit.
Source GetSource() const
Gets the source of the packet for subsidy purposes.
static void InvalidateAllFrom(Source src)
Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source.
void UpdateUnloadingTile(TileIndex tile)
Update for the cargo being unloaded on this tile.
uint16_t periods_in_transit
Amount of cargo aging periods this packet has been in transit.
Definition cargopacket.h:50
Helper class to perform the cargo payment.
Stores station stats for a single cargo.
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
Base class for all PoolItems.
Base class for all pools.
A location from where cargo can come from (or go to).
Definition source_type.h:32
static constexpr SourceID Invalid
Invalid/unknown index of source.
Definition source_type.h:34
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
Types related to vehicles.