mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-03-22 15:19:52 +01:00
Add logging inside saves which remembers which other saves material was taken from
The logging is saved inside the bson data in all online saves, local saves, stamps, and clipboard pieces. It is loaded back when reloading each of those. See #474 for the format of the data. It is the same format for the bson data. Note that "links" is an array of objects. It can be recursive. There is some effort to not duplicate information, we don't care if you loaded a stamp 10 times or if you are using the clipboard in your own save. Extra information is mostly not saved for your own stuff, only when you take material from other saves. Press ctrl+a in debug builds to show what info it is currently saving in Client. Also enabled in snapshots for now. There is one unrelated change in here, which fixes a crash pointed out by QuanTech. It was also save related and it was too close to the other changes to separate it into another commit. It fixes a crash when saving signs with invalid unicode. the BSON library doesn't like this, it was returning an error but we ignored it, which caused a crash. It now notices those errors. I also had to update several Serialize calls to check if it actually returned save data, or else it then would have started crashing there instead. Also some debug prints were removed
This commit is contained in:
parent
be6ac1d91e
commit
8e5b0c760e
@ -1011,13 +1011,14 @@ RequestStatus Client::UploadSave(SaveInfo & save)
|
||||
lastError = "Empty game save";
|
||||
return RequestFailure;
|
||||
}
|
||||
|
||||
save.SetID(0);
|
||||
|
||||
gameData = save.GetGameSave()->Serialise(gameDataLength);
|
||||
|
||||
if (!gameData)
|
||||
{
|
||||
lastError = "Cannot upload game save";
|
||||
lastError = "Cannot serialize game save";
|
||||
return RequestFailure;
|
||||
}
|
||||
#ifdef SNAPSHOT
|
||||
@ -1141,14 +1142,29 @@ std::string Client::AddStamp(GameSave * saveData)
|
||||
saveID
|
||||
<< std::setw(8) << std::setfill('0') << std::hex << lastStampTime
|
||||
<< std::setw(2) << std::setfill('0') << std::hex << lastStampName;
|
||||
std::string filename = std::string(STAMPS_DIR PATH_SEP + saveID.str()+".stm").c_str();
|
||||
|
||||
MakeDirectory(STAMPS_DIR);
|
||||
|
||||
Json::Value stampInfo;
|
||||
stampInfo["type"] = "stamp";
|
||||
stampInfo["username"] = authUser.Username;
|
||||
stampInfo["name"] = filename;
|
||||
stampInfo["date"] = (Json::Value::UInt64)time(NULL);
|
||||
if (authors.size() != 0)
|
||||
{
|
||||
// This is a stamp, always append full authorship info (even if same user)
|
||||
stampInfo["links"].append(Client::Ref().authors);
|
||||
}
|
||||
saveData->authors = stampInfo;
|
||||
|
||||
unsigned int gameDataLength;
|
||||
char * gameData = saveData->Serialise(gameDataLength);
|
||||
if (gameData == NULL)
|
||||
return "";
|
||||
|
||||
std::ofstream stampStream;
|
||||
stampStream.open(std::string(STAMPS_DIR PATH_SEP + saveID.str()+".stm").c_str(), std::ios::binary);
|
||||
stampStream.open(filename.c_str(), std::ios::binary);
|
||||
stampStream.write((const char *)gameData, gameDataLength);
|
||||
stampStream.close();
|
||||
|
||||
@ -1997,6 +2013,73 @@ std::list<std::string> * Client::AddTag(int saveID, std::string tag)
|
||||
return tags;
|
||||
}
|
||||
|
||||
// stamp-specific wrapper for MergeAuthorInfo
|
||||
// also used for clipboard and lua stamps
|
||||
void Client::MergeStampAuthorInfo(Json::Value stampAuthors)
|
||||
{
|
||||
if (stampAuthors.size())
|
||||
{
|
||||
// when loading stamp/clipboard, only append info to authorship info (since we aren't replacing the save)
|
||||
// unless there is nothing loaded currently, then set authors directly
|
||||
if (authors.size())
|
||||
{
|
||||
if (authors["username"] != stampAuthors["username"])
|
||||
{
|
||||
// Don't add if it's exactly the same
|
||||
if (stampAuthors["links"].size() != 1 || stampAuthors["links"][0] != Client::Ref().authors)
|
||||
{
|
||||
// 2nd arg of MergeAuthorInfo needs to be an array
|
||||
Json::Value toAdd;
|
||||
toAdd.append(stampAuthors);
|
||||
MergeAuthorInfo(toAdd);
|
||||
}
|
||||
}
|
||||
else if (stampAuthors["links"].size())
|
||||
{
|
||||
MergeAuthorInfo(stampAuthors["links"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
authors = stampAuthors;
|
||||
}
|
||||
}
|
||||
|
||||
// linksToAdd is an array (NOT an object) of links to add to authors["links"]
|
||||
void Client::MergeAuthorInfo(Json::Value linksToAdd)
|
||||
{
|
||||
for (Json::Value::ArrayIndex i = 0; i < linksToAdd.size(); i++)
|
||||
{
|
||||
// link is the same exact json we have open, don't do anything
|
||||
if (linksToAdd[i] == authors)
|
||||
return;
|
||||
|
||||
bool hasLink = false;
|
||||
for (Json::Value::ArrayIndex j = 0; j < authors["links"].size(); j++)
|
||||
{
|
||||
// check everything in authors["links"] to see if it's the same json as what we are already adding
|
||||
if (authors["links"][j] == linksToAdd[i])
|
||||
hasLink = true;
|
||||
}
|
||||
if (!hasLink)
|
||||
authors["links"].append(linksToAdd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// load current authors information into a json value (when saving everything: stamps, clipboard, local saves, and online saves)
|
||||
void Client::SaveAuthorInfo(Json::Value *saveInto)
|
||||
{
|
||||
if (authors.size() != 0)
|
||||
{
|
||||
// Different username? Save full original save info
|
||||
if (authors["username"] != (*saveInto)["username"])
|
||||
(*saveInto)["links"].append(authors);
|
||||
// This is probalby the same save
|
||||
// Don't append another layer of links, just keep existing links
|
||||
else if (authors["links"].size())
|
||||
(*saveInto)["links"] = authors["links"];
|
||||
}
|
||||
}
|
||||
|
||||
// powder.pref preference getting / setting functions
|
||||
|
||||
// Recursively go down the json to get the setting we want
|
||||
|
@ -85,10 +85,25 @@ private:
|
||||
Json::Value preferences;
|
||||
Json::Value GetPref(Json::Value root, std::string prop, Json::Value defaultValue = Json::nullValue);
|
||||
Json::Value SetPrefHelper(Json::Value root, std::string prop, Json::Value value);
|
||||
|
||||
// Save stealing info
|
||||
Json::Value authors;
|
||||
|
||||
public:
|
||||
|
||||
std::vector<ClientListener*> listeners;
|
||||
|
||||
// Save stealing info
|
||||
void MergeStampAuthorInfo(Json::Value linksToAdd);
|
||||
void MergeAuthorInfo(Json::Value linksToAdd);
|
||||
void OverwriteAuthorInfo(Json::Value overwrite) { authors = overwrite; }
|
||||
void SaveAuthorInfo(Json::Value *saveInto);
|
||||
void ClearAuthorInfo() { authors.clear(); }
|
||||
bool IsAuthorsEmpty() { return authors.size() == 0; }
|
||||
#if defined(DEBUG) || defined(SNAPSHOT)
|
||||
std::string GetAuthorString() { return authors.toStyledString(); }
|
||||
#endif
|
||||
|
||||
UpdateInfo GetUpdateInfo();
|
||||
|
||||
Client();
|
||||
|
@ -52,6 +52,7 @@ originalData(save.originalData)
|
||||
blockHeight = save.blockHeight;
|
||||
}
|
||||
particlesCount = save.particlesCount;
|
||||
authors = save.authors;
|
||||
}
|
||||
|
||||
GameSave::GameSave(int width, int height)
|
||||
@ -73,9 +74,6 @@ GameSave::GameSave(std::vector<char> data)
|
||||
expanded = false;
|
||||
hasOriginalData = true;
|
||||
originalData = data;
|
||||
#ifdef DEBUG
|
||||
std::cout << "Creating Collapsed save from data" << std::endl;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
Expand();
|
||||
@ -99,9 +97,6 @@ GameSave::GameSave(std::vector<unsigned char> data)
|
||||
expanded = false;
|
||||
hasOriginalData = true;
|
||||
originalData = std::vector<char>(data.begin(), data.end());
|
||||
#ifdef DEBUG
|
||||
std::cout << "Creating Collapsed save from data" << std::endl;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
Expand();
|
||||
@ -153,6 +148,7 @@ void GameSave::InitData()
|
||||
ambientHeat = NULL;
|
||||
fromNewerVersion = false;
|
||||
hasAmbientHeat = false;
|
||||
authors.clear();
|
||||
}
|
||||
|
||||
void GameSave::InitVars()
|
||||
@ -198,16 +194,10 @@ void GameSave::read(char * data, int dataSize)
|
||||
{
|
||||
if ((data[0]==0x66 && data[1]==0x75 && data[2]==0x43) || (data[0]==0x50 && data[1]==0x53 && data[2]==0x76))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << "Reading PSv..." << std::endl;
|
||||
#endif
|
||||
readPSv(data, dataSize);
|
||||
}
|
||||
else if(data[0] == 'O' && data[1] == 'P' && data[2] == 'S')
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << "Reading OPS..." << std::endl;
|
||||
#endif
|
||||
if (data[3] != '1')
|
||||
throw ParseException(ParseException::WrongVersion, "Save format from newer version");
|
||||
readOPS(data, dataSize);
|
||||
@ -257,6 +247,8 @@ std::vector<char> GameSave::Serialise()
|
||||
{
|
||||
unsigned int dataSize;
|
||||
char * data = Serialise(dataSize);
|
||||
if (data == NULL)
|
||||
return std::vector<char>();
|
||||
std::vector<char> dataVect(data, data+dataSize);
|
||||
delete[] data;
|
||||
return dataVect;
|
||||
@ -644,6 +636,20 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
fprintf(stderr, "Wrong type for %s\n", bson_iterator_key(&iter));
|
||||
}
|
||||
}
|
||||
else if (!strcmp(bson_iterator_key(&iter), "authors"))
|
||||
{
|
||||
if (bson_iterator_type(&iter) == BSON_OBJECT)
|
||||
{
|
||||
// we need to clear authors because the save may be read multiple times in the stamp browser (loading and rendering twice)
|
||||
// seems inefficient ...
|
||||
authors.clear();
|
||||
ConvertBsonToJson(&iter, &authors);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Wrong type for %s\n", bson_iterator_key(&iter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Read wall and fan data
|
||||
@ -1130,6 +1136,38 @@ fin:
|
||||
free(partsSimIndex);
|
||||
}
|
||||
|
||||
void GameSave::ConvertBsonToJson(bson_iterator *iter, Json::Value *j)
|
||||
{
|
||||
bson_iterator subiter;
|
||||
bson_iterator_subiterator(iter, &subiter);
|
||||
while (bson_iterator_next(&subiter))
|
||||
{
|
||||
std::string key = bson_iterator_key(&subiter);
|
||||
if (bson_iterator_type(&subiter) == BSON_STRING)
|
||||
(*j)[key] = bson_iterator_string(&subiter);
|
||||
else if (bson_iterator_type(&subiter) == BSON_BOOL)
|
||||
(*j)[key] = bson_iterator_bool(&subiter);
|
||||
else if (bson_iterator_type(&subiter) == BSON_INT)
|
||||
(*j)[key] = bson_iterator_int(&subiter);
|
||||
else if (bson_iterator_type(&subiter) == BSON_LONG)
|
||||
(*j)[key] = (Json::Value::Int64)bson_iterator_long(&subiter);
|
||||
else if (bson_iterator_type(&subiter) == BSON_ARRAY)
|
||||
{
|
||||
bson_iterator arrayiter;
|
||||
bson_iterator_subiterator(&subiter, &arrayiter);
|
||||
while (bson_iterator_next(&arrayiter))
|
||||
{
|
||||
if (bson_iterator_type(&arrayiter) == BSON_OBJECT && !strcmp(bson_iterator_key(&arrayiter), "part"))
|
||||
{
|
||||
Json::Value tempPart;
|
||||
ConvertBsonToJson(&arrayiter, &tempPart);
|
||||
(*j)["links"].append(tempPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameSave::readPSv(char * data, int dataLength)
|
||||
{
|
||||
unsigned char * d = NULL, * c = (unsigned char *)data;
|
||||
@ -2277,10 +2315,14 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|
||||
}
|
||||
bson_append_finish_array(&b);
|
||||
}
|
||||
bson_finish(&b);
|
||||
#ifdef DEBUG
|
||||
bson_print(&b);
|
||||
#endif
|
||||
if (authors.size())
|
||||
{
|
||||
bson_append_start_object(&b, "authors");
|
||||
ConvertJsonToBson(&b, authors);
|
||||
bson_append_finish_object(&b);
|
||||
}
|
||||
if (bson_finish(&b) == BSON_ERROR)
|
||||
goto fin;
|
||||
|
||||
finalData = (unsigned char *)bson_data(&b);
|
||||
finalDataLen = bson_size(&b);
|
||||
@ -2335,6 +2377,38 @@ fin:
|
||||
return (char*)outputData;
|
||||
}
|
||||
|
||||
// converts a json object to bson
|
||||
void GameSave::ConvertJsonToBson(bson *b, Json::Value j)
|
||||
{
|
||||
Json::Value::Members members = j.getMemberNames();
|
||||
for (Json::Value::Members::iterator iter = members.begin(), end = members.end(); iter != end; ++iter)
|
||||
{
|
||||
std::string member = *iter;
|
||||
if (j[member].isString())
|
||||
bson_append_string(b, member.c_str(), j[member].asCString());
|
||||
else if (j[member].isBool())
|
||||
bson_append_bool(b, member.c_str(), j[member].asBool());
|
||||
else if (j[member].isInt() || j[member].isUInt())
|
||||
bson_append_int(b, member.c_str(), j[member].asInt());
|
||||
else if (j[member].isInt64() || j[member].isUInt64())
|
||||
bson_append_long(b, member.c_str(), j[member].asInt64());
|
||||
else if (j[member].isArray())
|
||||
{
|
||||
bson_append_start_array(b, member.c_str());
|
||||
for (Json::Value::ArrayIndex i = 0; i < j[member].size(); i++)
|
||||
{
|
||||
// only supports objects here because that is all we need
|
||||
if (!j[member][i].isObject())
|
||||
continue;
|
||||
bson_append_start_object(b, "part");
|
||||
ConvertJsonToBson(b, j[member][i]);
|
||||
bson_append_finish_object(b);
|
||||
}
|
||||
bson_append_finish_array(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deallocates a pointer to a 2D array and sets it to NULL
|
||||
template <typename T>
|
||||
void GameSave::Deallocate2DArray(T ***array, int blockHeight)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Misc.h"
|
||||
|
||||
#include "bson/BSON.h"
|
||||
#include "json/json.h"
|
||||
#include "simulation/Sign.h"
|
||||
#include "simulation/Particle.h"
|
||||
|
||||
@ -61,7 +62,10 @@ public:
|
||||
//Element palette
|
||||
typedef std::pair<std::string, int> PaletteItem;
|
||||
std::vector<PaletteItem> palette;
|
||||
|
||||
|
||||
// author information
|
||||
Json::Value authors;
|
||||
|
||||
GameSave();
|
||||
GameSave(GameSave & save);
|
||||
GameSave(int width, int height);
|
||||
@ -112,7 +116,8 @@ private:
|
||||
void readOPS(char * data, int dataLength);
|
||||
void readPSv(char * data, int dataLength);
|
||||
char * serialiseOPS(unsigned int & dataSize);
|
||||
//serialisePSv();
|
||||
void ConvertJsonToBson(bson *b, Json::Value j);
|
||||
void ConvertBsonToJson(bson_iterator *b, Json::Value *j);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -29,9 +29,9 @@ RequestBroker::ProcessResponse ImageRequest::Process(RequestBroker & rb)
|
||||
if((*iter).first == URL)
|
||||
{
|
||||
image = (*iter).second;
|
||||
#ifdef DEBUG
|
||||
/*#ifdef DEBUG
|
||||
std::cout << typeid(*this).name() << " " << URL << " found in cache" << std::endl;
|
||||
#endif
|
||||
#endif*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,9 +74,9 @@ RequestBroker::ProcessResponse ImageRequest::Process(RequestBroker & rb)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
std::cout << typeid(*this).name() << " Request for " << URL << " failed with status " << status << std::endl;
|
||||
#endif
|
||||
#endif
|
||||
free(data);
|
||||
|
||||
return RequestBroker::Failed;
|
||||
@ -93,9 +93,9 @@ RequestBroker::ProcessResponse ImageRequest::Process(RequestBroker & rb)
|
||||
ImageRequest * otherReq = (ImageRequest*)(*iter);
|
||||
if(otherReq->URL == URL && otherReq != this)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
/*#ifdef DEBUG
|
||||
std::cout << typeid(*this).name() << " Request for " << URL << " found, appending." << std::endl;
|
||||
#endif
|
||||
#endif*/
|
||||
//Add the current listener to the item already being requested
|
||||
(*iter)->Children.push_back(this);
|
||||
return RequestBroker::Duplicate;
|
||||
@ -103,9 +103,9 @@ RequestBroker::ProcessResponse ImageRequest::Process(RequestBroker & rb)
|
||||
}
|
||||
|
||||
//If it's not already being requested, request it
|
||||
#ifdef DEBUG
|
||||
/*#ifdef DEBUG
|
||||
std::cout << typeid(*this).name() << " Creating new request for " << URL << std::endl;
|
||||
#endif
|
||||
#endif*/
|
||||
HTTPContext = http_async_req_start(NULL, (char *)URL.c_str(), NULL, 0, 0);
|
||||
RequestTime = time(NULL);
|
||||
}
|
||||
|
@ -319,11 +319,17 @@ sign * GameController::GetSignAt(int x, int y)
|
||||
|
||||
void GameController::PlaceSave(ui::Point position)
|
||||
{
|
||||
if (gameModel->GetPlaceSave())
|
||||
GameSave *placeSave = gameModel->GetPlaceSave();
|
||||
if (placeSave)
|
||||
{
|
||||
HistorySnapshot();
|
||||
gameModel->GetSimulation()->Load(position.X, position.Y, gameModel->GetPlaceSave());
|
||||
gameModel->SetPaused(gameModel->GetPlaceSave()->paused | gameModel->GetPaused());
|
||||
if (!gameModel->GetSimulation()->Load(position.X, position.Y, placeSave))
|
||||
{
|
||||
gameModel->SetPaused(placeSave->paused | gameModel->GetPaused());
|
||||
// if this is a clipboard and there is no author info, don't do anything
|
||||
if (Client::Ref().IsAuthorsEmpty() || placeSave->authors["type"] != "clipboard")
|
||||
Client::Ref().MergeStampAuthorInfo(placeSave->authors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,7 +566,10 @@ std::string GameController::StampRegion(ui::Point point1, ui::Point point2)
|
||||
if(newSave)
|
||||
{
|
||||
newSave->paused = gameModel->GetPaused();
|
||||
return Client::Ref().AddStamp(newSave);
|
||||
std::string stampName = Client::Ref().AddStamp(newSave);
|
||||
if (stampName.length() == 0)
|
||||
new ErrorMessage("Could not create stamp", "Error serializing save file");
|
||||
return stampName;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -575,6 +584,13 @@ void GameController::CopyRegion(ui::Point point1, ui::Point point2)
|
||||
newSave = gameModel->GetSimulation()->Save(point1.X, point1.Y, point2.X, point2.Y);
|
||||
if(newSave)
|
||||
{
|
||||
Json::Value clipboardInfo;
|
||||
clipboardInfo["type"] = "clipboard";
|
||||
clipboardInfo["username"] = Client::Ref().GetAuthUser().Username;
|
||||
clipboardInfo["date"] = (Json::Value::UInt64)time(NULL);
|
||||
Client::Ref().SaveAuthorInfo(&clipboardInfo);
|
||||
newSave->authors = clipboardInfo;
|
||||
|
||||
newSave->paused = gameModel->GetPaused();
|
||||
gameModel->SetClipboard(newSave);
|
||||
}
|
||||
@ -1203,9 +1219,20 @@ void GameController::OpenLocalSaveWindow(bool asCurrent)
|
||||
}
|
||||
else if (gameModel->GetSaveFile())
|
||||
{
|
||||
Json::Value localSaveInfo;
|
||||
localSaveInfo["type"] = "localsave";
|
||||
localSaveInfo["username"] = Client::Ref().GetAuthUser().Username;
|
||||
localSaveInfo["title"] = gameModel->GetSaveFile()->GetName();
|
||||
localSaveInfo["date"] = (Json::Value::UInt64)time(NULL);
|
||||
Client::Ref().SaveAuthorInfo(&localSaveInfo);
|
||||
gameSave->authors = localSaveInfo;
|
||||
|
||||
gameModel->SetSaveFile(&tempSave);
|
||||
Client::Ref().MakeDirectory(LOCAL_SAVE_DIR);
|
||||
if (Client::Ref().WriteFile(gameSave->Serialise(), gameModel->GetSaveFile()->GetName()))
|
||||
std::vector<char> saveData = gameSave->Serialise();
|
||||
if (saveData.size() == 0)
|
||||
new ErrorMessage("Error", "Unable to serialize game data.");
|
||||
else if (Client::Ref().WriteFile(gameSave->Serialise(), gameModel->GetSaveFile()->GetName()))
|
||||
new ErrorMessage("Error", "Unable to write save file.");
|
||||
else
|
||||
gameModel->SetInfoTip("Saved Successfully");
|
||||
|
@ -1,25 +1,29 @@
|
||||
#include "gui/interface/Engine.h"
|
||||
#include "GameModel.h"
|
||||
#include "GameView.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "simulation/Air.h"
|
||||
#include "ToolClasses.h"
|
||||
#include "graphics/Renderer.h"
|
||||
#include "gui/interface/Point.h"
|
||||
#include "Brush.h"
|
||||
#include "EllipseBrush.h"
|
||||
#include "TriangleBrush.h"
|
||||
#include "BitmapBrush.h"
|
||||
#include "client/Client.h"
|
||||
#include "client/GameSave.h"
|
||||
#include "client/SaveFile.h"
|
||||
#include "common/tpt-minmax.h"
|
||||
#include "gui/game/DecorationTool.h"
|
||||
#include "QuickOptions.h"
|
||||
#include "GameModelException.h"
|
||||
#include "Format.h"
|
||||
#include "Favorite.h"
|
||||
|
||||
#include "client/Client.h"
|
||||
#include "client/GameSave.h"
|
||||
#include "client/SaveFile.h"
|
||||
#include "common/tpt-minmax.h"
|
||||
#include "graphics/Renderer.h"
|
||||
#include "simulation/Air.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "simulation/Snapshot.h"
|
||||
|
||||
#include "gui/game/DecorationTool.h"
|
||||
#include "gui/interface/Engine.h"
|
||||
#include "gui/interface/Point.h"
|
||||
|
||||
|
||||
GameModel::GameModel():
|
||||
clipboard(NULL),
|
||||
placeSave(NULL),
|
||||
@ -581,9 +585,6 @@ int GameModel::GetActiveMenu()
|
||||
//Get an element tool from an element ID
|
||||
Tool * GameModel::GetElementTool(int elementID)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << elementID << std::endl;
|
||||
#endif
|
||||
for(std::vector<Tool*>::iterator iter = elementTools.begin(), end = elementTools.end(); iter != end; ++iter)
|
||||
{
|
||||
if((*iter)->GetToolID() == elementID)
|
||||
@ -647,7 +648,28 @@ void GameModel::SetSave(SaveInfo * newSave)
|
||||
sim->grav->stop_grav_async();
|
||||
sim->clear_sim();
|
||||
ren->ClearAccumulation();
|
||||
sim->Load(saveData);
|
||||
if (!sim->Load(saveData))
|
||||
{
|
||||
// This save was created before logging existed
|
||||
// Add in the correct info
|
||||
if (saveData->authors.size() == 0)
|
||||
{
|
||||
saveData->authors["type"] = "save";
|
||||
saveData->authors["id"] = newSave->id;
|
||||
saveData->authors["username"] = newSave->userName;
|
||||
saveData->authors["title"] = newSave->name;
|
||||
saveData->authors["description"] = newSave->Description;
|
||||
saveData->authors["published"] = newSave->Published;
|
||||
saveData->authors["date"] = newSave->updatedDate;
|
||||
}
|
||||
// This save was probably just created, and we didn't know the ID when creating it
|
||||
// Update with the proper ID
|
||||
else if (saveData->authors.get("id", -1) == 0)
|
||||
{
|
||||
saveData->authors["id"] = newSave->id;
|
||||
}
|
||||
Client::Ref().OverwriteAuthorInfo(saveData->authors);
|
||||
}
|
||||
}
|
||||
notifySaveChanged();
|
||||
UpdateQuickOptions();
|
||||
@ -691,7 +713,10 @@ void GameModel::SetSaveFile(SaveFile * newSave)
|
||||
}
|
||||
sim->clear_sim();
|
||||
ren->ClearAccumulation();
|
||||
sim->Load(saveData);
|
||||
if (!sim->Load(saveData))
|
||||
{
|
||||
Client::Ref().OverwriteAuthorInfo(saveData->authors);
|
||||
}
|
||||
}
|
||||
|
||||
notifySaveChanged();
|
||||
@ -968,6 +993,7 @@ void GameModel::ClearSimulation()
|
||||
|
||||
sim->clear_sim();
|
||||
ren->ClearAccumulation();
|
||||
Client::Ref().ClearAuthorInfo();
|
||||
|
||||
notifySaveChanged();
|
||||
UpdateQuickOptions();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "gui/search/Thumbnail.h"
|
||||
#include "simulation/SaveRenderer.h"
|
||||
#include "simulation/SimulationData.h"
|
||||
#include "gui/dialogues/InformationMessage.h"
|
||||
#include "gui/dialogues/ConfirmPrompt.h"
|
||||
#include "client/SaveFile.h"
|
||||
#include "Format.h"
|
||||
@ -1487,6 +1488,15 @@ void GameView::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool
|
||||
case SDLK_F5:
|
||||
c->ReloadSim();
|
||||
break;
|
||||
#if defined(DEBUG) || defined(SNAPSHOT)
|
||||
case 'a':
|
||||
if (ctrl)
|
||||
{
|
||||
std::string authorString = Client::Ref().GetAuthorString();
|
||||
new InformationMessage("Save authorship info", authorString, true);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 'r':
|
||||
if (ctrl)
|
||||
c->ReloadSim();
|
||||
|
@ -110,7 +110,18 @@ void LocalSaveActivity::Save()
|
||||
void LocalSaveActivity::saveWrite(std::string finalFilename)
|
||||
{
|
||||
Client::Ref().MakeDirectory(LOCAL_SAVE_DIR);
|
||||
if (Client::Ref().WriteFile(save.GetGameSave()->Serialise(), finalFilename))
|
||||
GameSave *gameSave = save.GetGameSave();
|
||||
Json::Value localSaveInfo;
|
||||
localSaveInfo["type"] = "localsave";
|
||||
localSaveInfo["username"] = Client::Ref().GetAuthUser().Username;
|
||||
localSaveInfo["title"] = finalFilename;
|
||||
localSaveInfo["date"] = (Json::Value::UInt64)time(NULL);
|
||||
Client::Ref().SaveAuthorInfo(&localSaveInfo);
|
||||
gameSave->authors = localSaveInfo;
|
||||
std::vector<char> saveData = gameSave->Serialise();
|
||||
if (saveData.size() == 0)
|
||||
new ErrorMessage("Error", "Unable to serialize game data.");
|
||||
else if (Client::Ref().WriteFile(gameSave->Serialise(), finalFilename))
|
||||
new ErrorMessage("Error", "Unable to write save file.");
|
||||
else
|
||||
{
|
||||
|
@ -199,7 +199,9 @@ ServerSaveActivity::ServerSaveActivity(SaveInfo save, bool saveNow, ServerSaveAc
|
||||
titleLabel->Appearance.VerticalAlign = ui::Appearance::AlignMiddle;
|
||||
AddComponent(titleLabel);
|
||||
|
||||
saveUploadTask = new SaveUploadTask(save);
|
||||
AddAuthorInfo();
|
||||
|
||||
saveUploadTask = new SaveUploadTask(this->save);
|
||||
saveUploadTask->AddTaskListener(this);
|
||||
saveUploadTask->Start();
|
||||
}
|
||||
@ -255,6 +257,20 @@ void ServerSaveActivity::Save()
|
||||
}
|
||||
}
|
||||
|
||||
void ServerSaveActivity::AddAuthorInfo()
|
||||
{
|
||||
Json::Value serverSaveInfo;
|
||||
serverSaveInfo["type"] = "save";
|
||||
serverSaveInfo["id"] = save.GetID();
|
||||
serverSaveInfo["username"] = Client::Ref().GetAuthUser().Username;
|
||||
serverSaveInfo["title"] = save.GetName();
|
||||
serverSaveInfo["description"] = save.GetDescription();
|
||||
serverSaveInfo["published"] = save.GetPublished();
|
||||
serverSaveInfo["date"] = (Json::Value::UInt64)time(NULL);
|
||||
Client::Ref().SaveAuthorInfo(&serverSaveInfo);
|
||||
save.GetGameSave()->authors = serverSaveInfo;
|
||||
}
|
||||
|
||||
void ServerSaveActivity::saveUpload()
|
||||
{
|
||||
save.SetName(nameField->GetText());
|
||||
@ -263,6 +279,7 @@ void ServerSaveActivity::saveUpload()
|
||||
save.SetUserName(Client::Ref().GetAuthUser().Username);
|
||||
save.SetID(0);
|
||||
save.GetGameSave()->paused = pausedCheckbox->GetChecked();
|
||||
AddAuthorInfo();
|
||||
|
||||
if(Client::Ref().UploadSave(save) != RequestOkay)
|
||||
{
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
virtual void OnTick(float dt);
|
||||
virtual ~ServerSaveActivity();
|
||||
protected:
|
||||
void AddAuthorInfo();
|
||||
virtual void NotifyDone(Task * task);
|
||||
VideoBuffer * thumbnail;
|
||||
SaveInfo save;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "gui/game/Tool.h"
|
||||
#include "LuaScriptHelper.h"
|
||||
#include "client/HTTP.h"
|
||||
#include "client/GameSave.h"
|
||||
#include "client/SaveFile.h"
|
||||
#include "Misc.h"
|
||||
#include "Platform.h"
|
||||
@ -1593,6 +1594,7 @@ int LuaScriptInterface::simulation_decoColor(lua_State * l)
|
||||
int LuaScriptInterface::simulation_clearSim(lua_State * l)
|
||||
{
|
||||
luacon_sim->clear_sim();
|
||||
Client::Ref().ClearAuthorInfo();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1672,7 +1674,7 @@ int LuaScriptInterface::simulation_loadStamp(lua_State * l)
|
||||
const char * filename = luaL_optstring(l, 1, "");
|
||||
tempfile = Client::Ref().GetStamp(filename);
|
||||
}
|
||||
if (!tempfile && lua_isnumber(l, 1)) //Load from stamp ID
|
||||
if ((!tempfile || !tempfile->GetGameSave()) && lua_isnumber(l, 1)) //Load from stamp ID
|
||||
{
|
||||
i = luaL_optint(l, 1, 0);
|
||||
int stampCount = Client::Ref().GetStampsCount();
|
||||
@ -1687,6 +1689,12 @@ int LuaScriptInterface::simulation_loadStamp(lua_State * l)
|
||||
{
|
||||
//luacon_sim->sys_pause = (tempfile->GetGameSave()->paused | luacon_model->GetPaused())?1:0;
|
||||
lua_pushinteger(l, 1);
|
||||
|
||||
if (tempfile->GetGameSave()->authors.size())
|
||||
{
|
||||
tempfile->GetGameSave()->authors["type"] = "luastamp";
|
||||
Client::Ref().MergeStampAuthorInfo(tempfile->GetGameSave()->authors);
|
||||
}
|
||||
}
|
||||
else
|
||||
lua_pushnil(l);
|
||||
|
Loading…
x
Reference in New Issue
Block a user