From c2b43f33da1461939df43657752ffd3651933b6e Mon Sep 17 00:00:00 2001 From: faketruth Date: Mon, 31 Oct 2011 21:30:14 +0000 Subject: Player data is saved and loaded as human readable JSON now. cFileFormatUpdate will loop through old files and convert them to new files (should replace legacy old format loading code) cItem has two new functions to load from Json and output Json, this will keep the items in Json standard ChestEntity and FurnaceEntity use the new functions in cItem git-svn-id: http://mc-server.googlecode.com/svn/trunk@35 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChestEntity.cpp | 18 +--- source/cFileFormatUpdater.cpp | 185 ++++++++++++++++++++++++++++++++++++++++++ source/cFileFormatUpdater.h | 11 +++ source/cFurnaceEntity.cpp | 31 +------ source/cInventory.cpp | 22 ++--- source/cInventory.h | 9 +- source/cItem.cpp | 22 +++++ source/cItem.h | 9 ++ source/cPlayer.cpp | 81 ++++++++++++++---- source/cRoot.cpp | 3 + 10 files changed, 317 insertions(+), 74 deletions(-) create mode 100644 source/cFileFormatUpdater.cpp create mode 100644 source/cFileFormatUpdater.h create mode 100644 source/cItem.cpp (limited to 'source') diff --git a/source/cChestEntity.cpp b/source/cChestEntity.cpp index 54a06fcb9..9ec46014d 100644 --- a/source/cChestEntity.cpp +++ b/source/cChestEntity.cpp @@ -111,14 +111,8 @@ bool cChestEntity::LoadFromJson( const Json::Value& a_Value ) int SlotIdx = 0; for( Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr ) { - Json::Value & Slot = *itr; cItem Item; - Item.m_ItemID = (ENUM_ITEM_ID)Slot.get("ID", -1 ).asInt(); - if( Item.m_ItemID > 0 ) - { - Item.m_ItemCount = (char)Slot.get("Count", -1 ).asInt(); - Item.m_ItemHealth = (short)Slot.get("Health", -1 ).asInt(); - } + Item.FromJson( *itr ); SetSlot( SlotIdx, Item ); SlotIdx++; } @@ -137,15 +131,7 @@ void cChestEntity::SaveToJson( Json::Value& a_Value ) { Json::Value Slot; cItem* Item = GetSlot( i ); - if( Item ) - { - Slot["ID"] = Item->m_ItemID; - if( Item->m_ItemID > 0 ) - { - Slot["Count"] = Item->m_ItemCount; - Slot["Health"] = Item->m_ItemHealth; - } - } + if( Item ) Item->GetJson( Slot ); AllSlots.append( Slot ); } a_Value["Slots"] = AllSlots; diff --git a/source/cFileFormatUpdater.cpp b/source/cFileFormatUpdater.cpp new file mode 100644 index 000000000..8516b5b40 --- /dev/null +++ b/source/cFileFormatUpdater.cpp @@ -0,0 +1,185 @@ +#include "cFileFormatUpdater.h" +#include "cMCLogger.h" +#include "Vector3d.h" +#include "Vector3f.h" +#include +#include +#include + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#include +#include +#include +#include + +#include +#endif + +#include "cItem.h" +#include + +typedef std::list< std::string > StringList; +StringList GetDirectoryContents( const char* a_Directory ); + +void cFileFormatUpdater::UpdateFileFormat() +{ + UpdatePlayersOfWorld("world"); +} + +// Convert player .bin files to JSON +void cFileFormatUpdater::UpdatePlayersOfWorld( const char* a_WorldName ) +{ + std::string PlayerDir = std::string( a_WorldName ) + "/player/"; + + StringList AllFiles = GetDirectoryContents( PlayerDir.c_str() ); + for( StringList::iterator itr = AllFiles.begin(); itr != AllFiles.end(); ++itr ) + { + std::string & FileName = *itr; + if( FileName.rfind(".bin") != std::string::npos ) // Get only the files ending in .bin + { + PlayerBINtoJSON( (PlayerDir + FileName).c_str() ); + } + } +} + +// Converts player binary files to human readable JSON +void cFileFormatUpdater::PlayerBINtoJSON( const char* a_FileName ) +{ + Vector3d PlayerPos; + Vector3f PlayerRot; + short PlayerHealth; + + const unsigned int NumInventorySlots = 45; // At this time the player inventory has/had 45 slots + cItem IventoryItems[ NumInventorySlots ]; + + FILE* f; +#ifdef _WIN32 + if( fopen_s(&f, a_FileName, "rb" ) == 0 ) // no error +#else + if( (f = fopen(a_FileName, "rb" ) ) != 0 ) // no error +#endif + { + // First read player position, rotation and health + if( fread( &PlayerPos.x, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerPos.y, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerPos.z, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerRot.x, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerRot.y, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerRot.z, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + if( fread( &PlayerHealth, sizeof(short), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", a_FileName); fclose(f); return; } + + + for(unsigned int i = 0; i < NumInventorySlots; i++) + { + cItem & Item = IventoryItems[i]; + if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, f) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return; } + if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, f) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return; } + if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, f)!= 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return; } + } + + fclose(f); + } + + // Loaded all the data, now create the JSON data + Json::Value JSON_PlayerPosition; + JSON_PlayerPosition.append( Json::Value( PlayerPos.x ) ); + JSON_PlayerPosition.append( Json::Value( PlayerPos.y ) ); + JSON_PlayerPosition.append( Json::Value( PlayerPos.z ) ); + + Json::Value JSON_PlayerRotation; + JSON_PlayerRotation.append( Json::Value( PlayerRot.x ) ); + JSON_PlayerRotation.append( Json::Value( PlayerRot.y ) ); + JSON_PlayerRotation.append( Json::Value( PlayerRot.z ) ); + + Json::Value JSON_Inventory; + for(unsigned int i = 0; i < NumInventorySlots; i++) + { + Json::Value JSON_Item; + IventoryItems[i].GetJson( JSON_Item ); + JSON_Inventory.append( JSON_Item ); + } + + Json::Value root; + root["position"] = JSON_PlayerPosition; + root["rotation"] = JSON_PlayerRotation; + root["inventory"] = JSON_Inventory; + root["health"] = PlayerHealth; + + Json::StyledWriter writer; + std::string JsonData = writer.write( root ); + + // Get correct filename + std::string FileName = a_FileName; + std::string FileNameWithoutExt = FileName.substr(0, FileName.find_last_of(".") ); + std::string FileNameJson = FileNameWithoutExt + ".json"; + + // Write to file +#ifdef _WIN32 + if( fopen_s(&f, FileNameJson.c_str(), "wb" ) == 0 ) // no error +#else + if( (f = fopen(FileNameJson.c_str(), "wb" ) ) != 0 ) // no error +#endif + { + if( fwrite( JsonData.c_str(), JsonData.size(), 1, f ) != 1 ) { LOGERROR("ERROR WRITING PLAYER JSON TO FILE %s", FileNameJson.c_str() ); return; } + fclose( f ); + } + + // Delete old format file, only do this when conversion has succeeded + if( std::remove( a_FileName ) != 0 ) + { + LOGERROR("COULD NOT DELETE FILE %s", a_FileName ); + return; + } + + LOGINFO("Successfully converted binary to Json %s", FileNameJson.c_str() ); +} + + + + + + + + + +// Helper function +StringList GetDirectoryContents( const char* a_Directory ) +{ + StringList AllFiles; +#ifdef _WIN32 + std::string FileFilter = std::string( a_Directory ) + "*.*"; + HANDLE hFind; + WIN32_FIND_DATA FindFileData; + + if( ( hFind = FindFirstFile(FileFilter.c_str(), &FindFileData) ) != INVALID_HANDLE_VALUE) + { + do + { + AllFiles.push_back( FindFileData.cFileName ); + } while( FindNextFile(hFind, &FindFileData) ); + FindClose(hFind); + } +#else + DIR *dp; + struct dirent *dirp; + if( (dp = opendir( a_Directory ) ) == NULL) + { + LOGERROR("Error (%i) opening %s\n", errno, a_Directory ); + } + else + { + while ((dirp = readdir(dp)) != NULL) + { + AllFiles.push_back( dirp->d_name ); + } + closedir(dp); + } +#endif + + return AllFiles; +} \ No newline at end of file diff --git a/source/cFileFormatUpdater.h b/source/cFileFormatUpdater.h new file mode 100644 index 000000000..fc6beed6e --- /dev/null +++ b/source/cFileFormatUpdater.h @@ -0,0 +1,11 @@ +#pragma once + +class cFileFormatUpdater +{ +public: + static void UpdateFileFormat(); +private: + static void UpdatePlayersOfWorld( const char* a_WorldName ); + + static void PlayerBINtoJSON( const char* a_FileName ); +}; \ No newline at end of file diff --git a/source/cFurnaceEntity.cpp b/source/cFurnaceEntity.cpp index 95f5f566c..36524e3b7 100644 --- a/source/cFurnaceEntity.cpp +++ b/source/cFurnaceEntity.cpp @@ -288,14 +288,7 @@ bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value ) int SlotIdx = 0; for( Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr ) { - Json::Value & Slot = *itr; - cItem & Item = m_Items[ SlotIdx ]; - Item.m_ItemID = (ENUM_ITEM_ID)Slot.get("ID", -1 ).asInt(); - if( Item.m_ItemID > 0 ) - { - Item.m_ItemCount = (char)Slot.get("Count", -1 ).asInt(); - Item.m_ItemHealth = (short)Slot.get("Health", -1 ).asInt(); - } + m_Items[ SlotIdx ].FromJson( *itr ); SlotIdx++; } @@ -304,12 +297,7 @@ bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value ) if( !JsonItem.empty() ) { cItem Item; - Item.m_ItemID = (ENUM_ITEM_ID)JsonItem.get("ID", -1).asInt(); - if( Item.m_ItemID > 0 ) - { - Item.m_ItemCount = (char)JsonItem.get("Count", -1).asInt(); - Item.m_ItemHealth = (short)JsonItem.get("Health", -1).asInt(); - } + Item.FromJson( JsonItem ); if( !Item.IsEmpty() ) { m_CookingItem = new cItem( Item ); @@ -335,13 +323,7 @@ void cFurnaceEntity::SaveToJson( Json::Value& a_Value ) for(unsigned int i = 0; i < 3; i++) { Json::Value Slot; - cItem & Item = m_Items[ i ]; - Slot["ID"] = Item.m_ItemID; - if( Item.m_ItemID > 0 ) - { - Slot["Count"] = Item.m_ItemCount; - Slot["Health"] = Item.m_ItemHealth; - } + m_Items[ i ].GetJson( Slot ); AllSlots.append( Slot ); } a_Value["Slots"] = AllSlots; @@ -350,12 +332,7 @@ void cFurnaceEntity::SaveToJson( Json::Value& a_Value ) if( m_CookingItem ) { Json::Value JsonItem; - JsonItem["ID"] = m_CookingItem->m_ItemID; - if( m_CookingItem->m_ItemID > 0 ) - { - JsonItem["Count"] = m_CookingItem->m_ItemCount; - JsonItem["Health"] = m_CookingItem->m_ItemHealth; - } + m_CookingItem->GetJson( JsonItem ); a_Value["Cooking"] = JsonItem; } diff --git a/source/cInventory.cpp b/source/cInventory.cpp index e78ac226e..788d38eaa 100644 --- a/source/cInventory.cpp +++ b/source/cInventory.cpp @@ -8,6 +8,8 @@ #include "cRecipeChecker.h" #include "cRoot.h" +#include + #include "packets/cPacket_WindowClick.h" #include "packets/cPacket_WholeInventory.h" #include "packets/cPacket_InventorySlot.h" @@ -340,25 +342,23 @@ void cInventory::DrawInventory() } } -void cInventory::WriteToFile(FILE* a_File) +void cInventory::SaveToJson(Json::Value & a_Value) { for(unsigned int i = 0; i < c_NumSlots; i++) { - cItem & Item = m_Slots[i]; - fwrite( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File ); - fwrite( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File ); - fwrite( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File ); + Json::Value JSON_Item; + m_Slots[i].GetJson( JSON_Item ); + a_Value.append( JSON_Item ); } } -bool cInventory::LoadFromFile(FILE* a_File) +bool cInventory::LoadFromJson(Json::Value & a_Value) { - for(unsigned int i = 0; i < c_NumSlots; i++) + int SlotIdx = 0; + for( Json::Value::iterator itr = a_Value.begin(); itr != a_Value.end(); ++itr ) { - cItem & Item = m_Slots[i]; - if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; } - if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; } - if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; } + m_Slots[SlotIdx].FromJson( *itr ); + SlotIdx++; } return true; } diff --git a/source/cInventory.h b/source/cInventory.h index cebcf346b..7d98af853 100644 --- a/source/cInventory.h +++ b/source/cInventory.h @@ -4,6 +4,11 @@ #include "cWindowOwner.h" #include "FileDefine.h" +namespace Json +{ + class Value; +}; + class cItem; class cClientHandle; class cPlayer; @@ -25,8 +30,8 @@ public: bool RemoveItem( cItem & a_Item ); //tolua_export void DrawInventory(); - void WriteToFile(FILE* a_File); - bool LoadFromFile(FILE* a_File); + void SaveToJson(Json::Value & a_Value); + bool LoadFromJson(Json::Value & a_Value); void SendWholeInventory( cClientHandle* a_Client ); diff --git a/source/cItem.cpp b/source/cItem.cpp new file mode 100644 index 000000000..b91a7a316 --- /dev/null +++ b/source/cItem.cpp @@ -0,0 +1,22 @@ +#include "cItem.h" +#include + +void cItem::GetJson( Json::Value & a_OutValue ) +{ + a_OutValue["ID"] = m_ItemID; + if( m_ItemID > 0 ) + { + a_OutValue["Count"] = m_ItemCount; + a_OutValue["Health"] = m_ItemHealth; + } +} + +void cItem::FromJson( const Json::Value & a_Value ) +{ + m_ItemID = (ENUM_ITEM_ID)a_Value.get("ID", -1 ).asInt(); + if( m_ItemID > 0 ) + { + m_ItemCount = (char)a_Value.get("Count", -1 ).asInt(); + m_ItemHealth = (short)a_Value.get("Health", -1 ).asInt(); + } +} \ No newline at end of file diff --git a/source/cItem.h b/source/cItem.h index edf3468ac..dde0c649b 100644 --- a/source/cItem.h +++ b/source/cItem.h @@ -3,6 +3,11 @@ #include "Defines.h" #include "BlockID.h" +namespace Json +{ + class Value; +}; + class cItem //tolua_export { //tolua_export public: @@ -27,6 +32,10 @@ public: { //tolua_export return ( (m_ItemID == a_Item.m_ItemID) && (m_ItemHealth == a_Item.m_ItemHealth) ); } //tolua_export + + void GetJson( Json::Value & a_OutValue ); //tolua_export + void FromJson( const Json::Value & a_Value ); //tolua_export + ENUM_ITEM_ID m_ItemID; //tolua_export char m_ItemCount; //tolua_export short m_ItemHealth; //tolua_export diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index 898bac54f..fee8df966 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -32,6 +32,7 @@ #include "Vector3f.h" #include "../iniFile/iniFile.h" +#include #ifndef _WIN32 // for mkdir #include @@ -636,7 +637,7 @@ bool cPlayer::LoadFromDisk() } char SourceFile[128]; - sprintf_s(SourceFile, 128, "world/player/%s.bin", m_pState->PlayerName.c_str() ); + sprintf_s(SourceFile, 128, "world/player/%s.json", m_pState->PlayerName.c_str() ); FILE* f; #ifdef _WIN32 @@ -645,15 +646,43 @@ bool cPlayer::LoadFromDisk() if( (f = fopen(SourceFile, "rb" ) ) != 0 ) // no error #endif { - if( fread( &m_Pos->x, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Pos->y, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Pos->z, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Rot->x, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Rot->y, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Rot->z, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( fread( &m_Health, sizeof(m_Health), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } - if( !m_Inventory->LoadFromFile( f ) ) { LOGERROR("ERROR READING INVENTORY FROM FILE %s", SourceFile); fclose(f); return false; } + // Get file size + fseek (f , 0 , SEEK_END); + long FileSize = ftell (f); + rewind(f); + + char* buffer = new char[ FileSize ]; + if( fread( buffer, FileSize, 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; } fclose(f); + + Json::Value root; + Json::Reader reader; + if( !reader.parse( buffer, root, false ) ) + { + LOGERROR("ERROR WHILE PARSING JSON FROM FILE %s", SourceFile); + } + + delete [] buffer; + + Json::Value & JSON_PlayerPosition = root["position"]; + if( JSON_PlayerPosition.size() == 3 ) + { + m_Pos->x = JSON_PlayerPosition[(unsigned int)0].asDouble(); + m_Pos->y = JSON_PlayerPosition[(unsigned int)1].asDouble(); + m_Pos->z = JSON_PlayerPosition[(unsigned int)2].asDouble(); + } + + Json::Value & JSON_PlayerRotation = root["rotation"]; + if( JSON_PlayerRotation.size() == 3 ) + { + m_Rot->x = (float)JSON_PlayerRotation[(unsigned int)0].asDouble(); + m_Rot->y = (float)JSON_PlayerRotation[(unsigned int)1].asDouble(); + m_Rot->z = (float)JSON_PlayerRotation[(unsigned int)2].asDouble(); + } + + m_Health = root.get("health", 0 ).asInt(); + m_Inventory->LoadFromJson(root["inventory"]); + return true; } return false; @@ -677,8 +706,31 @@ bool cPlayer::SaveToDisk() } #endif + // create the JSON data + Json::Value JSON_PlayerPosition; + JSON_PlayerPosition.append( Json::Value( m_Pos->x ) ); + JSON_PlayerPosition.append( Json::Value( m_Pos->y ) ); + JSON_PlayerPosition.append( Json::Value( m_Pos->z ) ); + + Json::Value JSON_PlayerRotation; + JSON_PlayerRotation.append( Json::Value( m_Rot->x ) ); + JSON_PlayerRotation.append( Json::Value( m_Rot->y ) ); + JSON_PlayerRotation.append( Json::Value( m_Rot->z ) ); + + Json::Value JSON_Inventory; + m_Inventory->SaveToJson( JSON_Inventory ); + + Json::Value root; + root["position"] = JSON_PlayerPosition; + root["rotation"] = JSON_PlayerRotation; + root["inventory"] = JSON_Inventory; + root["health"] = m_Health; + + Json::StyledWriter writer; + std::string JsonData = writer.write( root ); + char SourceFile[128]; - sprintf_s(SourceFile, 128, "world/player/%s.bin", m_pState->PlayerName.c_str() ); + sprintf_s(SourceFile, 128, "world/player/%s.json", m_pState->PlayerName.c_str() ); FILE* f; #ifdef _WIN32 @@ -687,14 +739,7 @@ bool cPlayer::SaveToDisk() if( (f = fopen(SourceFile, "wb" ) ) != 0 ) // no error #endif { - fwrite( &m_Pos->x, sizeof(double), 1, f ); - fwrite( &m_Pos->y, sizeof(double), 1, f ); - fwrite( &m_Pos->z, sizeof(double), 1, f ); - fwrite( &m_Rot->x, sizeof(float), 1, f ); - fwrite( &m_Rot->y, sizeof(float), 1, f ); - fwrite( &m_Rot->z, sizeof(float), 1, f ); - fwrite( &m_Health, sizeof(m_Health), 1, f ); - m_Inventory->WriteToFile( f ); + if( fwrite( JsonData.c_str(), JsonData.size(), 1, f ) != 1 ) { LOGERROR("ERROR WRITING PLAYER JSON TO FILE %s", SourceFile ); return false; } fclose(f); return true; } diff --git a/source/cRoot.cpp b/source/cRoot.cpp index 531d0c9f3..55ee28576 100644 --- a/source/cRoot.cpp +++ b/source/cRoot.cpp @@ -10,6 +10,7 @@ #include "cMonsterConfig.h" #include "cSleep.h" #include "cThread.h" +#include "cFileFormatUpdater.h" #include "../iniFile/iniFile.h" @@ -67,6 +68,8 @@ void cRoot::Start() { m_bRestart = false; + cFileFormatUpdater::UpdateFileFormat(); + m_Server = new cServer(); cIniFile IniFile("settings.ini"); IniFile.ReadFile(); -- cgit v1.2.3