1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 19:13:07 +01:00

Merge pull request #11884 from hdpoliveira/newsitem_queue_array

Create NewsItemQueue class
This commit is contained in:
Tulio Leao
2020-06-07 15:53:20 -03:00
committed by GitHub
2 changed files with 155 additions and 87 deletions

View File

@@ -23,7 +23,7 @@
#include "../windows/Intent.h"
#include "../world/Sprite.h"
NewsItemQueue gNewsItems;
NewsItemQueues gNewsItems;
/** rct2: 0x0097BE7C */
const uint8_t news_type_properties[] = {
@@ -39,24 +39,14 @@ const uint8_t news_type_properties[] = {
NEWS_TYPE_HAS_SUBJECT, // NEWS_ITEM_GRAPH
};
NewsItem& NewsItemQueue::Current()
NewsItem& NewsItemQueues::Current()
{
return Recent[0];
return Recent.front();
}
const NewsItem& NewsItemQueue::Current() const
const NewsItem& NewsItemQueues::Current() const
{
return Recent[0];
}
NewsItem& NewsItemQueue::Oldest()
{
return Archived[0];
}
const NewsItem& NewsItemQueue::Oldest() const
{
return Archived[0];
return Recent.front();
}
bool news_item_is_valid_idx(int32_t index)
@@ -74,25 +64,25 @@ NewsItem* news_item_get(int32_t index)
return gNewsItems.At(index);
}
NewsItem& NewsItemQueue::operator[](size_t index)
NewsItem& NewsItemQueues::operator[](size_t index)
{
return const_cast<NewsItem&>(const_cast<const NewsItemQueue&>(*this)[index]);
return const_cast<NewsItem&>(const_cast<const NewsItemQueues&>(*this)[index]);
}
const NewsItem& NewsItemQueue::operator[](size_t index) const
const NewsItem& NewsItemQueues::operator[](size_t index) const
{
if (index < NEWS_ITEM_HISTORY_START)
if (index < Recent.capacity())
return Recent[index];
else
return Archived[index - NEWS_ITEM_HISTORY_START];
return Archived[index - Recent.capacity()];
}
NewsItem* NewsItemQueue::At(int32_t index)
NewsItem* NewsItemQueues::At(int32_t index)
{
return const_cast<NewsItem*>(const_cast<const NewsItemQueue&>(*this).At(index));
return const_cast<NewsItem*>(const_cast<const NewsItemQueues&>(*this).At(index));
}
const NewsItem* NewsItemQueue::At(int32_t index) const
const NewsItem* NewsItemQueues::At(int32_t index) const
{
if (news_item_is_valid_idx(index))
{
@@ -115,25 +105,17 @@ bool news_item_is_queue_empty()
return gNewsItems.IsEmpty();
}
bool NewsItemQueue::IsEmpty() const
bool NewsItemQueues::IsEmpty() const
{
return Current().IsEmpty();
return Recent.empty();
}
/**
*
* rct2: 0x0066DF32
*/
void NewsItemQueue::Init()
{
Current().Type = NEWS_ITEM_NULL;
Oldest().Type = NEWS_ITEM_NULL;
}
void news_item_init_queue()
{
gNewsItems.Init();
// Throttles for warning types (PEEP_*_WARNING)
for (auto& warningThrottle : gPeepWarningThrottle)
{
@@ -144,7 +126,7 @@ void news_item_init_queue()
context_broadcast_intent(&intent);
}
uint16_t NewsItemQueue::IncrementTicks()
uint16_t NewsItemQueues::IncrementTicks()
{
return ++Current().Ticks;
}
@@ -160,7 +142,7 @@ static void news_item_tick_current()
}
}
int32_t NewsItemQueue::RemoveTime() const
int32_t NewsItemQueues::RemoveTime() const
{
if (!Recent[5].IsEmpty() && !Recent[4].IsEmpty() && !Recent[3].IsEmpty() && !Recent[2].IsEmpty())
{
@@ -169,7 +151,7 @@ int32_t NewsItemQueue::RemoveTime() const
return 320;
}
bool NewsItemQueue::CurrentShouldBeArchived() const
bool NewsItemQueues::CurrentShouldBeArchived() const
{
return Current().Ticks >= RemoveTime();
}
@@ -204,47 +186,25 @@ void news_item_close_current()
gNewsItems.ArchiveCurrent();
}
void NewsItemQueue::ArchiveCurrent()
void NewsItemQueues::ArchiveCurrent()
{
// Check if there is a current message
if (IsEmpty())
return;
AppendToArchive(Current());
Archived.push_back(Current());
// Invalidate the news window
window_invalidate_by_class(WC_RECENT_NEWS);
// Dequeue the current news item, shift news up
memmove(Recent, Recent + 1, sizeof(NewsItem) * (std::size(Recent) - 1));
Recent[NEWS_ITEM_HISTORY_START - 1].Type = NEWS_ITEM_NULL;
Recent.pop_front();
// Invalidate current news item bar
auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS);
context_broadcast_intent(&intent);
}
/**
* Finds a spare history slot or replaces an existing one if there are no spare
* slots available.
*/
void NewsItemQueue::AppendToArchive(NewsItem& item)
{
auto it = std::find_if(std::begin(Archived), std::end(Archived), [](const auto& newsItem) { return newsItem.IsEmpty(); });
if (it != std::end(Archived))
{
*it = item;
++it;
if (it != std::end(Archived))
it->Type = NEWS_ITEM_NULL;
return;
}
// Dequeue the first history news item, shift history up
memmove(Archived, Archived + 1, sizeof(NewsItem) * (std::size(Archived) - 1));
Archived[MAX_NEWS_ITEMS_ARCHIVE - 1] = item;
}
/**
* Get the (x,y,z) coordinates of the subject of a news item.
* If the new item is no longer valid, return LOCATION_NULL in the x-coordinate
@@ -339,17 +299,20 @@ std::optional<CoordsXYZ> news_item_get_subject_location(int32_t type, int32_t su
return subjectLoc;
}
NewsItem* NewsItemQueue::FirstOpenOrNewSlot()
NewsItem* NewsItemQueues::FirstOpenOrNewSlot()
{
auto it = std::begin(Recent);
for (; !it->IsEmpty();)
for (auto emptySlots = Recent.capacity() - Recent.size(); emptySlots < 2; ++emptySlots)
{
if (it + 2 >= std::end(Recent))
ArchiveCurrent();
else
it++;
ArchiveCurrent();
}
return &*it;
auto res = Recent.end();
// The for loop above guarantees there is always an extra element to use
assert(Recent.capacity() - Recent.size() >= 2);
auto newsItem = res + 1;
newsItem->Type = NEWS_ITEM_NULL;
return &*res;
}
/**
@@ -377,14 +340,7 @@ NewsItem* news_item_add_to_queue_raw(uint8_t type, const utf8* text, uint32_t as
newsItem->Day = ((days_in_month[date_get_month(newsItem->MonthYear)] * gDateMonthTicks) >> 16) + 1;
safe_strcpy(newsItem->Text, text, sizeof(newsItem->Text));
NewsItem* res = newsItem;
// Blatant disregard for what happens on the last element.
// TODO: Change this when we implement the queue ourselves.
newsItem++;
newsItem->Type = NEWS_ITEM_NULL;
return res;
return newsItem;
}
/**
@@ -506,8 +462,6 @@ void news_item_add_to_queue_custom(NewsItem* newNewsItem)
{
NewsItem* newsItem = gNewsItems.FirstOpenOrNewSlot();
*newsItem = *newNewsItem;
newsItem++;
newsItem->Type = NEWS_ITEM_NULL;
}
void news_item_remove(int32_t index)

View File

@@ -12,6 +12,8 @@
#include "../common.h"
#include "../world/Location.hpp"
#include <array>
#include <iterator>
#include <optional>
enum
@@ -65,7 +67,123 @@ constexpr int32_t MAX_NEWS_ITEMS = NEWS_ITEM_HISTORY_START + MAX_NEWS_ITEMS_ARCH
extern const uint8_t news_type_properties[10];
struct NewsItemQueue
template<std::size_t N> class NewsItemQueue
{
public:
static_assert(N > 0, "Cannot instantiate NewsItemQueue with size=0");
using value_type = typename std::array<NewsItem, N>::value_type;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = typename std::array<NewsItem, N>::iterator;
using const_iterator = typename std::array<NewsItem, N>::const_iterator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
NewsItemQueue()
{
Queue[0].Type = NEWS_ITEM_NULL;
}
constexpr iterator begin() noexcept
{
return std::begin(Queue);
}
constexpr const_iterator begin() const noexcept
{
return cbegin();
}
constexpr const_iterator cbegin() const noexcept
{
return std::cbegin(Queue);
}
iterator end() noexcept
{
return std::find_if(std::begin(Queue), std::end(Queue), [](const_reference item) { return item.IsEmpty(); });
}
const_iterator end() const noexcept
{
return cend();
}
const_iterator cend() const noexcept
{
return std::find_if(std::cbegin(Queue), std::cend(Queue), [](const_reference item) { return item.IsEmpty(); });
}
constexpr bool empty() const noexcept
{
return Queue[0].IsEmpty();
}
size_type size() const noexcept
{
return std::distance(cbegin(), cend());
}
reference front() noexcept
{
return *begin();
}
const_reference front() const noexcept
{
return *cbegin();
}
reference back() noexcept
{
return *end();
}
const_reference back() const noexcept
{
return *cend();
}
void pop_front()
{
std::move(std::begin(Queue) + 1, std::end(Queue), std::begin(Queue));
Queue[N - 1].Type = NEWS_ITEM_NULL;
}
void push_back(const_reference item)
{
auto it = end();
if (!std::distance(it, std::end(Queue)))
{
// Reached queue max size, need to free some space
pop_front();
Queue[N - 1] = item;
}
else
{
*it = item;
++it;
if (std::distance(it, std::end(Queue)))
it->Type = NEWS_ITEM_NULL;
}
}
reference operator[](size_type n) noexcept
{
return Queue[n];
}
const_reference operator[](size_type n) const noexcept
{
return Queue[n];
}
constexpr size_type capacity() const noexcept
{
return N;
}
private:
std::array<NewsItem, N> Queue;
};
struct NewsItemQueues
{
NewsItem& operator[](size_t index);
const NewsItem& operator[](size_t index) const;
@@ -86,8 +204,6 @@ struct NewsItemQueue
{
for (auto& newsItem : Recent)
{
if (newsItem.IsEmpty())
break;
p(newsItem);
}
}
@@ -96,8 +212,6 @@ struct NewsItemQueue
{
for (auto& newsItem : Archived)
{
if (newsItem.IsEmpty())
break;
p(newsItem);
}
}
@@ -106,11 +220,11 @@ private:
int32_t RemoveTime() const;
void AppendToArchive(NewsItem& item);
NewsItem Recent[NEWS_ITEM_HISTORY_START];
NewsItem Archived[MAX_NEWS_ITEMS_ARCHIVE];
NewsItemQueue<NEWS_ITEM_HISTORY_START> Recent;
NewsItemQueue<MAX_NEWS_ITEMS_ARCHIVE> Archived;
};
extern NewsItemQueue gNewsItems;
extern NewsItemQueues gNewsItems;
void news_item_init_queue();