(svn r26595) [1.4] -Backport from trunk:

- Fix: Transfer stations also should have a cargo rating [FS#5989] (r26581, r26580)
- Fix: [Network] AIs would not reset certain network state information upon creation of their company [FS#6003] (r26578, r26576)
- Fix: [Network] Client of non-dedicated server was not correctly put into the first company for all state variables [FS#6001] (r26577)
This commit is contained in:
frosch 2014-05-18 11:21:59 +00:00
parent 1d18ef48a4
commit 3cd96a459b
16 changed files with 86 additions and 85 deletions

View File

@ -853,59 +853,21 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
MarkWholeScreenDirty();
}
if (_network_server) {
if (ci != NULL) {
/* ci is only NULL when replaying.
* When replaying no client is actually in need of an update. */
ci->client_playas = c->index;
NetworkUpdateClientInfo(ci->client_id);
}
if (Company::IsValidID(c->index)) {
_network_company_states[c->index].months_empty = 0;
_network_company_states[c->index].password[0] = '\0';
NetworkServerUpdateCompanyPassworded(c->index, false);
/* XXX - When a client joins, we automatically set its name to the
* client's name (for some reason). As it stands now only the server
* knows the client's name, so it needs to send out a "broadcast" to
* do this. To achieve this we send a network command. However, it
* uses _local_company to execute the command as. To prevent abuse
* (eg. only yourself can change your name/company), we 'cheat' by
* impersonation _local_company as the server. Not the best solution;
* but it works.
* TODO: Perhaps this could be improved by when the client is ready
* with joining to let it send itself the command, and not the server?
* For example in network_client.c:534? */
if (ci != NULL) {
/* ci is only NULL when replaying.
* When replaying, the command to rename the president will
* automatically be ran, so this is not even needed to get
* the exact same state. */
NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index);
}
}
/* Announce new company on network. */
NetworkAdminCompanyInfo(c, true);
if (ci != NULL) {
/* ci is only NULL when replaying.
* When replaying, the message that someone started a new company
* is not interesting at all. */
NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
}
}
NetworkServerNewCompany(c, ci);
#endif /* ENABLE_NETWORK */
break;
}
case 1: // Make a new AI company
case 1: { // Make a new AI company
if (!(flags & DC_EXEC)) return CommandCost();
if (company_id != INVALID_COMPANY && (company_id >= MAX_COMPANIES || Company::IsValidID(company_id))) return CMD_ERROR;
DoStartupNewCompany(true, company_id);
Company *c = DoStartupNewCompany(true, company_id);
#ifdef ENABLE_NETWORK
if (c != NULL) NetworkServerNewCompany(c, NULL);
#endif /* ENABLE_NETWORK */
break;
}
case 2: { // Delete a company
CompanyRemoveReason reason = (CompanyRemoveReason)GB(p2, 0, 2);

View File

@ -1066,9 +1066,9 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti
/* Update station statistics */
if (accepted > 0) {
SetBit(st->goods[cargo_type].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED);
SetBit(st->goods[cargo_type].acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH);
SetBit(st->goods[cargo_type].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK);
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_EVER_ACCEPTED);
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_CURRENT_MONTH);
SetBit(st->goods[cargo_type].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
}
/* Update company statistics */
@ -1240,7 +1240,7 @@ void PrepareUnload(Vehicle *front_v)
const GoodsEntry *ge = &st->goods[v->cargo_type];
if (v->cargo_cap > 0 && v->cargo.TotalCount() > 0) {
v->cargo.Stage(
HasBit(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE),
HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE),
front_v->last_station_visited, next_station,
front_v->current_order.GetUnloadType(), ge,
front_v->cargo_payment);
@ -1510,7 +1510,7 @@ static void LoadUnloadVehicle(Vehicle *front)
payment->SetCargo(v->cargo_type);
if (!HasBit(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE) && v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER) > 0) {
if (!HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE) && v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER) > 0) {
/* The station does not accept our goods anymore. */
if (front->current_order.GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) {
/* Transfer instead of delivering. */
@ -1535,8 +1535,18 @@ static void LoadUnloadVehicle(Vehicle *front)
}
}
/* Mark the station dirty if we transfer, but not if we only deliver. */
dirty_station = v->cargo.ActionCount(VehicleCargoList::MTA_TRANSFER) > 0;
if (v->cargo.ActionCount(VehicleCargoList::MTA_TRANSFER) > 0) {
/* Mark the station dirty if we transfer, but not if we only deliver. */
dirty_station = true;
if (!ge->HasRating()) {
/* Upon transfering cargo, make sure the station has a rating. Fake a pickup for the
* first unload to prevent the cargo from quickly decaying after the initial drop. */
ge->time_since_pickup = 0;
SetBit(ge->status, GoodsEntry::GES_RATING);
}
}
amount_unloaded = v->cargo.Unload(amount_unloaded, &ge->cargo, payment);
remaining = v->cargo.UnloadCount() > 0;
if (amount_unloaded > 0) {
@ -1745,6 +1755,7 @@ static void LoadUnloadVehicle(Vehicle *front)
if (dirty_station) {
st->MarkTilesDirty(true);
SetWindowDirty(WC_STATION_VIEW, last_visited);
InvalidateWindowData(WC_STATION_LIST, last_visited);
}
}

View File

@ -179,7 +179,7 @@ NodeID LinkGraph::AddNode(const Station *st)
max(new_node + 1U, this->edges.Height()));
this->nodes[new_node].Init(st->index,
HasBit(good.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE));
HasBit(good.status, GoodsEntry::GES_ACCEPTANCE));
BaseEdge *new_edges = this->edges[new_node];

View File

@ -698,7 +698,7 @@ static void NetworkInitGameInfo()
/* There should be always space for the server. */
assert(NetworkClientInfo::CanAllocateItem());
NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST;
strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
}

View File

@ -71,7 +71,7 @@ void NetworkServerYearlyLoop();
void NetworkServerSendConfigUpdate();
void NetworkServerShowStatusToConsole();
bool NetworkServerStart();
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded);
void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci);
bool NetworkServerChangeClientName(ClientID client_id, const char *new_name);

View File

@ -2171,4 +2171,31 @@ void NetworkPrintClients()
}
}
/**
* Perform all the server specific administration of a new company.
* @param c The newly created company; can't be NULL.
* @param ci The client information of the client that made the company; can be NULL.
*/
void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci)
{
assert(c != NULL);
if (!_network_server) return;
_network_company_states[c->index].months_empty = 0;
_network_company_states[c->index].password[0] = '\0';
NetworkServerUpdateCompanyPassworded(c->index, false);
if (ci != NULL) {
/* ci is NULL when replaying, or for AIs. In neither case there is a client. */
ci->client_playas = c->index;
NetworkUpdateClientInfo(ci->client_id);
NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index);
NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);
}
/* Announce new company on network. */
NetworkAdminCompanyInfo(c, true);
}
#endif /* ENABLE_NETWORK */

View File

@ -123,6 +123,7 @@ public:
void NetworkServer_Tick(bool send_frame);
void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed = true);
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded);
/**
* Iterate over all the sockets from a given starting point.

View File

@ -378,10 +378,10 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
uint32 res = 0;
for (Station * const * st_iter = sl->Begin(); st_iter != sl->End(); st_iter++) {
const Station *st = *st_iter;
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0);
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1);
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2);
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0);
if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1);
if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2);
if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3);
}
/* Cargo triggered CB 148? */

View File

@ -394,7 +394,7 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, b
uint32 value = 0;
for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
if (HasBit(this->goods[cargo_type].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) SetBit(value, cargo_type);
if (HasBit(this->goods[cargo_type].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(value, cargo_type);
}
return value;
}
@ -426,12 +426,12 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, b
case 0x62: return ge->HasRating() ? ge->rating : 0xFFFFFFFF;
case 0x63: return ge->cargo.DaysInTransit();
case 0x64: return ge->HasVehicleEverTriedLoading() ? ge->last_speed | (ge->last_age << 8) : 0xFF00;
case 0x65: return GB(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1) << 3;
case 0x65: return GB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1) << 3;
case 0x69: {
assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 1 == (int)GoodsEntry::GES_LAST_MONTH);
assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 2 == (int)GoodsEntry::GES_CURRENT_MONTH);
assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 3 == (int)GoodsEntry::GES_ACCEPTED_BIGTICK);
return GB(ge->acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED, 4);
return GB(ge->status, GoodsEntry::GES_EVER_ACCEPTED, 4);
}
}
}
@ -441,7 +441,7 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, b
const GoodsEntry *g = &this->goods[GB(variable - 0x8C, 3, 4)];
switch (GB(variable - 0x8C, 0, 3)) {
case 0: return g->cargo.TotalCount();
case 1: return GB(min(g->cargo.TotalCount(), 4095), 0, 4) | (GB(g->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1) << 7);
case 1: return GB(min(g->cargo.TotalCount(), 4095), 0, 4) | (GB(g->status, GoodsEntry::GES_ACCEPTANCE, 1) << 7);
case 2: return g->time_since_pickup;
case 3: return g->rating;
case 4: return g->cargo.Source();

View File

@ -1597,7 +1597,7 @@ bool AfterLoadGame()
FOR_ALL_STATIONS(st) {
for (CargoID c = 0; c < NUM_CARGO; c++) {
st->goods[c].last_speed = 0;
if (st->goods[c].cargo.AvailableCount() != 0) SetBit(st->goods[c].acceptance_pickup, GoodsEntry::GES_PICKUP);
if (st->goods[c].cargo.AvailableCount() != 0) SetBit(st->goods[c].status, GoodsEntry::GES_RATING);
}
}
}

View File

@ -708,8 +708,8 @@ static bool LoadOldGood(LoadgameState *ls, int num)
if (!LoadChunk(ls, ge, goods_chunk)) return false;
SB(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge->acceptance_pickup, GoodsEntry::GES_PICKUP, 1, _cargo_source != 0xFF);
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge->status, GoodsEntry::GES_RATING, 1, _cargo_source != 0xFF);
if (GB(_waiting_acceptance, 0, 12) != 0 && CargoPacket::CanAllocateItem()) {
ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, 0, 0),
INVALID_STATION);

View File

@ -265,7 +265,7 @@ const SaveLoad *GetGoodsDesc()
{
static const SaveLoad goods_desc[] = {
SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, 0, 67),
SLE_CONDVAR(GoodsEntry, acceptance_pickup, SLE_UINT8, 68, SL_MAX_VERSION),
SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, 68, SL_MAX_VERSION),
SLE_CONDNULL(2, 51, 67),
SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8),
SLE_VAR(GoodsEntry, rating, SLE_UINT8),
@ -337,7 +337,7 @@ static void Load_STNS()
SlObject(ge, GetGoodsDesc());
SwapPackets(ge);
if (IsSavegameVersionBefore(68)) {
SB(ge->acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
if (GB(_waiting_acceptance, 0, 12) != 0) {
/* In old versions, enroute_from used 0xFF as INVALID_STATION */
StationID source = (IsSavegameVersionBefore(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
@ -351,7 +351,7 @@ static void Load_STNS()
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share);
ge->cargo.Append(cp, INVALID_STATION);
SB(ge->acceptance_pickup, GoodsEntry::GES_PICKUP, 1, 1);
SB(ge->status, GoodsEntry::GES_RATING, 1, 1);
}
}
}

View File

@ -57,6 +57,6 @@ ScriptCargoList_StationAccepting::ScriptCargoList_StationAccepting(StationID sta
Station *st = ::Station::Get(station_id);
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) this->AddItem(i);
if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) this->AddItem(i);
}
}

View File

@ -175,7 +175,7 @@ struct GoodsEntry {
* This also indicates, whether a cargo has a rating at the station.
* This flag is never cleared.
*/
GES_PICKUP,
GES_RATING,
/**
* Set when a vehicle ever delivered cargo to the station for final delivery.
@ -203,7 +203,7 @@ struct GoodsEntry {
};
GoodsEntry() :
acceptance_pickup(0),
status(0),
time_since_pickup(255),
rating(INITIAL_STATION_RATING),
last_speed(0),
@ -214,7 +214,7 @@ struct GoodsEntry {
max_waiting_cargo(0)
{}
byte acceptance_pickup; ///< Status of this cargo, see #GoodsEntryStatus.
byte status; ///< Status of this cargo, see #GoodsEntryStatus.
/**
* Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo.
@ -252,18 +252,18 @@ struct GoodsEntry {
/**
* Reports whether a vehicle has ever tried to load the cargo at this station.
* This does not imply that there was cargo available for loading. Refer to GES_PICKUP for that.
* This does not imply that there was cargo available for loading. Refer to GES_RATING for that.
* @return true if vehicle tried to load.
*/
bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; }
/**
* Does this cargo have a rating at this station?
* @return true if the cargo has a rating, i.e. pickup has been attempted.
* @return true if the cargo has a rating, i.e. cargo has been moved to the station.
*/
inline bool HasRating() const
{
return HasBit(this->acceptance_pickup, GES_PICKUP);
return HasBit(this->status, GES_RATING);
}
uint GetSumFlowVia(StationID via) const;

View File

@ -436,7 +436,7 @@ static uint GetAcceptanceMask(const Station *st)
uint mask = 0;
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) mask |= 1 << i;
if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) mask |= 1 << i;
}
return mask;
}
@ -579,7 +579,7 @@ void UpdateStationAcceptance(Station *st, bool show_msg)
}
GoodsEntry &ge = st->goods[i];
SB(ge.acceptance_pickup, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8);
if (LinkGraph::IsValidID(ge.link_graph)) {
(*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8);
}
@ -3189,7 +3189,7 @@ void TriggerWatchedCargoCallbacks(Station *st)
/* Collect cargoes accepted since the last big tick. */
uint cargoes = 0;
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
}
/* Anything to do? */
@ -3222,7 +3222,7 @@ static bool StationHandleBigTick(BaseStation *st)
TriggerWatchedCargoCallbacks(Station::From(st));
for (CargoID i = 0; i < NUM_CARGO; i++) {
ClrBit(Station::From(st)->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK);
ClrBit(Station::From(st)->goods[i].status, GoodsEntry::GES_ACCEPTED_BIGTICK);
}
}
@ -3618,8 +3618,8 @@ void StationMonthlyLoop()
FOR_ALL_STATIONS(st) {
for (CargoID i = 0; i < NUM_CARGO; i++) {
GoodsEntry *ge = &st->goods[i];
SB(ge->acceptance_pickup, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH, 1));
ClrBit(ge->acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH);
SB(ge->status, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->status, GoodsEntry::GES_CURRENT_MONTH, 1));
ClrBit(ge->status, GoodsEntry::GES_CURRENT_MONTH);
}
}
}
@ -3635,7 +3635,7 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint rad
for (CargoID i = 0; i < NUM_CARGO; i++) {
GoodsEntry *ge = &st->goods[i];
if (ge->acceptance_pickup != 0) {
if (ge->status != 0) {
ge->rating = Clamp(ge->rating + amount, 0, 255);
}
}
@ -3676,7 +3676,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT
if (!ge.HasRating()) {
InvalidateWindowData(WC_STATION_LIST, st->index);
SetBit(ge.acceptance_pickup, GoodsEntry::GES_PICKUP);
SetBit(ge.status, GoodsEntry::GES_RATING);
}
TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, type);

View File

@ -1796,7 +1796,7 @@ struct StationViewWindow : public Window {
uint32 cargo_mask = 0;
for (CargoID i = 0; i < NUM_CARGO; i++) {
if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i);
}
SetDParam(0, cargo_mask);
int bottom = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INT32_MAX, STR_STATION_VIEW_ACCEPTS_CARGO);