Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Zapis Binarny wielu obiektów w jednym pliku

Ostatnio zmodyfikowano wczoraj o godz. 21:45
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
» 2025-05-03 20:33:33
tak jest lepiej ? :-)

C/C++
void binary_save( std::wstring pathfile = L"world\\test_world.wrd" ) {
   
   
class Writer
    {
       
std::ostream & os;
   
public:
       
Writer( std::ostream & os )
            :
os( os )
       
{ }
       
       
void write_string( const std::string & str )
       
{
           
uint16_t str_len = static_cast < uint16_t >( str.size() );
           
os.write( reinterpret_cast < const char * >( & str_len ), sizeof( str_len ) );
           
os.write( str.data(), str_len );
       
}
       
       
void write_uint32( uint32_t val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( uint32_t ) );
       
}
       
       
void write_uint8( uint8_t val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( uint8_t ) );
       
}
       
       
void write_float( float val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( float ) );
       
}
       
       
void write_int( int val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( int ) );
       
}
       
       
void write_short( short val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( short ) );
       
}
       
//itd inne warianty write()
   
};
   
   
std::ofstream file( pathfile, std::ios::binary );
   
Writer writer( file );
   
   
// najpierw zapisz ścieżki prefabrykatów w celu wyeliminowania powtarzalnych scieżek i zastąpieniu ich przez id
   
writer.write_string( "#ResourcesBegin" );
   
writer.write_uint32( prefabs.size() );
   
   
for( auto & prefab: prefabs )
       
 writer.write_string( prefab->name );
   
   
writer.write_string( "#ResourcesEnd" );
   
   
// zapisz mapę - chunki oraz obiekty przypisane do nich
   
writer.write_string( "#MapBegin" );
   
   
for( auto & chunk: chunks ) {
       
       
// save chunk coords
       
writer.write_int( chunk->coords.x );
       
writer.write_int( chunk->coords.y );
       
       
// save tiles
       
Terrain * ter = chunk->terrain;
       
for( short y = 0; y < 16; y++ ) {
           
for( short x = 0; x < 16; x++ ) {
               
writer.write_short( ter->tiles[ y * 16 + x ] );
           
}
        }
       
       
       
// save objects
       
writer.write_uint32( chunk->getAllGameObjects().size() );
       
       
for( auto & object: chunk->getAllGameObjects() ) {
           
           
writer.write_uint8( static_cast < uint8_t >( object->type ) );
           
writer.write_uint32( getPrefabID( object->name ) );
           
           
if( object->type == GameObjectType::Building ) {
               
               
writer.write_short( dynamic_cast < Building * >( object )->id );
               
writer.write_float( object->position.x );
               
writer.write_float( object->position.y );
               
           
}
           
else if( object->type == GameObjectType::Monster ) {
               
               
sf::Vector2f position = dynamic_cast < Monster * >( object )->base;
               
writer.write_float( position.x );
               
writer.write_float( position.y );
               
           
}
           
else if( object->type == GameObjectType::Character ) {
               
               
writer.write_float( object->position.x );
               
writer.write_float( object->position.y );
               
           
}
           
else if( object->type == GameObjectType::InventoryOnMap ) {
               
               
writer.write_short( dynamic_cast < InventoryOnMap * >( object )->inventory->id );
               
writer.write_float( object->position.x );
               
writer.write_float( object->position.y );
               
           
}
           
else {
               
               
writer.write_float( object->position.x );
               
writer.write_float( object->position.y );
           
}
        }
       
    }
   
   
writer.write_string( "#MapEnd" );
   
file.close();
   
}
P-182318
pekfos
» 2025-05-03 20:41:17
Dużo lepiej.
C/C++
writer.write_float( object->position.x );
writer.write_float( object->position.y );
Jak masz powtarzalne struktury danych jak choćby ta pozycja, to możesz dorobić na to też metody zapisu by nie powtarzać się. Np
C/C++
writer.write_point( object->position );
P-182319
tBane
Temat założony przez niniejszego użytkownika
» 2025-05-03 20:46:46
Ok. Słuszna uwaga. Dzięki :-)

edit//
Rozmiar pliku z ponad 1MB spadł do 900kb i do tego szybciej wczutuje taką mapę o około 2s :-)
Oto kompletny kod:

C/C++
void binary_save( std::wstring pathfile = L"world\\test_world.wrd" ) {
   
   
class Writer
    {
       
std::ostream & os;
   
public:
       
Writer( std::ostream & os )
            :
os( os )
       
{ }
       
       
void write_string( const std::string & str )
       
{
           
uint16_t str_len = static_cast < uint16_t >( str.size() );
           
os.write( reinterpret_cast < const char * >( & str_len ), sizeof( str_len ) );
           
os.write( str.data(), str_len );
       
}
       
       
void write_uint32( uint32_t val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( uint32_t ) );
       
}
       
       
void write_uint16( uint16_t val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( uint16_t ) );
       
}
       
       
void write_uint8( uint8_t val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( uint8_t ) );
       
}
       
       
void write_float( float val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( float ) );
       
}
       
       
void write_int( int val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( int ) );
       
}
       
       
void write_short( short val ) {
           
os.write( reinterpret_cast < const char * >( & val ), sizeof( short ) );
       
}
       
//itd inne warianty write()
       
       
void write_Vector2f( sf::Vector2f val ) {
           
os.write( reinterpret_cast < const char * >( & val.x ), sizeof( float ) );
           
os.write( reinterpret_cast < const char * >( & val.y ), sizeof( float ) );
       
}
       
       
void write_Vector2i( sf::Vector2i val ) {
           
os.write( reinterpret_cast < const char * >( & val.x ), sizeof( int ) );
           
os.write( reinterpret_cast < const char * >( & val.y ), sizeof( int ) );
       
}
    }
;
   
   
std::ofstream file( pathfile, std::ios::binary );
   
Writer writer( file );
   
   
// najpierw zapisz ścieżki prefabrykatów w celu wyeliminowania powtarzalnych scieżek i zastąpieniu ich przez id
   
writer.write_string( "#ResourcesBegin" );
   
writer.write_uint32( prefabs.size() );
   
   
for( auto & prefab: prefabs )
       
 writer.write_string( prefab->name );
   
   
writer.write_string( "#ResourcesEnd" );
   
   
// zapisz mapę - chunki oraz obiekty przypisane do nich
   
writer.write_string( "#MapBegin" );
   
   
for( auto & chunk: chunks ) {
       
       
// save chunk coords
       
writer.write_int( chunk->coords.x );
       
writer.write_int( chunk->coords.y );
       
       
// save tiles
       
Terrain * ter = chunk->terrain;
       
for( short y = 0; y < 16; y++ ) {
           
for( short x = 0; x < 16; x++ ) {
               
writer.write_short( ter->tiles[ y * 16 + x ] );
           
}
        }
       
       
       
// save objects
       
writer.write_uint32( chunk->getAllGameObjects().size() );
       
       
for( auto & object: chunk->getAllGameObjects() ) {
           
           
writer.write_uint16( static_cast < uint16_t >( object->type ) );
           
           
           
if( object->type == GameObjectType::Building ) {
               
               
writer.write_short( dynamic_cast < Building * >( object )->id );
               
writer.write_Vector2f( object->position );
               
           
}
           
else if( object->type == GameObjectType::Monster ) {
               
writer.write_uint32( getPrefabID( object->name ) );
               
sf::Vector2f position = dynamic_cast < Monster * >( object )->base;
               
writer.write_Vector2f( object->position );
               
           
}
           
else if( object->type == GameObjectType::Character ) {
               
writer.write_uint32( getPrefabID( object->name ) );
               
writer.write_Vector2f( object->position );
               
           
}
           
else if( object->type == GameObjectType::InventoryOnMap ) {
               
writer.write_uint32( getPrefabID( object->name ) );
               
writer.write_short( dynamic_cast < InventoryOnMap * >( object )->inventory->id );
               
writer.write_Vector2f( object->position );
               
           
}
           
else {
               
writer.write_uint32( getPrefabID( object->name ) );
               
writer.write_Vector2f( object->position );
           
}
        }
       
    }
   
   
writer.write_string( "#MapEnd" );
   
   
for( auto & chunk: chunks ) {
       
for( auto & building: chunk->_buildings ) {
           
writer.write_string( "#BuildingBegin" );
           
           
writer.write_short( building->id );
           
writer.write_string( building->name );
           
writer.write_Vector2i( building->size );
           
writer.write_string( building->_door->name );
           
writer.write_string( building->texture_top_walls->name );
           
writer.write_string( building->texture_center_walls->name );
           
writer.write_string( building->texture_bottom_walls->name );
           
writer.write_string( building->texture_windows->name );
           
           
           
writer.write_short( building->floors->width );
           
writer.write_short( building->floors->height );
           
           
for( short y = 0; y < building->floors->height; y++ ) {
               
for( short x = 0; x < building->floors->width; x++ ) {
                   
writer.write_short( building->floors->floors[ y * building->floors->width + x ] );
               
}
            }
           
           
std::vector < GameObject * > building_objects = building->getAllGameObjects();
           
writer.write_uint32( building_objects.size() );
           
           
for( auto & object: building_objects ) {
               
writer.write_uint16( static_cast < uint16_t >( object->type ) );
               
writer.write_uint32( getPrefabID( object->name ) );
               
               
sf::Vector2f position;
               
position.x = int( object->position.x ) - int( building->position.x ) + building->size.x / 2 * 16;
               
position.y = int( object->position.y ) - int( building->position.y ) + building->size.y * 16;
               
               
writer.write_Vector2f( position );
           
}
           
           
           
writer.write_string( "#BuildingEnd" );
       
}
    }
   
   
file.close();
   
}
P-182320
pekfos
» 2025-05-04 21:28:22
Rozmiar pliku z ponad 1MB spadł do 900kb i do tego szybciej wczutuje taką mapę o około 2s :-)
Na jakim kalkulatorze to odpalasz że ta zmiana dała 2s przyspieszenia? Na pewno te wczytywanie się wykonuje 1 raz?
P-182321
tBane
Temat założony przez niniejszego użytkownika
» 2025-05-04 21:35:32
Normalnie wczytywanie trwa 7s, przyspieszenie 2s to chyba duża różnica.


Procesor Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz   2.90 GHz
Zainstalowana pamięć RAM 32,0 GB
Karta graficzna NVIDIA GeForce RTX 2070 (8 GB)

C/C++
void binary_load( std::wstring pathfile = L"world\\world.wrd" ) {
   
   
class Reader {
       
std::istream & is;
       
   
public:
       
Reader( std::istream & is )
            :
is( is )
       
{ }
       
       
std::string read_string() {
           
uint16_t len;
           
is.read( reinterpret_cast < char * >( & len ), sizeof( uint16_t ) );
           
           
std::string str( len, '\0' ); // utwórz pusty string o długości len
           
is.read( & str[ 0 ], len ); // bezpieczne wczytanie danych do stringa
           
return str;
       
}
       
       
uint32_t read_uint32() {
           
uint32_t value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( uint32_t ) );
           
return value;
       
}
       
       
uint16_t read_uint16() {
           
uint16_t value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( uint16_t ) );
           
return value;
       
}
       
       
uint8_t read_uint8() {
           
uint8_t value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( uint8_t ) );
           
return value;
       
}
       
       
float read_float() {
           
float value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( float ) );
           
return value;
       
}
       
       
int read_int() {
           
int value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( int ) );
           
return value;
       
}
       
       
short read_short() {
           
short value;
           
is.read( reinterpret_cast < char * >( & value ), sizeof( short ) );
           
return value;
       
}
       
       
sf::Vector2f read_Vector2f() {
           
sf::Vector2f value;
           
is.read( reinterpret_cast < char * >( & value.x ), sizeof( float ) );
           
is.read( reinterpret_cast < char * >( & value.y ), sizeof( float ) );
           
return value;
       
}
       
       
sf::Vector2i read_Vector2i() {
           
sf::Vector2i value;
           
is.read( reinterpret_cast < char * >( & value.x ), sizeof( int ) );
           
is.read( reinterpret_cast < char * >( & value.y ), sizeof( int ) );
           
return value;
       
}
    }
;
   
   
   
std::ifstream file( pathfile, std::ios::binary );
   
Reader reader( file );
   
   
std::vector < std::string > pathfiles;
   
   
while( file && !file.eof() ) {
       
std::string phrase;
       
       
try {
           
phrase = reader.read_string();
       
}
       
catch( ... ) {
           
break; // na wypadek błędu odczytu
       
}
       
       
if( phrase == "#Resources" ) {
           
           
uint32_t resources_count = reader.read_uint32();
           
           
for( uint32_t i = 0; i < resources_count; i++ ) {
               
pathfiles.push_back( reader.read_string() );
               
//cout << i << " : " << pathfiles.back() << "\n";
               
           
}
        }
       
else if( phrase == "#Map" ) {
           
           
// clearing chunks
           
for( auto & chunk: chunks )
               
 delete chunk;
           
           
chunks.clear();
           
clearAllMainListsOfGameObjects();
           
           
this->width = reader.read_uint8();
           
this->height = reader.read_uint8();
           
           
for( short i = 0; i < width * height; i++ ) {
               
               
sf::Vector2i coords = reader.read_Vector2i();
               
Chunk * ch = new Chunk( coords.x, coords.y );
               
               
//std::cout << coords.x << " " << coords.y << "\n";
               
               
for( short y = 0; y < 16; y++ ) {
                   
for( short x = 0; x < 16; x++ ) {
                       
short t_val = reader.read_short();
                       
ch->terrain->edit( x, y, t_val );
                       
( t_val == 0 ||( t_val >= countOfBasicTerrain && t_val < countOfBasicTerrain + 16 ) ) ? ch->water->edit( x, y, t_val )
                            :
ch->water->edit( x, y, - 1 );
                       
                   
}
                }
               
               
uint32_t objects_count = reader.read_uint32();
               
for( uint32_t i = 0; i < objects_count; i++ ) {
                   
uint16_t objectType = reader.read_uint16();
                   
GameObject * object = nullptr;
                   
                   
if( objectType == static_cast < uint16_t >( GameObjectType::Building ) ) {
                       
object = new Building( reader.read_short() );
                   
}
                   
else if( objectType == static_cast < uint16_t >( GameObjectType::Character ) ) {
                       
GameObject * prefab = getPrefab( pathfiles[ reader.read_uint32() ] );
                       
object = getNewGameObject( prefab );
                   
}
                   
else if( objectType == static_cast < uint16_t >( GameObjectType::InventoryOnMap ) ) {
                       
Inventory * in = new Inventory( reader.read_short() );
                       
object = new InventoryOnMap( in );
                   
}
                   
else {
                       
GameObject * prefab = getPrefab( pathfiles[ reader.read_uint32() ] );
                       
//std::cout << "Other\n";
                       
object = getNewGameObject( prefab );
                       
                   
}
                   
                   
if( object != nullptr ) {
                       
object->setPosition( reader.read_Vector2f() );
                       
ch->addGameObject( object );
                   
}
                }
               
               
chunks.push_back( ch );
           
}
           
        }
       
else if( phrase == "#Building" ) {
           
           
Building * building = getBuilding( reader.read_short() );
           
building->name = reader.read_string();
           
building->size = reader.read_Vector2i();
           
           
building->_door = dynamic_cast < Door * >( getNewGameObject( getPrefab( reader.read_string() ) ) );
           
building->_door->setPosition( building->position );
           
           
building->texture_top_walls = getSingleTexture( reader.read_string() );
           
building->texture_center_walls = getSingleTexture( reader.read_string() );
           
building->texture_bottom_walls = getSingleTexture( reader.read_string() );
           
building->texture_windows = getSingleTexture( reader.read_string() );
           
           
short floor_w = reader.read_short();
           
short floor_h = reader.read_short();
           
           
if( building->floors != nullptr )
               
 delete building->floors;
           
           
building->floors = new Floors( building->position.x / 16 - building->size.x / 2, building->position.y / 16 - building->size.y, building->size.x, building->size.y );
           
           
for( short y = 0; y < floor_h; y++ ) {
               
for( short x = 0; x < floor_w; x++ ) {
                   
building->floors->edit( x, y, reader.read_short() );
               
}
            }
           
           
uint32_t objects_count = reader.read_uint32();
           
for( uint32_t i = 0; i < objects_count; i++ ) {
               
               
uint16_t objectType = reader.read_uint16();
               
GameObject * prefab = getPrefab( pathfiles[ reader.read_uint32() ] );
               
if( prefab != nullptr ) {
                   
GameObject * object = getNewGameObject( prefab );
                   
sf::Vector2f position = reader.read_Vector2f();
                   
position.x = position.x -( building->size.x * 16 / 2 ) + building->position.x;
                   
position.y = position.y -( building->size.y * 16 ) + building->position.y;
                   
object->setPosition( position );
                   
building->addGameObject( object );
               
}
            }
           
           
building->loadTexture();
           
       
}
       
else if( phrase == "#Inventory" ) {
           
           
clearInventories();
           
Inventory * inventory = new Inventory( reader.read_short() );
           
uint32_t items_count = reader.read_uint32();
           
           
for( uint32_t i = 0; i < items_count; i++ ) {
               
               
uint32_t id = reader.read_uint32();
               
Item * item = getItem( pathfiles[ id ] );
               
uint16_t count = reader.read_uint16();
               
               
inventory->addItem( item, count );
               
           
}
           
           
std::cout << "#Inventory: " << inventory->id << "\n";
           
for( short i = 0; i < inventory->items.size(); i++ ) {
               
std::cout << inventory->items[ i ]->name << " " << inventory->counts[ i ] << "\n";
           
}
        }
       
    }
   
   
file.close();
   
}
P-182322
tBane
Temat założony przez niniejszego użytkownika
» 2025-05-04 21:45:05
mój błąd - odpalałem w trybie debug... w release jest poniżej sekundy ...
P-182323
1 « 2 »
Poprzednia strona Strona 2 z 2