/** * Update signals at segments that are at both ends of * given (existent or non-existent) track * * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param track track at which ends we will update signals * @param owner owner whose signals we will update */ void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner) { assert(_globset.IsEmpty()); AddTrackToSignalBuffer(tile, track, owner); UpdateSignalsInBuffer(owner); }
/** * Update signals, starting at one side of a tile * Will check tile next to this at opposite side too * * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param side side of tile * @param owner owner whose signals we will update * @return the state of the signal segment */ SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner) { assert(_globset.IsEmpty()); _globset.Add(tile, side); return UpdateSignalsInBuffer(owner); }
/** * Update signals in buffer * Called from 'outside' */ void UpdateSignalsInBuffer() { if (!_globset.IsEmpty()) { UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; // invalidate } }
/** * Add side of tile to signal update buffer * * @param tile tile where we start * @param side side of tile * @param owner owner whose signals we will update */ void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner) { /* do not allow signal updates for two companies in one run */ assert(_globset.IsEmpty() || owner == _last_owner); _last_owner = owner; _globset.Add(tile, side); if (_globset.Items() >= SIG_GLOB_UPDATE) { /* too many items, force update */ UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; } }
/** * Add track to signal update buffer * * @param tile tile where we start * @param track track at which ends we will update signals * @param owner owner whose signals we will update */ void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner) { static const DiagDirection _search_dir_1[] = { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE }; static const DiagDirection _search_dir_2[] = { DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE }; /* do not allow signal updates for two companies in one run */ assert(_globset.IsEmpty() || owner == _last_owner); _last_owner = owner; _globset.Add(tile, _search_dir_1[track]); _globset.Add(tile, _search_dir_2[track]); if (_globset.Items() >= SIG_GLOB_UPDATE) { /* too many items, force update */ UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; } }
/** * Updates blocks in _globset buffer * * @param owner company whose signals we are updating * @return state of the first block from _globset * @pre Company::IsValidID(owner) */ static SigSegState UpdateSignalsInBuffer(Owner owner) { assert(Company::IsValidID(owner)); bool first = true; // first block? SigSegState state = SIGSEG_FREE; // value to return TileIndex tile; DiagDirection dir; while (_globset.Get(&tile, &dir)) { assert(_tbuset.IsEmpty()); assert(_tbdset.IsEmpty()); /* After updating signal, data stored are always MP_RAILWAY with signals. * Other situations happen when data are from outside functions - * modification of railbits (including both rail building and removal), * train entering/leaving block, train leaving depot... */ switch (GetTileType(tile)) { case MP_TUNNELBRIDGE: /* 'optimization assert' - do not try to update signals when it is not needed */ assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL); assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile))); _tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR); break; case MP_RAILWAY: if (IsRailDepot(tile)) { /* 'optimization assert' do not try to update signals in other cases */ assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile)); _tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside break; } /* FALL THROUGH */ case MP_STATION: case MP_ROAD: if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { /* only add to set when there is some 'interesting' track */ _tbdset.Add(tile, dir); _tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir)); break; } /* FALL THROUGH */ default: /* jump to next tile */ tile = tile + TileOffsByDiagDir(dir); dir = ReverseDiagDir(dir); if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { _tbdset.Add(tile, dir); break; } /* happens when removing a rail that wasn't connected at one or both sides */ continue; // continue the while() loop } assert(!_tbdset.Overflowed()); // it really shouldn't overflow by these one or two items assert(!_tbdset.IsEmpty()); // it wouldn't hurt anyone, but shouldn't happen too SigFlags flags = ExploreSegment(owner); if (first) { first = false; /* SIGSEG_FREE is set by default */ if (flags & SF_PBS) { state = SIGSEG_PBS; } else if ((flags & SF_TRAIN) || ((flags & SF_EXIT) && !(flags & SF_GREEN)) || (flags & SF_FULL)) { state = SIGSEG_FULL; } } /* do not do anything when some buffer was full */ if (flags & SF_FULL) { ResetSets(); // free all sets break; } UpdateSignalsAroundSegment(flags); } return state; }