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
00199 if (update_cache) this->AddToCache(cp);
00200 for (CargoPacketList::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
00201 CargoPacket *icp = *it;
00202 if (VehicleCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00203 icp->Merge(cp);
00204 return;
00205 }
00206 }
00207
00208
00209 this->packets.push_back(cp);
00210 }
00211
00217 template <class Tinst, class Tcont>
00218 void CargoList<Tinst, Tcont>::Truncate(uint max_remaining)
00219 {
00220 for (Iterator it(packets.begin()); it != packets.end(); ) {
00221 CargoPacket *cp = *it;
00222 if (max_remaining == 0) {
00223
00224 this->packets.erase(it++);
00225 static_cast<Tinst *>(this)->RemoveFromCache(cp);
00226 delete cp;
00227 continue;
00228 }
00229
00230 uint local_count = cp->count;
00231 if (local_count > max_remaining) {
00232 uint diff = local_count - max_remaining;
00233 this->count -= diff;
00234 this->cargo_days_in_transit -= cp->days_in_transit * diff;
00235 cp->count = max_remaining;
00236 max_remaining = 0;
00237 } else {
00238 max_remaining -= local_count;
00239 }
00240 ++it;
00241 }
00242 }
00243
00248 void VehicleCargoList::Reserve(CargoPacket *cp)
00249 {
00250 assert(cp != NULL);
00251 this->AddToCache(cp);
00252 this->reserved_count += cp->count;
00253 this->reserved.push_back(cp);
00254 }
00255
00261 void VehicleCargoList::Unreserve(StationID next, StationCargoList *dest)
00262 {
00263 Iterator it(this->reserved.begin());
00264 while (it != this->reserved.end()) {
00265 CargoPacket *cp = *it;
00266 this->RemoveFromCache(cp);
00267 this->reserved_count -= cp->count;
00268 dest->Append(next, cp);
00269 this->reserved.erase(it++);
00270 }
00271 }
00272
00278 uint VehicleCargoList::LoadReserved(uint max_move)
00279 {
00280 uint orig_max = max_move;
00281 Iterator it(this->reserved.begin());
00282 while (it != this->reserved.end() && max_move > 0) {
00283 CargoPacket *cp = *it;
00284 if (cp->count <= max_move) {
00285
00286 max_move -= cp->count;
00287 this->reserved.erase(it++);
00288 this->reserved_count -= cp->count;
00289 this->Append(cp, false);
00290 } else if (CargoPacket::CanAllocateItem()) {
00291 cp->count -= max_move;
00292 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);
00293 this->Append(cp_new, false);
00294 this->reserved_count -= max_move;
00295 max_move = 0;
00296 }
00297 }
00298 return orig_max - max_move;
00299 }
00300
00311 template<class Tinst, class Tcont>
00312 uint CargoList<Tinst, Tcont>::MovePacket(VehicleCargoList *dest, Iterator &it, uint cap, TileIndex load_place, bool reserve)
00313 {
00314 CargoPacket *packet = this->RemovePacket(it, cap, load_place);
00315 uint ret = packet->count;
00316 if (reserve) {
00317 dest->Reserve(packet);
00318 } else {
00319 dest->Append(packet);
00320 }
00321 return ret;
00322 }
00323
00333 template<class Tinst, class Tcont>
00334 uint CargoList<Tinst, Tcont>::MovePacket(StationCargoList *dest, StationID next, Iterator &it, uint cap)
00335 {
00336 CargoPacket *packet = this->RemovePacket(it, cap);
00337 uint ret = packet->count;
00338 dest->Append(next, packet);
00339 return ret;
00340 }
00341
00351 template<class Tinst, class Tcont>
00352 CargoPacket *CargoList<Tinst, Tcont>::RemovePacket(Iterator &it, uint cap, TileIndex load_place)
00353 {
00354 CargoPacket *packet = *it;
00355
00356 if (packet->count > cap) {
00357
00358 packet = packet->Split(cap);
00359
00360
00361
00362
00363 if (packet == NULL) {
00364 packet = *it;
00365 uint dropped = packet->count - cap;
00366 this->count -= dropped;
00367 this->cargo_days_in_transit -= dropped * packet->days_in_transit;
00368 packet->count = cap;
00369 this->packets.erase(it++);
00370 } else {
00371 assert(packet->count == cap);
00372 ++it;
00373 }
00374 } else {
00375 this->packets.erase(it++);
00376 }
00377 static_cast<Tinst *>(this)->RemoveFromCache(packet);
00378 if (load_place != INVALID_TILE) {
00379 packet->loaded_at_xy = load_place;
00380 }
00381 return packet;
00382 }
00383
00387 template <class Tinst, class Tcont>
00388 void CargoList<Tinst, Tcont>::InvalidateCache()
00389 {
00390 this->count = 0;
00391 this->cargo_days_in_transit = 0;
00392
00393 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00394 static_cast<Tinst *>(this)->AddToCache(*it);
00395 }
00396 }
00397
00401 VehicleCargoList::~VehicleCargoList()
00402 {
00403 for (Iterator it(this->reserved.begin()); it != this->reserved.end(); ++it) {
00404 delete *it;
00405 }
00406 }
00407
00416 uint VehicleCargoList::DeliverPacket(Iterator &it, uint cap, CargoPayment *payment)
00417 {
00418 CargoPacket *p = *it;
00419 uint unloaded = 0;
00420 if (p->count <= cap) {
00421 payment->PayFinalDelivery(p, p->count);
00422 this->packets.erase(it++);
00423 this->RemoveFromCache(p);
00424 unloaded = p->count;
00425 delete p;
00426 } else {
00427 payment->PayFinalDelivery(p, cap);
00428 this->count -= cap;
00429 this->cargo_days_in_transit -= cap * p->days_in_transit;
00430 this->feeder_share -= p->feeder_share;
00431 p->feeder_share = 0;
00432 p->count -= cap;
00433 unloaded = cap;
00434 ++it;
00435 }
00436 return unloaded;
00437 }
00438
00445 uint VehicleCargoList::KeepPacket(Iterator &it)
00446 {
00447 CargoPacket *cp = *it;
00448 this->reserved.push_back(cp);
00449 this->reserved_count += cp->count;
00450 this->packets.erase(it++);
00451 return cp->count;
00452 }
00453
00465 uint VehicleCargoList::TransferPacket(Iterator &it, uint cap, StationCargoList *dest, CargoPayment *payment, StationID next)
00466 {
00467 CargoPacket *cp = this->RemovePacket(it, cap);
00468 cp->feeder_share += payment->PayTransfer(cp, cp->count);
00469 uint ret = cp->count;
00470 dest->Append(next, cp);
00471 return ret;
00472 }
00473
00483 UnloadType StationCargoList::WillUnloadOld(byte flags, StationID source)
00484 {
00485
00486 bool move = (flags & (UL_DELIVER | UL_ACCEPTED | UL_TRANSFER)) != 0;
00487
00488 bool deliver = (flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && (source != this->station->index);
00489
00490 bool transfer = (flags & (UL_TRANSFER | UL_DELIVER)) != 0;
00491 if (move) {
00492 if(deliver) {
00493 return UL_DELIVER;
00494 } else if (transfer) {
00495 return UL_TRANSFER;
00496 } else {
00497
00498
00499
00500 return UL_KEEP;
00501 }
00502 } else {
00503 return UL_KEEP;
00504 }
00505 }
00506
00520 UnloadType StationCargoList::WillUnloadCargoDist(byte flags, StationID next, StationID via, StationID source)
00521 {
00522 if (via == this->station->index) {
00523
00524 if (flags & UL_TRANSFER) {
00525
00526 return UL_TRANSFER;
00527 } else if (flags & UL_ACCEPTED) {
00528 return UL_DELIVER;
00529 } else if (flags & UL_DELIVER) {
00530
00531 return UL_TRANSFER;
00532 } else {
00533
00534 return UL_KEEP;
00535 }
00536 } else {
00537
00538 if (flags & UL_DELIVER) {
00539
00540
00541
00542 if ((flags & UL_ACCEPTED) && !(flags & UL_TRANSFER) && source != this->station->index) {
00543 return UL_DELIVER;
00544 } else {
00545
00546 return UL_TRANSFER;
00547 }
00548 } else if (flags & UL_TRANSFER) {
00549
00550 return UL_TRANSFER;
00551 } else if (next == via && next != INVALID_STATION) {
00552
00553 return UL_KEEP;
00554 } else {
00555
00556 return UL_TRANSFER;
00557 }
00558 }
00559 }
00560
00567 void VehicleCargoList::SwapReserved()
00568 {
00569 assert(this->packets.empty());
00570 this->packets.swap(this->reserved);
00571 this->reserved_count = 0;
00572 }
00573
00595 uint StationCargoList::TakeFrom(VehicleCargoList *source, uint max_unload, OrderUnloadFlags order_flags, StationID next, bool has_stopped, CargoPayment *payment)
00596 {
00597 uint remaining_unload = max_unload;
00598 uint unloaded;
00599 byte flags = this->GetUnloadFlags(order_flags);
00600 GoodsEntry *dest = &this->station->goods[this->cargo];
00601 UnloadType action;
00602
00603 for (VehicleCargoList::Iterator c = source->packets.begin(); c != source->packets.end() && remaining_unload > 0;) {
00604 StationID cargo_source = (*c)->source;
00605 FlowStatSet &flows = dest->flows[cargo_source];
00606 FlowStatSet::iterator begin = flows.begin();
00607 StationID via = (begin != flows.end() ? begin->Via() : INVALID_STATION);
00608 if (via != INVALID_STATION) {
00609
00610 action = this->WillUnloadCargoDist(flags, next, via, cargo_source);
00611 } else {
00612
00613 action = WillUnloadOld(flags, cargo_source);
00614 }
00615
00616 switch(action) {
00617 case UL_DELIVER:
00618 unloaded = source->DeliverPacket(c, remaining_unload, payment);
00619 if (via != INVALID_STATION) {
00620 if (via == this->station->index) {
00621 dest->UpdateFlowStats(flows, begin, unloaded);
00622 } else {
00623 dest->UpdateFlowStats(flows, unloaded, this->station->index);
00624 }
00625 }
00626 remaining_unload -= unloaded;
00627 break;
00628 case UL_TRANSFER:
00629
00630 if (via == this->station->index) {
00631 via = (++begin != flows.end()) ? begin->Via() : INVALID_STATION;
00632 }
00633 unloaded = source->TransferPacket(c, remaining_unload, this, payment, via);
00634 if (via != INVALID_STATION) {
00635 dest->UpdateFlowStats(flows, begin, unloaded);
00636 }
00637 remaining_unload -= unloaded;
00638 break;
00639 case UL_KEEP:
00640 unloaded = source->KeepPacket(c);
00641 if (via != INVALID_STATION && next != INVALID_STATION && !has_stopped) {
00642 if (via == next) {
00643 dest->UpdateFlowStats(flows, begin, unloaded);
00644 } else {
00645 dest->UpdateFlowStats(flows, unloaded, next);
00646 }
00647 }
00648 break;
00649 default:
00650 NOT_REACHED();
00651 }
00652 }
00653 return max_unload - remaining_unload;
00654 }
00655
00659 void VehicleCargoList::OnCleanPool()
00660 {
00661 this->reserved.clear();
00662 this->Parent::OnCleanPool();
00663 }
00664
00670 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
00671 {
00672 this->feeder_share -= cp->feeder_share;
00673 this->Parent::RemoveFromCache(cp);
00674 }
00675
00681 void VehicleCargoList::AddToCache(const CargoPacket *cp)
00682 {
00683 this->feeder_share += cp->feeder_share;
00684 this->Parent::AddToCache(cp);
00685 }
00686
00693 uint VehicleCargoList::MoveTo(VehicleCargoList *dest, uint cap)
00694 {
00695 uint orig_cap = cap;
00696 Iterator it = packets.begin();
00697 while (it != packets.end() && cap > 0) {
00698 cap -= MovePacket(dest, it, cap);
00699 }
00700 return orig_cap - cap;
00701 }
00702
00706 void VehicleCargoList::AgeCargo()
00707 {
00708 for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
00709 CargoPacket *cp = *it;
00710
00711 if (cp->days_in_transit == 0xFF) continue;
00712
00713 cp->days_in_transit++;
00714 this->cargo_days_in_transit += cp->count;
00715 }
00716 }
00717
00718
00719
00720
00721
00722
00723
00729 FORCEINLINE byte StationCargoList::GetUnloadFlags(OrderUnloadFlags order_flags)
00730 {
00731 byte flags = 0;
00732 if (HasBit(this->station->goods[this->cargo].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) {
00733 flags |= UL_ACCEPTED;
00734 }
00735 if (order_flags & OUFB_UNLOAD) {
00736 flags |= UL_DELIVER;
00737 }
00738 if (order_flags & OUFB_TRANSFER) {
00739 flags |= UL_TRANSFER;
00740 }
00741 return flags;
00742 }
00743
00752 void StationCargoList::Append(StationID next, CargoPacket *cp)
00753 {
00754 assert(cp != NULL);
00755 this->AddToCache(cp);
00756
00757 StationCargoPacketMap::List &list = this->packets[next];
00758
00759 for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) {
00760 CargoPacket *icp = *it;
00761 if (StationCargoList::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
00762 icp->Merge(cp);
00763 return;
00764 }
00765 }
00766
00767
00768 list.push_back(cp);
00769 }
00770
00780 uint StationCargoList::MovePackets(VehicleCargoList *dest, uint cap, Iterator begin, Iterator end, bool reserve)
00781 {
00782 uint orig_cap = cap;
00783 while (begin != end && cap > 0) {
00784 cap -= this->MovePacket(dest, begin, cap, this->station->xy, reserve);
00785 }
00786 return orig_cap - cap;
00787 }
00788
00797 uint StationCargoList::MoveTo(VehicleCargoList *dest, uint cap, StationID next, bool reserve)
00798 {
00799 uint orig_cap = cap;
00800 std::pair<Iterator, Iterator> bounds(this->packets.equal_range(next));
00801 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00802 if (next != INVALID_STATION && cap > 0) {
00803 bounds = this->packets.equal_range(INVALID_STATION);
00804 cap -= this->MovePackets(dest, cap, bounds.first, bounds.second, reserve);
00805 }
00806 return orig_cap - cap;
00807 }
00808
00813 void StationCargoList::RerouteStalePackets(StationID to)
00814 {
00815 std::pair<Iterator, Iterator> range(this->packets.equal_range(to));
00816 for (Iterator it(range.first); it != range.second && it.GetKey() == to;) {
00817 CargoPacket *packet = *it;
00818 this->packets.erase(it++);
00819 StationID next = this->station->goods[this->cargo].UpdateFlowStatsTransfer(packet->source, packet->count, this->station->index);
00820 assert(next != to);
00821
00822
00823
00824
00825
00826 this->packets.Insert(next, packet);
00827 }
00828 }
00829
00837 void StationCargoList::CountAndTruncate(uint max_remaining, StationCargoAmountMap &cargo_per_source)
00838 {
00839 uint prev_count = this->count;
00840 uint loop = 0;
00841 while (this->count > max_remaining) {
00842 for (Iterator it(this->packets.begin()); it != this->packets.end();) {
00843 CargoPacket *packet = *it;
00844 if (loop == 0) cargo_per_source[packet->source] += packet->count;
00845
00846 if (RandomRange(prev_count) < max_remaining) {
00847 ++it;
00848 continue;
00849 }
00850
00851 uint diff = this->count - max_remaining;
00852 if (packet->count > diff) {
00853 packet->count -= diff;
00854 this->count = max_remaining;
00855 this->cargo_days_in_transit -= packet->days_in_transit * diff;
00856 if (loop > 0) {
00857 return;
00858 } else {
00859 ++it;
00860 }
00861 } else {
00862 this->packets.erase(it++);
00863 this->RemoveFromCache(packet);
00864 delete packet;
00865 }
00866 }
00867 loop++;
00868 }
00869 }
00870
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
00897 template class CargoList<VehicleCargoList, CargoPacketList>;
00898 template class CargoList<StationCargoList, StationCargoPacketMap>;