2025-07-06 20:43:53 +03:00
# include "ResourceManager.hpp"
2025-12-16 12:02:08 +03:00
# include <Helpers/Networking/NetLibrary.hpp>
2025-07-06 20:43:53 +03:00
# include <include/core/SkImage.h>
2025-12-16 12:02:08 +03:00
# include <Helpers/NetworkingObjects/NetObjID.hpp>
2025-08-07 12:44:31 +03:00
# include "ResourceDisplay/SvgResourceDisplay.hpp"
2025-12-17 14:46:27 +03:00
# include "CommandList.hpp"
2025-07-06 20:43:53 +03:00
# include "ResourceDisplay/ImageResourceDisplay.hpp"
# include "ResourceDisplay/FileResourceDisplay.hpp"
# include <cereal/types/string.hpp>
# include <Helpers/Logger.hpp>
# include <fstream>
# include "World.hpp"
# include "ResourceDisplay/FileResourceDisplay.hpp"
2025-12-16 12:02:08 +03:00
# include <cereal/archives/portable_binary.hpp>
2025-07-06 20:43:53 +03:00
ResourceManager : : ResourceManager ( World & initWorld ) :
world ( initWorld )
{ }
void ResourceManager : : init_client_callbacks ( ) {
2025-12-16 12:02:08 +03:00
world . con . client_add_recv_callback ( SERVER_NEW_RESOURCE_ID , [ & ] ( cereal : : PortableBinaryInputArchive & message ) {
2025-12-17 14:46:27 +03:00
NetworkingObjects : : NetObjID idBeingRetrieved ;
message ( idBeingRetrieved ) ;
// There is a scenario where the resource id and data messages can be sent twice for the same resource (a resource can be sent early before CLIENT_INITIAL_DATA is sent, and then resent with CLIENT_INITIAL_DATA), so check if resource already exists, and only keep track of the ID if the resource doesn't exist yet
if ( ! world . netObjMan . get_obj_temporary_ref_from_id < ResourceData > ( idBeingRetrieved ) )
resourcesBeingRetrieved . emplace ( idBeingRetrieved , std : : weak_ptr < NetServer : : ClientData > ( ) ) ;
2025-07-06 20:43:53 +03:00
} ) ;
2025-12-16 12:02:08 +03:00
world . con . client_add_recv_callback ( SERVER_NEW_RESOURCE_DATA , [ & ] ( cereal : : PortableBinaryInputArchive & message ) {
2025-12-17 14:46:27 +03:00
if ( ! resourcesBeingRetrieved . empty ( ) ) { // If the resource was sent for the second time, this will be empty, so we can ignore the message
2025-12-16 13:48:21 +03:00
ResourceData newResource ;
message ( newResource ) ;
resourceList . emplace_back ( world . netObjMan . make_obj_direct_with_specific_id < ResourceData > ( resourcesBeingRetrieved . begin ( ) - > first , newResource ) ) ;
resourcesBeingRetrieved . clear ( ) ;
}
2025-10-09 21:02:19 +03:00
} ) ;
}
2025-12-16 12:02:08 +03:00
void ResourceManager : : init_server_callbacks ( ) {
2025-12-17 14:46:27 +03:00
world . netServer - > add_recv_callback ( CLIENT_NEW_RESOURCE_ID , [ & ] ( std : : shared_ptr < NetServer : : ClientData > client , cereal : : PortableBinaryInputArchive & message ) {
2025-12-16 12:02:08 +03:00
NetworkingObjects : : NetObjID idBeingRetrieved ;
message ( idBeingRetrieved ) ;
2025-12-17 14:46:27 +03:00
resourcesBeingRetrieved . emplace ( idBeingRetrieved , client ) ;
2025-12-16 12:02:08 +03:00
} ) ;
2025-12-17 14:46:27 +03:00
world . netServer - > add_recv_callback ( CLIENT_NEW_RESOURCE_DATA , [ & ] ( std : : shared_ptr < NetServer : : ClientData > client , cereal : : PortableBinaryInputArchive & message ) {
2025-12-16 12:02:08 +03:00
ResourceData newResource ;
message ( newResource ) ;
auto it = std : : find_if ( resourcesBeingRetrieved . begin ( ) , resourcesBeingRetrieved . end ( ) , [ & client ] ( auto & p ) {
2025-12-17 14:46:27 +03:00
return ( ! p . second . expired ( ) & & p . second . lock ( ) = = client ) ;
2025-12-16 12:02:08 +03:00
} ) ;
resourceList . emplace_back ( world . netObjMan . make_obj_direct_with_specific_id < ResourceData > ( it - > first , newResource ) ) ;
2025-12-17 14:46:27 +03:00
world . netServer - > send_items_to_all_clients_except ( client , RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_ID , resourceList . back ( ) . get_net_id ( ) ) ;
world . netServer - > send_items_to_all_clients_except ( client , RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_DATA , newResource ) ;
resourcesBeingRetrieved . erase ( it ) ;
2025-12-16 12:02:08 +03:00
} ) ;
}
float ResourceManager : : get_resource_retrieval_progress ( const NetworkingObjects : : NetObjID & id ) {
auto resourceClientID = resourcesBeingRetrieved . find ( id ) ;
if ( resourceClientID = = resourcesBeingRetrieved . end ( ) )
2025-10-09 21:02:19 +03:00
return 0.0f ;
2025-12-17 14:46:27 +03:00
if ( world . netServer ) {
std : : weak_ptr < NetServer : : ClientData > clientIDToLookFor = resourceClientID - > second ;
if ( clientIDToLookFor . expired ( ) ) {
resourcesBeingRetrieved . erase ( resourceClientID ) ;
2025-10-10 10:34:12 +03:00
return 0.0f ;
}
2025-12-17 14:46:27 +03:00
auto progressBytes = clientIDToLookFor . lock ( ) - > get_progress_into_fragmented_message ( RESOURCE_COMMAND_CHANNEL ) ;
2025-12-16 12:02:08 +03:00
if ( progressBytes . totalBytes = = 0 )
return 0.0f ;
return static_cast < float > ( progressBytes . downloadedBytes ) / static_cast < float > ( progressBytes . totalBytes ) ;
2025-10-10 10:34:12 +03:00
}
else if ( world . con . client_exists ( ) & & ! world . con . is_client_disconnected ( ) ) {
2025-12-16 12:02:08 +03:00
NetLibrary : : DownloadProgress progressBytes = world . con . client_get_resource_retrieval_progress ( ) ;
if ( progressBytes . totalBytes = = 0 )
2025-10-10 10:34:12 +03:00
return 0.0f ;
2025-12-16 12:02:08 +03:00
return static_cast < float > ( progressBytes . downloadedBytes ) / static_cast < float > ( progressBytes . totalBytes ) ;
2025-10-10 10:34:12 +03:00
}
return 0.0f ;
2025-07-06 20:43:53 +03:00
}
void ResourceManager : : update ( ) {
for ( auto & [ k , v ] : displays )
v - > update ( world ) ;
}
2025-12-16 12:54:12 +03:00
NetworkingObjects : : NetObjTemporaryPtr < ResourceData > ResourceManager : : add_resource_file ( const std : : filesystem : : path & filePath ) {
2025-07-06 20:43:53 +03:00
// https://nullptr.org/cpp-read-file-into-string/
2025-11-21 08:35:47 +03:00
std : : ifstream file ( filePath , std : : ios : : in | std : : ios : : binary | std : : ios : : ate ) ;
2025-07-06 20:43:53 +03:00
if ( ! file . is_open ( ) ) {
2025-11-21 10:03:11 +03:00
Logger : : get ( ) . log ( " INFO " , " [ResourceManager::add_resource_file] Could not open file " + filePath . string ( ) ) ;
2025-12-16 12:54:12 +03:00
return { } ;
2025-07-06 20:43:53 +03:00
}
size_t resourcesize ;
auto tellgResult = file . tellg ( ) ;
if ( tellgResult = = - 1 ) {
2025-11-21 10:03:11 +03:00
Logger : : get ( ) . log ( " INFO " , " [ResourceManager::add_resource_file] tellg failed for file " + filePath . string ( ) ) ;
2025-12-16 12:54:12 +03:00
return { } ;
2025-07-06 20:43:53 +03:00
}
resourcesize = static_cast < size_t > ( tellgResult ) ;
file . seekg ( 0 , std : : ios_base : : beg ) ;
ResourceData resource ;
resource . data = std : : make_shared < std : : string > ( ) ;
2025-11-21 08:35:47 +03:00
resource . name = std : : filesystem : : path ( filePath ) . filename ( ) . string ( ) ;
2025-07-06 20:43:53 +03:00
std : : string & toPlaceIn = * resource . data ;
toPlaceIn . resize ( resourcesize ) ;
file . read ( toPlaceIn . data ( ) , resourcesize ) ;
file . close ( ) ;
2025-11-21 08:35:47 +03:00
Logger : : get ( ) . log ( " INFO " , " [ResourceManager::add_resource_file] Successfully read file " + filePath . string ( ) ) ;
2025-07-06 20:43:53 +03:00
return add_resource ( resource ) ;
}
2025-12-16 12:54:12 +03:00
const NetworkingObjects : : NetObjOwnerPtr < ResourceData > & ResourceManager : : add_resource ( const ResourceData & resource ) {
2025-12-16 12:02:08 +03:00
auto it = std : : find_if ( resourceList . begin ( ) , resourceList . end ( ) , [ & ] ( const auto & p ) {
return p - > data = = resource . data | | ( * p - > data ) = = ( * resource . data ) ;
2025-07-06 20:43:53 +03:00
} ) ;
2025-12-16 12:02:08 +03:00
if ( it ! = resourceList . end ( ) ) {
2025-07-06 20:43:53 +03:00
Logger : : get ( ) . log ( " INFO " , " [ResourceManager::add_resource] File " + std : : string ( resource . name ) + " is a duplicate " ) ;
2025-12-16 12:54:12 +03:00
return * it ;
2025-07-06 20:43:53 +03:00
}
2025-12-16 12:02:08 +03:00
auto & resourceInsert = resourceList . emplace_back ( world . netObjMan . make_obj_direct < ResourceData > ( resource ) ) ;
2025-12-17 14:46:27 +03:00
if ( world . netServer ) {
world . netServer - > send_items_to_all_clients ( RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_ID , resourceInsert . get_net_id ( ) ) ;
world . netServer - > send_items_to_all_clients ( RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_DATA , resource ) ;
2025-07-06 20:43:53 +03:00
}
2025-12-16 12:02:08 +03:00
else {
world . con . client_send_items_to_server ( RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_ID , resourceInsert . get_net_id ( ) ) ;
world . con . client_send_items_to_server ( RESOURCE_COMMAND_CHANNEL , SERVER_NEW_RESOURCE_DATA , resource ) ;
2025-07-06 20:43:53 +03:00
}
2025-12-16 12:54:12 +03:00
return resourceInsert ;
2025-07-06 20:43:53 +03:00
}
2025-12-16 12:02:08 +03:00
ResourceDisplay * ResourceManager : : get_display_data ( const NetworkingObjects : : NetObjID & fileID ) {
2025-07-06 20:43:53 +03:00
auto loadedDisplayIt = displays . find ( fileID ) ;
if ( loadedDisplayIt ! = displays . end ( ) )
2025-10-10 18:41:08 +03:00
return loadedDisplayIt - > second . get ( ) ;
2025-07-06 20:43:53 +03:00
2025-12-16 12:02:08 +03:00
NetworkingObjects : : NetObjTemporaryPtr < ResourceData > resourceData = world . netObjMan . get_obj_temporary_ref_from_id < ResourceData > ( fileID ) ;
if ( resourceData = = NetworkingObjects : : NetObjTemporaryPtr < ResourceData > ( ) )
2025-07-06 20:43:53 +03:00
return nullptr ;
2025-10-10 18:41:08 +03:00
auto imgResource ( std : : make_unique < ImageResourceDisplay > ( ) ) ;
2025-12-16 12:02:08 +03:00
if ( imgResource - > load ( * this , resourceData - > name , * resourceData - > data ) ) {
2025-10-10 18:41:08 +03:00
displays . emplace ( fileID , std : : move ( imgResource ) ) ;
return displays [ fileID ] . get ( ) ;
2025-07-06 20:43:53 +03:00
}
2025-10-10 18:41:08 +03:00
auto svgResource ( std : : make_unique < SvgResourceDisplay > ( ) ) ;
2025-12-16 12:02:08 +03:00
if ( svgResource - > load ( * this , resourceData - > name , * resourceData - > data ) ) {
2025-10-10 18:41:08 +03:00
displays . emplace ( fileID , std : : move ( svgResource ) ) ;
return displays [ fileID ] . get ( ) ;
2025-08-07 12:44:31 +03:00
}
2025-10-10 18:41:08 +03:00
auto fileResource ( std : : make_unique < FileResourceDisplay > ( ) ) ;
2025-12-16 12:02:08 +03:00
fileResource - > load ( * this , resourceData - > name , * resourceData - > data ) ;
2025-10-10 18:41:08 +03:00
displays . emplace ( fileID , std : : move ( fileResource ) ) ;
return displays [ fileID ] . get ( ) ;
2025-07-06 20:43:53 +03:00
}
2025-12-16 12:02:08 +03:00
const std : : vector < NetworkingObjects : : NetObjOwnerPtr < ResourceData > > & ResourceManager : : resource_list ( ) {
return resourceList ;
2025-07-06 20:43:53 +03:00
}