diff --git a/src/client/Client.h b/src/client/Client.h index 41eeef7e2..c824d2821 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -42,7 +42,7 @@ public: UpdateInfo(int time, std::string file, BuildType type) : Major(0), Minor(0), Build(0), Time(time), File(file), Type(type) {} }; -class ThumbnailListener; +class RequestListener; class ClientListener; class Client: public Singleton { private: diff --git a/src/client/RequestBroker.cpp b/src/client/RequestBroker.cpp index e09cb5c19..8ecd5cc99 100644 --- a/src/client/RequestBroker.cpp +++ b/src/client/RequestBroker.cpp @@ -3,7 +3,7 @@ #include #include #include "RequestBroker.h" -#include "ThumbnailListener.h" +#include "RequestListener.h" #include "Client.h" #include "HTTP.h" #include "GameSave.h" @@ -15,14 +15,18 @@ RequestBroker::RequestBroker() { thumbnailQueueRunning = false; - //thumbnailQueueMutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_init (&thumbnailQueueMutex, NULL); //listenersMutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_init (&listenersMutex, NULL); pthread_mutex_init (&runningMutex, NULL); + + + pthread_mutex_init (&requestQueueMutex, NULL); + + + pthread_mutex_init (&completeQueueMutex, NULL); } RequestBroker::~RequestBroker() @@ -58,38 +62,63 @@ void RequestBroker::Shutdown() else pthread_mutex_unlock(&runningMutex); - - for (std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) + std::vector::iterator req = activeRequests.begin(); + while(req != activeRequests.end()) { - ThumbnailRequest req = *iter; - if(req.HTTPContext) - { - http_async_req_close(req.HTTPContext); - } + (*req)->Cleanup(); + delete (*req); + req++; } } -void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener) +void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, RequestListener * tListener) { RenderThumbnail(gameSave, true, true, width, height, tListener); } -void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener) +void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, RequestListener * tListener) { - AttachThumbnailListener(tListener); - pthread_mutex_lock(&thumbnailQueueMutex); - renderRequests.push_back(ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, ListenerHandle(tListener->ListenerRand, tListener))); - pthread_mutex_unlock(&thumbnailQueueMutex); + ListenerHandle handle = AttachRequestListener(tListener); + + ThumbRenderRequest * r = new ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, handle); + + pthread_mutex_lock(&requestQueueMutex); + requestQueue.push_back(r); + pthread_mutex_unlock(&requestQueueMutex); assureRunning(); } -void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener) +void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener) { - AttachThumbnailListener(tListener); - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailRequests.push_back(ThumbnailRequest(saveID, saveDate, width, height, ListenerHandle(tListener->ListenerRand, tListener))); - pthread_mutex_unlock(&thumbnailQueueMutex); + std::stringstream urlStream; + urlStream << "http://" << STATICSERVER << "/" << saveID; + if(saveDate) + { + urlStream << "_" << saveDate; + } + urlStream << "_small.pti"; + + RetrieveImage(urlStream.str(), width, height, tListener); +} + +void RequestBroker::RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener) +{ + std::stringstream urlStream; + urlStream << "http://" << STATICSERVER << "/avatars/" << username << ".pti"; + + RetrieveImage(urlStream.str(), width, height, tListener); +} + +void RequestBroker::RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener) +{ + ListenerHandle handle = AttachRequestListener(tListener); + + ImageRequest * r = new ImageRequest(imageUrl, width, height, handle); + + pthread_mutex_lock(&requestQueueMutex); + requestQueue.push_back(r); + pthread_mutex_unlock(&requestQueueMutex); assureRunning(); } @@ -102,23 +131,24 @@ void * RequestBroker::thumbnailQueueProcessHelper(void * ref) void RequestBroker::FlushThumbQueue() { - pthread_mutex_lock(&thumbnailQueueMutex); - while(thumbnailComplete.size()) + pthread_mutex_lock(&completeQueueMutex); + while(completeQueue.size()) { - if(CheckThumbnailListener(thumbnailComplete.front().first)) + if(CheckRequestListener(completeQueue.front()->Listener)) { - thumbnailComplete.front().first.second->OnThumbnailReady(thumbnailComplete.front().second); + completeQueue.front()->Listener.second->OnResponseReady(completeQueue.front()->ResultObject); } else { #ifdef DEBUG std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl; #endif - delete thumbnailComplete.front().second; + completeQueue.front()->Cleanup(); } - thumbnailComplete.pop_front(); + delete completeQueue.front(); + completeQueue.pop(); } - pthread_mutex_unlock(&thumbnailQueueMutex); + pthread_mutex_unlock(&completeQueueMutex); } void RequestBroker::thumbnailQueueProcessTH() @@ -150,216 +180,211 @@ void RequestBroker::thumbnailQueueProcessTH() break; } - - //Renderer - pthread_mutex_lock(&thumbnailQueueMutex); - if(renderRequests.size()) + if(activeRequests.size()) { - lastAction = time(NULL); - ThumbRenderRequest req; - req = renderRequests.front(); - renderRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Processing render request" << std::endl; -#endif - - Thumbnail * thumbnail = SaveRenderer::Ref().Render(req.Save, req.Decorations, req.Fire); - delete req.Save; - - if(thumbnail) + std::vector::iterator req = activeRequests.begin(); + while(req != activeRequests.end()) { - thumbnail->Resize(req.Width, req.Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair(req.CompletedListener, thumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { - pthread_mutex_unlock(&thumbnailQueueMutex); - } - - //Renderer - pthread_mutex_lock(&thumbnailQueueMutex); - if(thumbnailRequests.size()) - { - lastAction = time(NULL); - Thumbnail * thumbnail = NULL; - - ThumbnailRequest req; - req = thumbnailRequests.front(); - - //Check the cache - for(std::deque >::iterator iter = thumbnailCache.begin(), end = thumbnailCache.end(); iter != end; ++iter) - { - if((*iter).first == req.ID) + ProcessResponse resultStatus = OK; + Request * r = *req; + switch(r->Type) { - thumbnail = (*iter).second; -#ifdef DEBUG - std::cout << typeid(*this).name() << " " << req.ID.SaveID << ":" << req.ID.SaveDate << " found in cache" << std::endl; -#endif + case Request::ThumbnailRender: + resultStatus = processThumbnailRender(*(ThumbRenderRequest*)r); + break; + case Request::Image: + resultStatus = processImage(*(ImageRequest*)r); + break; } - } - - if(thumbnail) - { - //Got thumbnail from cache - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - - for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) + if(resultStatus == Duplicate || resultStatus == Failed || resultStatus == Finished) { - Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); - tempThumbnail->Resize((*specIter).Width, (*specIter).Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { - //Check for ongoing requests - bool requested = false; - for(std::list::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter) - { - if((*iter).ID == req.ID) - { - requested = true; - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " found, appending." << std::endl; -#endif - - //Add the current listener to the item already being requested - (*iter).SubRequests.push_back(req.SubRequests.front()); - } - } - - if(requested) - { - //Already requested - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - else if(currentRequests.size() < IMGCONNS) //If it's not already being requested and we still have more space for a new connection, request it - { - thumbnailRequests.pop_front(); - pthread_mutex_unlock(&thumbnailQueueMutex); - - //If it's not already being requested, request it - std::stringstream urlStream; - urlStream << "http://" << STATICSERVER << "/" << req.ID.SaveID; - if(req.ID.SaveDate) - { - urlStream << "_" << req.ID.SaveDate; - } - urlStream << "_small.pti"; - -#ifdef DEBUG - std::cout << typeid(*this).name() << " Creating new request for " << req.ID.SaveID << ":" << req.ID.SaveDate << std::endl; -#endif - - req.HTTPContext = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 0); - req.RequestTime = time(NULL); - currentRequests.push_back(req); + req = activeRequests.erase(req); } else { - //Already full of requests - pthread_mutex_unlock(&thumbnailQueueMutex); - + req++; } } - } - else - { - pthread_mutex_unlock(&thumbnailQueueMutex); - } - - std::list::iterator iter = currentRequests.begin(); - while (iter != currentRequests.end()) - { lastAction = time(NULL); - - ThumbnailRequest req = *iter; - Thumbnail * thumbnail = NULL; - - if(http_async_req_status(req.HTTPContext)) - { - - pixel * thumbData; - char * data; - int status, data_size, imgw, imgh; - data = http_async_req_stop(req.HTTPContext, &status, &data_size); - - if (status == 200 && data) - { - thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh); - free(data); - - if(thumbData) - { - thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, thumbData, ui::Point(imgw, imgh)); - free(thumbData); - } - else - { - //Error thumbnail - VideoBuffer errorThumb(128, 128); - errorThumb.SetCharacter(64, 64, 'x', 255, 255, 255, 255); - - thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, errorThumb.Buffer, ui::Point(errorThumb.Width, errorThumb.Height)); - } - - if(thumbnailCache.size() >= THUMB_CACHE_SIZE) - { - delete thumbnailCache.front().second; - thumbnailCache.pop_front(); - } - thumbnailCache.push_back(std::pair(req.ID, thumbnail)); - - for(std::vector::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter) - { - Thumbnail * tempThumbnail = new Thumbnail(*thumbnail); - tempThumbnail->Resize((*specIter).Width, (*specIter).Height); - - pthread_mutex_lock(&thumbnailQueueMutex); - thumbnailComplete.push_back(std::pair((*specIter).CompletedListener, tempThumbnail)); - pthread_mutex_unlock(&thumbnailQueueMutex); - } - } - else - { -#ifdef DEBUG - std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " failed with status " << status << std::endl; -#endif - if(data) - free(data); - } - iter = currentRequests.erase(iter); - } - else - { - ++iter; - } } + //Move any items from the request queue to the processing queue + pthread_mutex_lock(&requestQueueMutex); + std::vector::iterator newReq = requestQueue.begin(); + while(newReq != requestQueue.end()) + { + if(activeRequests.size() > 5) + { + break; + } + else + { + activeRequests.push_back(*newReq); + newReq = requestQueue.erase(newReq); + } + } + pthread_mutex_unlock(&requestQueueMutex); } pthread_mutex_lock(&runningMutex); thumbnailQueueRunning = false; pthread_mutex_unlock(&runningMutex); } -void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener) +RequestBroker::ProcessResponse RequestBroker::processThumbnailRender(ThumbRenderRequest & request) +{ +#ifdef DEBUG + std::cout << typeid(*this).name() << " Processing render request" << std::endl; +#endif + Thumbnail * thumbnail = SaveRenderer::Ref().Render(request.Save, request.Decorations, request.Fire); + delete request.Save; + request.Save = NULL; + + if(thumbnail) + { + thumbnail->Resize(request.Width, request.Height); + request.ResultObject = (void*)thumbnail; + requestComplete(&request); + return Finished; + } + else + { + return Failed; + } + return Failed; +} + +RequestBroker::ProcessResponse RequestBroker::processImage(ImageRequest & request) +{ + VideoBuffer * image = NULL; + + //Have a look at the thumbnail cache + for(std::deque >::iterator iter = imageCache.begin(), end = imageCache.end(); iter != end; ++iter) + { + if((*iter).first == request.URL) + { + image = (*iter).second; +#ifdef DEBUG + std::cout << typeid(*this).name() << " " << request.URL << " found in cache" << std::endl; +#endif + } + } + + if(!image) + { + if(request.HTTPContext) + { + if(http_async_req_status(request.HTTPContext)) + { + pixel * imageData; + char * data; + int status, data_size, imgw, imgh; + data = http_async_req_stop(request.HTTPContext, &status, &data_size); + + if (status == 200 && data) + { + imageData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh); + free(data); + + if(imageData) + { + //Success! + image = new VideoBuffer(imageData, imgw, imgh); + free(imageData); + } + else + { + //Error thumbnail + image = new VideoBuffer(32, 32); + image->SetCharacter(14, 14, 'x', 255, 255, 255, 255); + } + + if(imageCache.size() >= THUMB_CACHE_SIZE) + { + //Remove unnecessary from thumbnail cache + delete imageCache.front().second; + imageCache.pop_front(); + } + imageCache.push_back(std::pair(request.URL, image)); + } + else + { + #ifdef DEBUG + std::cout << typeid(*this).name() << " Request for " << request.URL << " failed with status " << status << std::endl; + #endif + if(data) + free(data); + + return Failed; + } + } + } + else + { + //Check for ongoing requests + for(std::vector::iterator iter = activeRequests.begin(), end = activeRequests.end(); iter != end; ++iter) + { + if((*iter)->Type != Request::Image) + continue; + ImageRequest * otherReq = (ImageRequest*)(*iter); + if(otherReq->URL == request.URL && otherReq != &request) + { + #ifdef DEBUG + std::cout << typeid(*this).name() << " Request for " << request.URL << " found, appending." << std::endl; + #endif + //Add the current listener to the item already being requested + (*iter)->Children.push_back(&request); + return Duplicate; + } + } + + //If it's not already being requested, request it + #ifdef DEBUG + std::cout << typeid(*this).name() << " Creating new request for " << request.URL << std::endl; + #endif + request.HTTPContext = http_async_req_start(NULL, (char *)request.URL.c_str(), NULL, 0, 0); + request.RequestTime = time(NULL); + } + } + + if(image) + { + + //Create a copy, to seperate from the cache + VideoBuffer * myVB = new VideoBuffer(*image); + myVB->Resize(request.Width, request.Height, true); + request.ResultObject = (void*)myVB; + requestComplete(&request); + for(std::vector::iterator childIter = request.Children.begin(), childEnd = request.Children.end(); childIter != childEnd; ++childIter) + { + if((*childIter)->Type == Request::Image) + { + ImageRequest * childReq = (ImageRequest*)*childIter; + VideoBuffer * tempImage = new VideoBuffer(*image); + tempImage->Resize(childReq->Width, childReq->Height, true); + childReq->ResultObject = (void*)tempImage; + requestComplete(*childIter); + } + } + return Finished; + } + + return OK; +} + +void RequestBroker::requestComplete(Request * completedRequest) +{ + pthread_mutex_lock(&completeQueueMutex); + completeQueue.push(completedRequest); + pthread_mutex_unlock(&completeQueueMutex); +} + + +void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener) { RetrieveThumbnail(saveID, 0, width, height, tListener); } -bool RequestBroker::CheckThumbnailListener(ListenerHandle handle) +bool RequestBroker::CheckRequestListener(ListenerHandle handle) { pthread_mutex_lock(&listenersMutex); int count = std::count(validListeners.begin(), validListeners.end(), handle); @@ -368,14 +393,16 @@ bool RequestBroker::CheckThumbnailListener(ListenerHandle handle) return count; } -void RequestBroker::AttachThumbnailListener(ThumbnailListener * tListener) +ListenerHandle RequestBroker::AttachRequestListener(RequestListener * tListener) { + ListenerHandle handle = ListenerHandle(tListener->ListenerRand, tListener); pthread_mutex_lock(&listenersMutex); - validListeners.push_back(ListenerHandle(tListener->ListenerRand, tListener)); + validListeners.push_back(handle); pthread_mutex_unlock(&listenersMutex); + return handle; } -void RequestBroker::DetachThumbnailListener(ThumbnailListener * tListener) +void RequestBroker::DetachRequestListener(RequestListener * tListener) { pthread_mutex_lock(&listenersMutex); diff --git a/src/client/RequestBroker.h b/src/client/RequestBroker.h index b3d1fc378..9244e9158 100644 --- a/src/client/RequestBroker.h +++ b/src/client/RequestBroker.h @@ -9,113 +9,147 @@ #include "Singleton.h" class GameSave; -class Thumbnail; -class ThumbnailListener; -typedef std::pair ListenerHandle; +class VideoBuffer; +class RequestListener; +typedef std::pair ListenerHandle; class RequestBroker: public Singleton { private: - class ThumbnailSpec - { - public: - int Width, Height; - ListenerHandle CompletedListener; - ThumbnailSpec(int width, int height, ListenerHandle completedListener) : - Width(width), Height(height), CompletedListener(completedListener) {} - }; - class ThumbnailID + enum ProcessResponse { Finished, OK, Canceled, Failed, Duplicate }; + + class Request { public: - int SaveID, SaveDate; - bool operator ==(const ThumbnailID & second) + enum RequestType { ThumbnailRender, Image }; + RequestType Type; + void * ResultObject; + ListenerHandle Listener; + std::vector Children; + Request(RequestType type, ListenerHandle listener) { - return SaveID == second.SaveID && SaveDate == second.SaveDate; + Type = type; + Listener = listener; + ResultObject = NULL; } - ThumbnailID(int saveID, int saveDate) : SaveID(saveID), SaveDate(saveDate) {} - ThumbnailID() : SaveID(0), SaveDate(0) {} - }; - - class ThumbnailRequest - { - public: - bool Complete; - void * HTTPContext; - int RequestTime; - - ThumbnailID ID; - std::vector SubRequests; - - ThumbnailRequest(int saveID, int saveDate, int width, int height, ListenerHandle completedListener) : - ID(saveID, saveDate), Complete(false), HTTPContext(NULL), RequestTime(0) + virtual ~Request() + { + std::vector::iterator iter = Children.begin(); + while(iter != Children.end()) { - SubRequests.push_back(ThumbnailSpec(width, height, completedListener)); + delete (*iter); + iter++; } - ThumbnailRequest() : Complete(false), HTTPContext(NULL), RequestTime(0) {} + } + virtual void Cleanup() + { + std::vector::iterator iter = Children.begin(); + while(iter != Children.end()) + { + (*iter)->Cleanup(); + iter++; + } + } }; - class ThumbRenderRequest + class ThumbRenderRequest: public Request { public: int Width, Height; bool Decorations; bool Fire; GameSave * Save; - ListenerHandle CompletedListener; - ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle completedListener) : - Save(save), Width(width), Height(height), CompletedListener(completedListener), Decorations(decorations), Fire(fire) {} - ThumbRenderRequest() : Save(0), Decorations(true), Fire(true), Width(0), Height(0), CompletedListener(ListenerHandle(0, (ThumbnailListener*)NULL)) {} + ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle listener): + Request(ThumbnailRender, listener) + { + Save = save; + Width = width; + Height = height; + Decorations = decorations; + Fire = fire; + } + virtual ~ThumbRenderRequest() + { + if(Save) + delete Save; + } + virtual void Cleanup() + { + Request::Cleanup(); + if(ResultObject) + { + delete ((VideoBuffer*)ResultObject); + ResultObject = NULL; + } + } }; - class Request + class ImageRequest: public Request { - enum RequestType { Thumbnail, ThumbnailRender, HTTP }; public: - RequestType Type; - void * RequestObject; - ListenerHandle Listener; + int Width, Height; + std::string URL; + int RequestTime; + void * HTTPContext; + ImageRequest(std::string url, int width, int height, ListenerHandle listener): + Request(Image, listener) + { + URL = url; + HTTPContext = NULL; + Width = width; + Height = height; + } + virtual ~ImageRequest() {} + virtual void Cleanup() + { + Request::Cleanup(); + if(ResultObject) + { + delete ((VideoBuffer*)ResultObject); + ResultObject = NULL; + } + } }; - //Thumbnail retreival - /*int thumbnailCacheNextID; - Thumbnail * thumbnailCache[THUMB_CACHE_SIZE]; - void * activeThumbRequests[IMGCONNS]; - int activeThumbRequestTimes[IMGCONNS]; - int activeThumbRequestCompleteTimes[IMGCONNS]; - std::string activeThumbRequestIDs[IMGCONNS];*/ - - pthread_mutex_t thumbnailQueueMutex; pthread_mutex_t listenersMutex; pthread_mutex_t runningMutex; + pthread_mutex_t requestQueueMutex; + pthread_mutex_t completeQueueMutex; + pthread_t thumbnailQueueThread; bool thumbnailQueueRunning; - std::deque thumbnailRequests; - std::deque renderRequests; - - std::deque > thumbnailComplete; - std::list currentRequests; - std::deque > thumbnailCache; std::vector validListeners; - std::deque requestQueue; + std::deque > imageCache; + + std::queue completeQueue; + std::vector requestQueue; + std::vector activeRequests; static void * thumbnailQueueProcessHelper(void * ref); void thumbnailQueueProcessTH(); void assureRunning(); + ProcessResponse processThumbnailRender(ThumbRenderRequest & request); + ProcessResponse processImage(ImageRequest & request); + + void requestComplete(Request * completedRequest); + public: RequestBroker(); virtual ~RequestBroker(); void Shutdown(); void FlushThumbQueue(); - void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener); - void RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener); - void RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener); - void RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener); + void RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener); + void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, RequestListener * tListener); + void RenderThumbnail(GameSave * gameSave, int width, int height, RequestListener * tListener); + void RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener); + void RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener); + void RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener); - bool CheckThumbnailListener(ListenerHandle handle); - void AttachThumbnailListener(ThumbnailListener * tListener); - void DetachThumbnailListener(ThumbnailListener * tListener); + bool CheckRequestListener(ListenerHandle handle); + ListenerHandle AttachRequestListener(RequestListener * tListener); + void DetachRequestListener(RequestListener * tListener); }; \ No newline at end of file diff --git a/src/client/RequestListener.h b/src/client/RequestListener.h new file mode 100644 index 000000000..1f53b2a89 --- /dev/null +++ b/src/client/RequestListener.h @@ -0,0 +1,11 @@ +#pragma once + +class RequestListener +{ +public: + int ListenerRand; + RequestListener() { ListenerRand = rand(); } + virtual ~RequestListener() {} + + virtual void OnResponseReady(void * response) {} +}; diff --git a/src/client/ThumbnailListener.h b/src/client/ThumbnailListener.h deleted file mode 100644 index 97bdef5e0..000000000 --- a/src/client/ThumbnailListener.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -class Thumbnail; -class ThumbnailListener -{ -public: - int ListenerRand; - ThumbnailListener() { ListenerRand = rand(); } - virtual ~ThumbnailListener() {} - - virtual void OnThumbnailReady(Thumbnail * thumb) {} -}; diff --git a/src/interface/AvatarButton.cpp b/src/interface/AvatarButton.cpp index 0343aed33..0a55ffa61 100644 --- a/src/interface/AvatarButton.cpp +++ b/src/interface/AvatarButton.cpp @@ -5,6 +5,7 @@ #include "Format.h" #include "Engine.h" #include "client/Client.h" +#include "client/RequestBroker.h" #include "graphics/Graphics.h" #include "ContextMenu.h" #include "Keys.h" @@ -23,6 +24,7 @@ AvatarButton::AvatarButton(Point position, Point size, std::string username): AvatarButton::~AvatarButton() { + RequestBroker::Ref().DetachRequestListener(this); if(avatar) delete avatar; if(actionCallback) @@ -34,13 +36,18 @@ void AvatarButton::Tick(float dt) if(!avatar && !tried && name.size() > 0) { tried = true; - avatar = Client::Ref().GetAvatar(name); - if(avatar) { - if(avatar->Width != Size.X && avatar->Height != Size.Y) - { - avatar->Resize(Size.X, Size.Y, true); - } - } + RequestBroker::Ref().RetrieveAvatar(name, Size.X, Size.Y, this); + } +} + +void AvatarButton::OnResponseReady(void * imagePtr) +{ + VideoBuffer * image = (VideoBuffer*)imagePtr; + if(image) + { + if(avatar) + delete avatar; + avatar = image; } } diff --git a/src/interface/AvatarButton.h b/src/interface/AvatarButton.h index b336256f9..d946ddf17 100644 --- a/src/interface/AvatarButton.h +++ b/src/interface/AvatarButton.h @@ -6,6 +6,7 @@ #include "Component.h" #include "graphics/Graphics.h" #include "interface/Colour.h" +#include "client/RequestListener.h" namespace ui { @@ -17,7 +18,7 @@ public: virtual ~AvatarButtonAction() {} }; -class AvatarButton : public Component +class AvatarButton : public Component, public RequestListener { VideoBuffer * avatar; std::string name; @@ -37,6 +38,8 @@ public: virtual void Draw(const Point& screenPos); virtual void Tick(float dt); + virtual void OnResponseReady(void * imagePtr); + virtual void DoAction(); void SetUsername(std::string username) { name = username; } diff --git a/src/interface/SaveButton.cpp b/src/interface/SaveButton.cpp index 6e42169cc..87b80a61d 100644 --- a/src/interface/SaveButton.cpp +++ b/src/interface/SaveButton.cpp @@ -117,7 +117,7 @@ SaveButton::SaveButton(Point position, Point size, SaveFile * file): SaveButton::~SaveButton() { - RequestBroker::Ref().DetachThumbnailListener(this); + RequestBroker::Ref().DetachRequestListener(this); if(thumbnail) delete thumbnail; @@ -129,13 +129,14 @@ SaveButton::~SaveButton() delete file; } -void SaveButton::OnThumbnailReady(Thumbnail * thumb) +void SaveButton::OnResponseReady(void * imagePtr) { - if(thumb) + VideoBuffer * image = (VideoBuffer*)imagePtr; + if(image) { if(thumbnail) delete thumbnail; - thumbnail = thumb; + thumbnail = image; waitingForThumb = false; } } @@ -144,23 +145,25 @@ void SaveButton::Tick(float dt) { if(!thumbnail && !waitingForThumb) { + float scaleFactor = (Size.Y-25)/((float)YRES); + ui::Point thumbBoxSize = ui::Point(((float)XRES)*scaleFactor, ((float)YRES)*scaleFactor); if(save) { if(save->GetGameSave()) { waitingForThumb = true; - RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this); } else if(save->GetID()) { waitingForThumb = true; - RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), thumbBoxSize.X, thumbBoxSize.Y, this); } } else if(file && file->GetGameSave()) { waitingForThumb = true; - RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), Size.X-3, Size.Y-25, this); + RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this); } } } @@ -180,11 +183,11 @@ void SaveButton::Draw(const Point& screenPos) if(thumbnail) { - thumbBoxSize = ui::Point(thumbnail->Size.X, thumbnail->Size.Y); + thumbBoxSize = ui::Point(thumbnail->Width, thumbnail->Height); if(save && save->id) - g->draw_image(thumbnail->Data, screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbnail->Size.X, thumbnail->Size.Y, 255); + g->draw_image(thumbnail, screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255); else - g->draw_image(thumbnail->Data, screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbnail->Size.X, thumbnail->Size.Y, 255); + g->draw_image(thumbnail, screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255); } else { diff --git a/src/interface/SaveButton.h b/src/interface/SaveButton.h index 7a7597352..e03d48aa6 100644 --- a/src/interface/SaveButton.h +++ b/src/interface/SaveButton.h @@ -6,9 +6,8 @@ #include "Component.h" #include "client/SaveFile.h" #include "client/SaveInfo.h" -#include "client/ThumbnailListener.h" +#include "client/RequestListener.h" #include "graphics/Graphics.h" -#include "search/Thumbnail.h" #include "interface/Colour.h" namespace ui @@ -24,11 +23,11 @@ public: virtual ~SaveButtonAction() {} }; -class SaveButton : public Component, public ThumbnailListener +class SaveButton : public Component, public RequestListener { SaveFile * file; SaveInfo * save; - Thumbnail * thumbnail; + VideoBuffer * thumbnail; std::string name; std::string votesString; std::string votesBackground; @@ -59,7 +58,7 @@ public: virtual void Draw(const Point& screenPos); virtual void Tick(float dt); - virtual void OnThumbnailReady(Thumbnail * thumb); + virtual void OnResponseReady(void * imagePtr); void SetSelected(bool selected_) { selected = selected_; } bool GetSelected() { return selected; } diff --git a/src/preview/PreviewView.cpp b/src/preview/PreviewView.cpp index b9bae9a18..5b9ea9b77 100644 --- a/src/preview/PreviewView.cpp +++ b/src/preview/PreviewView.cpp @@ -543,15 +543,15 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) int usernameY = currentY+5, commentY; if(showAvatars) { - tempAvatar = new ui::AvatarButton(ui::Point(4, currentY+4), ui::Point(26, 26), comments->at(i)->authorName); + tempAvatar = new ui::AvatarButton(ui::Point(2, currentY+7), ui::Point(26, 26), comments->at(i)->authorName); commentComponents.push_back(tempAvatar); commentsPanel->AddChild(tempAvatar); } if(showAvatars) - tempUsername = new ui::Label(ui::Point(31, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); + tempUsername = new ui::Label(ui::Point(31, currentY+3), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); else - tempUsername = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); + tempUsername = new ui::Label(ui::Point(5, currentY+3), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName); tempUsername->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempUsername->Appearance.VerticalAlign = ui::Appearance::AlignBottom; currentY += 16; @@ -560,7 +560,10 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) commentsPanel->AddChild(tempUsername); commentY = currentY+5; - tempComment = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), -1), comments->at(i)->comment); + if(showAvatars) + tempComment = new ui::Label(ui::Point(31, currentY+5), ui::Point(Size.X-((XRES/2) + 13 + 26), -1), comments->at(i)->comment); + else + tempComment = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), -1), comments->at(i)->comment); tempComment->SetMultiline(true); tempComment->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempComment->Appearance.VerticalAlign = ui::Appearance::AlignTop; diff --git a/src/save/LocalSaveActivity.cpp b/src/save/LocalSaveActivity.cpp index 193f0aaf2..58c9a63f1 100644 --- a/src/save/LocalSaveActivity.cpp +++ b/src/save/LocalSaveActivity.cpp @@ -123,14 +123,14 @@ void LocalSaveActivity::OnDraw() if(thumbnail) { - g->draw_image(thumbnail->Data, Position.X+(Size.X-thumbnail->Size.X)/2, Position.Y+45, thumbnail->Size.X, thumbnail->Size.Y, 255); - g->drawrect(Position.X+(Size.X-thumbnail->Size.X)/2, Position.Y+45, thumbnail->Size.X, thumbnail->Size.Y, 180, 180, 180, 255); + g->draw_image(thumbnail, Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, 255); + g->drawrect(Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255); } } -void LocalSaveActivity::OnThumbnailReady(Thumbnail * thumbnail) +void LocalSaveActivity::OnRequestReady(void * imagePtr) { - this->thumbnail = thumbnail; + this->thumbnail = (VideoBuffer*)imagePtr; } LocalSaveActivity::~LocalSaveActivity() diff --git a/src/save/LocalSaveActivity.h b/src/save/LocalSaveActivity.h index aacbc0b67..dd33fc414 100644 --- a/src/save/LocalSaveActivity.h +++ b/src/save/LocalSaveActivity.h @@ -2,14 +2,14 @@ #include "Activity.h" #include "client/SaveFile.h" -#include "client/ThumbnailListener.h" +#include "client/RequestListener.h" namespace ui { class Textbox; } -class Thumbnail; +class VideoBuffer; class FileSavedCallback { @@ -19,10 +19,10 @@ public: virtual void FileSaved(SaveFile * file) {} }; -class LocalSaveActivity: public WindowActivity, public ThumbnailListener +class LocalSaveActivity: public WindowActivity, public RequestListener { SaveFile save; - Thumbnail * thumbnail; + VideoBuffer * thumbnail; ui::Textbox * filenameField; class CancelAction; class SaveAction; @@ -34,6 +34,6 @@ public: void saveWrite(std::string finalFilename); virtual void Save(); virtual void OnDraw(); - virtual void OnThumbnailReady(Thumbnail * thumbnail); + virtual void OnRequestReady(void * imagePtr); virtual ~LocalSaveActivity(); }; \ No newline at end of file diff --git a/src/save/ServerSaveActivity.cpp b/src/save/ServerSaveActivity.cpp index fc108142a..1481b6df9 100644 --- a/src/save/ServerSaveActivity.cpp +++ b/src/save/ServerSaveActivity.cpp @@ -3,7 +3,6 @@ #include "interface/Textbox.h" #include "interface/Button.h" #include "interface/Checkbox.h" -#include "search/Thumbnail.h" #include "client/RequestBroker.h" #include "dialogues/ErrorMessage.h" #include "dialogues/ConfirmPrompt.h" @@ -245,14 +244,14 @@ void ServerSaveActivity::OnDraw() if(thumbnail) { - g->draw_image(thumbnail->Data, Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Size.X)/2, Position.Y+25, thumbnail->Size.X, thumbnail->Size.Y, 255); - g->drawrect(Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Size.X)/2, Position.Y+25, thumbnail->Size.X, thumbnail->Size.Y, 180, 180, 180, 255); + g->draw_image(thumbnail, Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, 255); + g->drawrect(Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255); } } -void ServerSaveActivity::OnThumbnailReady(Thumbnail * thumbnail) +void ServerSaveActivity::OnRequestReady(void * imagePtr) { - this->thumbnail = thumbnail; + this->thumbnail = (VideoBuffer *)imagePtr; } ServerSaveActivity::~ServerSaveActivity() diff --git a/src/save/ServerSaveActivity.h b/src/save/ServerSaveActivity.h index 5f4cdfefc..9e3774842 100644 --- a/src/save/ServerSaveActivity.h +++ b/src/save/ServerSaveActivity.h @@ -2,7 +2,7 @@ #include "Activity.h" #include "client/SaveInfo.h" -#include "client/ThumbnailListener.h" +#include "client/RequestListener.h" #include "tasks/TaskListener.h" namespace ui @@ -13,7 +13,7 @@ namespace ui class Task; class Thumbnail; -class ServerSaveActivity: public WindowActivity, public ThumbnailListener, public TaskListener +class ServerSaveActivity: public WindowActivity, public RequestListener, public TaskListener { public: class SaveUploadedCallback @@ -29,7 +29,7 @@ public: virtual void Save(); virtual void Exit(); virtual void OnDraw(); - virtual void OnThumbnailReady(Thumbnail * thumbnail); + virtual void OnRequestReady(void * imagePtr); virtual void OnTick(float dt); virtual ~ServerSaveActivity(); protected: @@ -37,7 +37,7 @@ protected: Task * saveUploadTask; SaveUploadedCallback * callback; SaveInfo save; - Thumbnail * thumbnail; + VideoBuffer * thumbnail; ui::Textbox * nameField; ui::Textbox * descriptionField; ui::Checkbox * publishedCheckbox;