00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "station_base.h"
00014 #include "core/pool_func.hpp"
00015 #include "core/random_func.hpp"
00016 #include "economy_base.h"
00017
00018
00019 CargoPacketPool _cargopacket_pool("CargoPacket");
00020 INSTANTIATE_POOL_METHODS(CargoPacket)
00021
00022
00025 CargoPacket::CargoPacket()
00026 {
00027 this->source_type = ST_INDUSTRY;
00028 this->source_id = INVALID_SOURCE;
00029 }
00030
00042 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
00043 feeder_share(0),
00044 count(count),
00045 days_in_transit(0),
00046 source_id(source_id),
00047 source(source),
00048 source_xy(source_xy),
00049 loaded_at_xy(0)
00050 {
00051 assert(count != 0);
00052 this->source_type = source_type;
00053 }
00054
00069 CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) :
00070 feeder_share(feeder_share),
00071 count(count),
00072 days_in_transit(days_in_transit),
00073 source_id(source_id),
00074 source(source),
00075 source_xy(source_xy),
00076 loaded_at_xy(loaded_at_xy)
00077 {
00078 assert(count != 0);
00079 this->source_type = source_type;
00080 }
00081
00087 FORCEINLINE CargoPacket *CargoPacket::Split(uint new_size)
00088 {
00089 if (!CargoPacket::CanAllocateItem()) return NULL;
00090
00091 Money fs = this->feeder_share * new_size / static_cast<uint>(this->count);
00092 CargoPacket *cp_new = new CargoPacket(new_size, this->days_in_transit, this->source, this->source_xy, this->loaded_at_xy, fs, this->source_type, this->source_id);
00093 this->feeder_share -= fs;
00094 this->count -= new_size;
00095 return cp_new;
00096 }
00097
00102 FORCEINLINE void CargoPacket::Merge(CargoPacket *cp)
00103 {
00104 this->count += cp->count;
00105 this->feeder_share += cp->feeder_share;
00106 delete cp;
00107 }
00108
00114 void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
00115 {
00116 CargoPacket *cp;
00117 FOR_ALL_CARGOPACKETS(cp) {
00118 if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
00119 }
00120 }
00121
00126 void CargoPacket::InvalidateAllFrom(StationID sid)
00127 {
00128 CargoPacket *cp;
00129 FOR_ALL_CARGOPACKETS(cp) {
00130 if (cp->source == sid) cp->source = INVALID_STATION;
00131 }
00132 }
00133
00134
00135
00136
00137
00138
00139
00143 template <class Tinst, class Tcont>
00144 CargoList<Tinst, Tcont>::~CargoList()
00145 {
00146 for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
00147 delete *it;
00148 }
00149 }
00150
00155 template <class Tinst, class Tcont>
00156 void CargoList<Tinst, Tcont>::OnCleanPool()
00157 {
00158 this->packets.clear();
00159 }
00160
00166 template <class Tinst, class Tcont>
00167 void CargoList<Tinst, Tcont>::RemoveFromCache(const CargoPacket *cp)
00168 {
00169 this->count -= cp->count;
00170 this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
00171 }
00172
00178 template <class Tinst, class Tcont>
00179 void CargoList<Tinst, Tcont>::AddToCache(const CargoPacket *cp)
00180 {
00181 this->count += cp->count;
00182 this->cargo_days_in_transit += cp->days_in_transit * cp->count;
00183 }
00184
00195 void VehicleCargoList::Append(CargoPacket *cp, bool update_cache)
00196 {
00197 assert(cp != NULL);
00198 if (update_cache) this->AddToCache(cp);
00199 for (CargoPacketList::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
00200 CargoPacket *icp = *it;
00201 if (VehicleCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00202 icp->Merge(cp);
00203 return;
00204 }
00205 }
00206
00207
00208 this->packets.push_back(cp);
00209 }
00210
00216 template <class Tinst, class Tcont>
00217 void CargoList<Tinst, Tcont>::Truncate(uint max_remaining)
00218 {
00219 for (Iterator it(packets.begin()); it != packets.end(); ) {
00220 CargoPacket *cp = *it;
00221 if (max_remaining == 0) {
00222
00223 this->packets.erase(it++);
00224 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00225 delete cp;
00226 continue;
00227 }
00228
00229 uint local_count = cp->count;
00230 if (local_count > max_remaining) {
00231 uint diff = local_count - max_remaining;
00232 this->count -= diff;
00233 this->cargo_days_in_transit -= cp->days_in_transit * diff;
00234 cp->count = max_remaining;
00235 max_remaining = 0;
00236 } else {
00237 max_remaining -= local_count;
00238 }
00239 ++it;
00240 }
00241 }
00242
00247 void VehicleCargoList::Reserve(CargoPacket *cp)
00248 {
00249 assert(cp != NULL);
00250 this->AddToCache(cp);
00251 this->reserved_count += cp->count;
00252 this->reserved.push_back(cp);
00253 }
00254
00260 void VehicleCargoList::Unreserve(StationID next, StationCargoList *dest)
00261 {
00262 Iterator it(this->reserved.begin());
00263 while (it != this->reserved.end()) {
00264 CargoPacket *cp = *it;
00265 this->RemoveFromCache(cp);
00266 this->reserved_count -= cp->count;
00267 dest->Append(next, cp);
00268 this->reserved.erase(it++);
00269 }
00270 }
00271
00277 uint VehicleCargoList::LoadReserved(uint max_move)
00278 {
00279 uint orig_max = max_move;
00280 Iterator it(this->reserved.begin());
00281 while (it != this->reserved.end() && max_move > 0) {
00282 CargoPacket *cp = *it;
00283 if (cp->count <= max_move) {
00284
00285 max_move -= cp->count;
00286 this->reserved.erase(it++);
00287 this->reserved_count -= cp->count;
00288 this->Append(cp, false);
00289 } else if (CargoPacket::CanAllocateItem()) {
00290 cp->count -= max_move;
00291 CargoPacket *cp_new = new CargoPacket(max_move, cp->days_in_transit, cp->source, cp->source_xy, cp->loaded_at_xy, 0, cp->source_type, cp->source_id);
00292 this->Append(cp_new, false);
00293 this->reserved_count -= max_move;
00294 max_move = 0;
00295 }
00296 }
00297 return orig_max - max_move;
00298 }
00299
00310 template<class Tinst, class Tcont>
00311 uint CargoList<Tinst, Tcont>::MovePacket(VehicleCargoList *dest, Iterator &it, uint cap, TileIndex load_place, bool reserve)
00312 {
00313 CargoPacket *packet = this->RemovePacket(it, cap, load_place);
00314 uint ret = packet->count;
00315 if (reserve) {
00316 dest->Reserve(packet);
00317 } else {
00318 dest->Append(packet);
00319 }
00320 return ret;
00321 }
00322
00332 template<class Tinst, class Tcont>
00333 uint CargoList<Tinst, Tcont>::MovePacket(StationCargoList *dest, StationID next, Iterator &it, uint cap)
00334 {
00335 CargoPacket *packet = this->RemovePacket(it, cap);
00336 uint ret = packet->count;
00337 dest->Append(next, packet);
00338 return ret;
00339 }
00340
00350 template<class Tinst, class Tcont>
00351 CargoPacket *CargoList<Tinst, Tcont>::RemovePacket(Iterator &it, uint cap, TileIndex load_place)
00352 {
00353 CargoPacket *packet = *it;
00354
00355 if (packet->count > cap) {
00356
00357 packet = packet->Split(cap);
00358
00359
00360
00361
00362 if (packet == NULL) {
00363 packet = *it;
00364 uint dropped = packet->count - cap;
00365 this->count -= dropped;
00366 this->cargo_days_in_transit -= dropped * packet->days_in_transit;
00367 packet->count = cap;
00368 this->packets.erase(it++);
00369 } else {
00370 assert(packet->count == cap);
00371 ++it;
00372 }
00373 } else {
00374 this->packets.erase(it++);
00375 }
00376 static_cast<Tinst *>(this)->RemoveFromCache(packet);
00377 if (load_place != INVALID_TILE) {
00378 packet->loaded_at_xy = load_place;
00379 }
00380 return packet;
00381 }
00382
00386 template <class Tinst, class Tcont>
00387 void CargoList<Tinst, Tcont>::InvalidateCache()
00388 {
00389 this->count = 0;
00390 this->cargo_days_in_transit = 0;
00391
00392 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00393 static_cast<Tinst *>(this)->AddToCache(*it);
00394 }
00395 }
00396
00400 VehicleCargoList::~VehicleCargoList()
00401 {
00402 for (Iterator it(this->reserved.begin()); it != this->reserved.end(); ++it) {
00403 delete *it;
00404 }
00405 }
00406
00415 uint VehicleCargoList::DeliverPacket(Iterator &it, uint cap, CargoPayment *payment)
00416 {
00417 CargoPacket *p = *it;
00418 uint unloaded = 0;
00419 if (p->count <= cap) {
00420 payment->PayFinalDelivery(p, p->count);
00421 this->packets.erase(it++);
00422 this->RemoveFromCache(p);
00423 unloaded = p->count;
00424 delete p;
00425 } else {
00426 payment->PayFinalDelivery(p, cap);
00427 this->count -= cap;
00428 this->cargo_days_in_transit -= cap * p->days_in_transit;
00429 this->feeder_share -= p->feeder_share;
00430 p->feeder_share = 0;
00431 p->count -= cap;
00432 unloaded = cap;
00433 ++it;
00434 }
00435 return unloaded;
00436 }
00437
00444 uint VehicleCargoList::KeepPacket(Iterator &it)
00445 {
00446 CargoPacket *cp = *it;
00447 this->reserved.push_back(cp);
00448 this->reserved_count += cp->count;
00449 this->packets.erase(it++);
00450 return cp->count;
00451 }
00452
00464 uint VehicleCargoList::TransferPacket(Iterator &it, uint cap, StationCargoList *dest, CargoPayment *payment, StationID next)
00465 {
00466 CargoPacket *cp = this->RemovePacket(it, cap);
00467 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00468 uint ret = cp->count;
00469 dest->Append(next, cp);
00470 return ret;
00471 }
00472
00482 UnloadType StationCargoList::WillUnloadOld(byte flags, StationID source)
00483 {
00484
00485 bool move = (flags & (UL_DELIVER | UL_ACCEPTED | UL_TRANSFER)) != 0;
00486
00487 bool deliver = (flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && (source != this->station->index);
00488
00489 bool transfer = (flags & (UL_TRANSFER | UL_DELIVER)) != 0;
00490 if (move) {
00491 if(deliver) {
00492 return UL_DELIVER;
00493 } else if (transfer) {
00494 return UL_TRANSFER;
00495 } else {
00496
00497
00498
00499 return UL_KEEP;
00500 }
00501 } else {
00502 return UL_KEEP;
00503 }
00504 }
00505
00519 UnloadType StationCargoList::WillUnloadCargoDist(byte flags, StationID next, StationID via, StationID source)
00520 {
00521 if (via == this->station->index) {
00522
00523 if (flags & UL_TRANSFER) {
00524
00525 return UL_TRANSFER;
00526 } else if (flags & UL_ACCEPTED) {
00527 return UL_DELIVER;
00528 } else if (flags & UL_DELIVER) {
00529
00530 return UL_TRANSFER;
00531 } else {
00532
00533 return UL_KEEP;
00534 }
00535 } else {
00536
00537 if (flags & UL_DELIVER) {
00538
00539
00540
00541 if ((flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && source != this->station->index) {
00542 return UL_DELIVER;
00543 } else {
00544
00545 return UL_TRANSFER;
00546 }
00547 } else if (flags & UL_TRANSFER) {
00548
00549 return UL_TRANSFER;
00550 } else if (next == via && next != INVALID_STATION) {
00551
00552 return UL_KEEP;
00553 } else {
00554
00555 return UL_TRANSFER;
00556 }
00557 }
00558 }
00559
00566 void VehicleCargoList::SwapReserved()
00567 {
00568 assert(this->packets.empty());
00569 this->packets.swap(this->reserved);
00570 this->reserved_count = 0;
00571 }
00572
00594 uint StationCargoList::TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags order_flags, StationID next, bool has_stopped, CargoPayment *payment)
00595 {
00596 uint remaining_unload = max_unload;
00597 uint unloaded;
00598 byte flags = this->GetUnloadFlags(order_flags);
00599 GoodsEntry *dest = &this->station->goods[this->cargo];
00600 UnloadType action;
00601
00602 for (VehicleCargoList::Iterator c = source->packets.begin(); c != source->packets.end() && remaining_unload > 0;) {
00603 StationID cargo_source = (*c)->source;
00604 FlowStatSet &flows = dest->flows[cargo_source];
00605 FlowStatSet::iterator begin = flows.begin();
00606 StationID via = (begin != flows.end() ? begin->Via() : INVALID_STATION);
00607 if (via != INVALID_STATION) {
00608
00609 action = this->WillUnloadCargoDist(flags, next, via, cargo_source);
00610 } else {
00611
00612 action = this->WillUnloadOld(flags, cargo_source);
00613 }
00614
00615 switch (action) {
00616 case UL_DELIVER:
00617 unloaded = source->DeliverPacket(c, remaining_unload, payment);
00618 if (via != INVALID_STATION) {
00619 if (via == this->station->index) {
00620 dest->UpdateFlowStats(flows, begin, unloaded);
00621 } else {
00622 dest->UpdateFlowStats(flows, unloaded, this->station->index);
00623 }
00624 }
00625 remaining_unload -= unloaded;
00626 break;
00627 case UL_TRANSFER:
00628
00629 if (via == this->station->index) {
00630 via = (++begin != flows.end()) ? begin->Via() : INVALID_STATION;
00631 }
00632 unloaded = source->TransferPacket(c, remaining_unload, this, payment, via);
00633 if (via != INVALID_STATION) {
00634 dest->UpdateFlowStats(flows, begin, unloaded);
00635 }
00636 remaining_unload -= unloaded;
00637 break;
00638 case UL_KEEP:
00639 unloaded = source->KeepPacket(c);
00640 if (via != INVALID_STATION && next != INVALID_STATION && !has_stopped) {
00641 if (via == next) {
00642 dest->UpdateFlowStats(flows, begin, unloaded);
00643 } else {
00644 dest->UpdateFlowStats(flows, unloaded, next);
00645 }
00646 }
00647 break;
00648 default:
00649 NOT_REACHED();
00650 }
00651 }
00652 return max_unload - remaining_unload;
00653 }
00654
00658 void VehicleCargoList::OnCleanPool()
00659 {
00660 this->reserved.clear();
00661 this->Parent::OnCleanPool();
00662 }
00663
00669 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
00670 {
00671 this->feeder_share -= cp->feeder_share;
00672 this->Parent::RemoveFromCache(cp);
00673 }
00674
00680 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00681 {
00682 this->feeder_share += cp->feeder_share;
00683 this->Parent::AddToCache(cp);
00684 }
00685
00692 uint VehicleCargoList::MoveTo(VehicleCargoList *dest, uint cap)
00693 {
00694 uint orig_cap = cap;
00695 Iterator it = packets.begin();
00696 while (it != packets.end() && cap > 0) {
00697 cap -= MovePacket(dest, it, cap);
00698 }
00699 return orig_cap - cap;
00700 }
00701
00705 void VehicleCargoList::AgeCargo()
00706 {
00707 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00708 CargoPacket *cp = *it;
00709
00710 if (cp->days_in_transit == 0xFF) continue;
00711
00712 cp->days_in_transit++;
00713 this->cargo_days_in_transit += cp->count;
00714 }
00715 }
00716
00717
00718
00719
00720
00721
00722
00728 FORCEINLINE byte StationCargoList::GetUnloadFlags(OrderUnloadFlags order_flags)
00729 {
00730 byte flags = 0;
00731 if (HasBit(this->station->goods[this->cargo].acceptance_pickup, GoodsEntry::ACCEPTANCE)) {
00732 flags |= UL_ACCEPTED;
00733 }
00734 if (order_flags & OUFB_UNLOAD) {
00735 flags |= UL_DELIVER;
00736 }
00737 if (order_flags & OUFB_TRANSFER) {
00738 flags |= UL_TRANSFER;
00739 }
00740 return flags;
00741 }
00742
00751 void StationCargoList::Append(StationID next, CargoPacket *cp)
00752 {
00753 assert(cp != NULL);
00754 this->AddToCache(cp);
00755
00756 StationCargoPacketMap::List &list = this->packets[next];
00757 for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) {
00758 CargoPacket *icp = *it;
00759 if (StationCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00760 icp->Merge(cp);
00761 return;
00762 }
00763 }
00764
00765
00766 list.push_back(cp);
00767 }
00768
00778 uint StationCargoList::MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve)
00779 {
00780 uint orig_cap = cap;
00781 while (begin != end && cap > 0) {
00782 cap -= this->MovePacket(dest, begin, cap, this->station->xy, reserve);
00783 }
00784 return orig_cap - cap;
00785 }
00786
00795 uint StationCargoList::MoveTo(VehicleCargoList *dest, uint cap, StationID next, bool reserve)
00796 {
00797 uint orig_cap = cap;
00798 std::pair<Iterator, Iterator> bounds(this->packets.equal_range(next));
00799 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00800 if (next != INVALID_STATION && cap > 0) {
00801 bounds = this->packets.equal_range(INVALID_STATION);
00802 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00803 }
00804 return orig_cap - cap;
00805 }
00806
00811 void StationCargoList::RerouteStalePackets(StationID to)
00812 {
00813 std::pair<Iterator, Iterator> range(this->packets.equal_range(to));
00814 for (Iterator it(range.first); it != range.second && it.GetKey() == to;) {
00815 CargoPacket *packet = *it;
00816 this->packets.erase(it++);
00817 StationID next = this->station->goods[this->cargo].UpdateFlowStatsTransfer(packet->source, packet->count, this->station->index);
00818 assert(next != to);
00819
00820
00821
00822
00823
00824 this->packets.Insert(next, packet);
00825 }
00826 }
00827
00835 void StationCargoList::CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source)
00836 {
00837 uint prev_count = this->count;
00838 uint loop = 0;
00839 while (this->count > max_remaining) {
00840 for (Iterator it(this->packets.begin()); it != this->packets.end();) {
00841 CargoPacket *packet = *it;
00842 if (loop == 0) cargo_per_source[packet->source] += packet->count;
00843
00844 if (RandomRange(prev_count) < max_remaining) {
00845 ++it;
00846 continue;
00847 }
00848
00849 uint diff = this->count - max_remaining;
00850 if (packet->count > diff) {
00851 packet->count -= diff;
00852 this->count = max_remaining;
00853 this->cargo_days_in_transit -= packet->days_in_transit * diff;
00854 if (loop > 0) {
00855 return;
00856 } else {
00857 ++it;
00858 }
00859 } else {
00860 this->packets.erase(it++);
00861 this->RemoveFromCache(packet);
00862 delete packet;
00863 }
00864 }
00865 loop++;
00866 }
00867 }
00868
00872 void VehicleCargoList::InvalidateCache()
00873 {
00874 this->feeder_share = 0;
00875 this->reserved_count = 0;
00876 this->Parent::InvalidateCache();
00877 for (ConstIterator it(this->reserved.begin()); it != this->reserved.end(); it++) {
00878 this->AddToCache(*it);
00879 this->reserved_count += (*it)->count;
00880 }
00881 }
00882
00888 void StationCargoList::AssignTo(Station *station, CargoID cargo)
00889 {
00890 assert(this->station == NULL);
00891 assert(station != NULL && cargo != INVALID_CARGO);
00892 this->station = station;
00893 this->cargo = cargo;
00894 }
00895
00896
00897
00898
00899
00900 template class CargoList<VehicleCargoList, CargoPacketList>;
00901 template class CargoList<StationCargoList, StationCargoPacketMap>;