mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
1274 lines
50 KiB
C++
1274 lines
50 KiB
C++
/*
|
|
* GDevelop Core
|
|
* Copyright 2008-2015 Florian Rival (Florian.Rival@gmail.com). All rights reserved.
|
|
* This project is released under the MIT License.
|
|
*/
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
#include "GDCore/String.h"
|
|
#include <fstream>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <SFML/System/Utf.hpp>
|
|
#include "GDCore/IDE/Dialogs/ProjectExtensionsDialog.h"
|
|
#include "GDCore/IDE/Dialogs/ProjectUpdateDialog.h"
|
|
#include "GDCore/IDE/Dialogs/ChooseVariableDialog.h"
|
|
#include "GDCore/IDE/ArbitraryResourceWorker.h"
|
|
#include "GDCore/PlatformDefinition/Platform.h"
|
|
#include "GDCore/PlatformDefinition/PlatformExtension.h"
|
|
#include "GDCore/PlatformDefinition/Layout.h"
|
|
#include "GDCore/PlatformDefinition/ExternalEvents.h"
|
|
#include "GDCore/PlatformDefinition/ExternalLayout.h"
|
|
#include "GDCore/PlatformDefinition/SourceFile.h"
|
|
#include "GDCore/PlatformDefinition/ImageManager.h"
|
|
#include "GDCore/PlatformDefinition/Object.h"
|
|
#include "GDCore/PlatformDefinition/ResourcesManager.h"
|
|
#include "GDCore/PlatformDefinition/ChangesNotifier.h"
|
|
#include "GDCore/Events/ExpressionMetadata.h"
|
|
#include "GDCore/Serialization/SerializerElement.h"
|
|
#include "GDCore/Serialization/Serializer.h"
|
|
#include "GDCore/IDE/MetadataProvider.h"
|
|
#include "GDCore/IDE/PlatformManager.h"
|
|
#include "GDCore/IDE/wxTools/SafeYield.h"
|
|
#include "GDCore/CommonTools.h"
|
|
#include "GDCore/Utf8/utf8.h"
|
|
#include "GDCore/TinyXml/tinyxml.h"
|
|
#include "GDCore/Tools/VersionWrapper.h"
|
|
#include "GDCore/Tools/Log.h"
|
|
#include "GDCore/Tools/Localization.h"
|
|
#include "GDCore/Serialization/Serializer.h"
|
|
#include "Project.h"
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
#include <wx/propgrid/propgrid.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/propgrid/propgrid.h>
|
|
#include <wx/propgrid/advprops.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/filename.h>
|
|
#include <wx/stdpaths.h>
|
|
#include <wx/utils.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
#undef CreateEvent
|
|
|
|
namespace gd
|
|
{
|
|
|
|
Project::Project() :
|
|
#if defined(GD_IDE_ONLY)
|
|
name(_("Project")),
|
|
packageName("com.example.gamename"),
|
|
#endif
|
|
windowWidth(800),
|
|
windowHeight(600),
|
|
maxFPS(60),
|
|
minFPS(10),
|
|
verticalSync(false),
|
|
imageManager(std::shared_ptr<gd::ImageManager>(new ImageManager))
|
|
#if defined(GD_IDE_ONLY)
|
|
,useExternalSourceFiles(false),
|
|
currentPlatform(NULL),
|
|
GDMajorVersion(gd::VersionWrapper::Major()),
|
|
GDMinorVersion(gd::VersionWrapper::Minor()),
|
|
dirty(false)
|
|
#endif
|
|
{
|
|
imageManager->SetGame(this);
|
|
#if defined(GD_IDE_ONLY)
|
|
//Game use builtin extensions by default
|
|
extensionsUsed.push_back("BuiltinObject");
|
|
extensionsUsed.push_back("BuiltinAudio");
|
|
extensionsUsed.push_back("BuiltinVariables");
|
|
extensionsUsed.push_back("BuiltinTime");
|
|
extensionsUsed.push_back("BuiltinMouse");
|
|
extensionsUsed.push_back("BuiltinKeyboard");
|
|
extensionsUsed.push_back("BuiltinJoystick");
|
|
extensionsUsed.push_back("BuiltinCamera");
|
|
extensionsUsed.push_back("BuiltinWindow");
|
|
extensionsUsed.push_back("BuiltinFile");
|
|
extensionsUsed.push_back("BuiltinNetwork");
|
|
extensionsUsed.push_back("BuiltinScene");
|
|
extensionsUsed.push_back("BuiltinAdvanced");
|
|
extensionsUsed.push_back("Sprite");
|
|
extensionsUsed.push_back("BuiltinCommonInstructions");
|
|
extensionsUsed.push_back("BuiltinCommonConversions");
|
|
extensionsUsed.push_back("BuiltinStringInstructions");
|
|
extensionsUsed.push_back("BuiltinMathematicalTools");
|
|
extensionsUsed.push_back("BuiltinExternalLayouts");
|
|
#endif
|
|
|
|
#if !defined(GD_IDE_ONLY)
|
|
platforms.push_back(&CppPlatform::Get());
|
|
#endif
|
|
}
|
|
|
|
Project::~Project()
|
|
{
|
|
}
|
|
|
|
std::shared_ptr<gd::Object> Project::CreateObject(const gd::String & type, const gd::String & name, const gd::String & platformName)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if ( !platformName.empty() && platforms[i]->GetName() != platformName ) continue;
|
|
|
|
std::shared_ptr<gd::Object> object = platforms[i]->CreateObject(type, name); //Create a base object if the type can't be found in the platform
|
|
if ( object && object->GetType() == type ) return object; //If the object is valid and has the good type (not a base object), return it
|
|
}
|
|
|
|
return std::shared_ptr<gd::Object>();
|
|
}
|
|
|
|
gd::Behavior* Project::CreateBehavior(const gd::String & type, const gd::String & platformName)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if ( !platformName.empty() && platforms[i]->GetName() != platformName ) continue;
|
|
|
|
gd::Behavior* behavior = platforms[i]->CreateBehavior(type);
|
|
if ( behavior ) return behavior;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
std::shared_ptr<gd::BehaviorsSharedData> Project::CreateBehaviorSharedDatas(const gd::String & type, const gd::String & platformName)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if ( !platformName.empty() && platforms[i]->GetName() != platformName ) continue;
|
|
|
|
std::shared_ptr<gd::BehaviorsSharedData> behavior = platforms[i]->CreateBehaviorSharedDatas(type);
|
|
if ( behavior ) return behavior;
|
|
}
|
|
|
|
return std::shared_ptr<gd::BehaviorsSharedData>();
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(const gd::String & type, const gd::String & platformName)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if ( !platformName.empty() && platforms[i]->GetName() != platformName ) continue;
|
|
|
|
std::shared_ptr<gd::BaseEvent> event = platforms[i]->CreateEvent(type);
|
|
if ( event ) return event;
|
|
}
|
|
|
|
return std::shared_ptr<gd::BaseEvent>();
|
|
}
|
|
|
|
Platform & Project::GetCurrentPlatform() const
|
|
{
|
|
if ( currentPlatform == NULL )
|
|
std::cout << "FATAL ERROR: Project has no assigned current platform. GD will crash." << std::endl;
|
|
|
|
return *currentPlatform;
|
|
}
|
|
|
|
void Project::AddPlatform(Platform & platform)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if (platforms[i] == &platform)
|
|
return;
|
|
}
|
|
|
|
//Add the platform and make it the current one if the game has no other platform.
|
|
platforms.push_back(&platform);
|
|
if ( currentPlatform == NULL ) currentPlatform = &platform;
|
|
}
|
|
|
|
void Project::SetCurrentPlatform(const gd::String & platformName)
|
|
{
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if (platforms[i]->GetName() == platformName)
|
|
{
|
|
currentPlatform = platforms[i];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Project::RemovePlatform(const gd::String & platformName)
|
|
{
|
|
if ( platforms.size() <= 1 ) return false;
|
|
|
|
for (std::size_t i = 0;i<platforms.size();++i)
|
|
{
|
|
if (platforms[i]->GetName() == platformName)
|
|
{
|
|
//Remove the platform, ensuring that currentPlatform remains correct.
|
|
if ( currentPlatform == platforms[i] ) currentPlatform = platforms.back();
|
|
if ( currentPlatform == platforms[i] ) currentPlatform = platforms[0];
|
|
platforms.erase(platforms.begin()+i);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
bool Project::HasLayoutNamed(const gd::String & name) const
|
|
{
|
|
return ( find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)) != scenes.end() );
|
|
}
|
|
gd::Layout & Project::GetLayout(const gd::String & name)
|
|
{
|
|
return *(*find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
|
}
|
|
const gd::Layout & Project::GetLayout(const gd::String & name) const
|
|
{
|
|
return *(*find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
|
}
|
|
gd::Layout & Project::GetLayout(std::size_t index)
|
|
{
|
|
return *scenes[index];
|
|
}
|
|
const gd::Layout & Project::GetLayout (std::size_t index) const
|
|
{
|
|
return *scenes[index];
|
|
}
|
|
std::size_t Project::GetLayoutPosition(const gd::String & name) const
|
|
{
|
|
for (std::size_t i = 0;i<scenes.size();++i)
|
|
{
|
|
if ( scenes[i]->GetName() == name ) return i;
|
|
}
|
|
return gd::String::npos;
|
|
}
|
|
std::size_t Project::GetLayoutsCount() const
|
|
{
|
|
return scenes.size();
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
void Project::SwapLayouts(std::size_t first, std::size_t second)
|
|
{
|
|
if ( first >= scenes.size() || second >= scenes.size() )
|
|
return;
|
|
|
|
std::shared_ptr<gd::Layout> firstItem = scenes[first];
|
|
std::shared_ptr<gd::Layout> secondItem = scenes[second];
|
|
scenes[first] = secondItem;
|
|
scenes[second] = firstItem;
|
|
}
|
|
#endif
|
|
|
|
gd::Layout & Project::InsertNewLayout(const gd::String & name, std::size_t position)
|
|
{
|
|
std::shared_ptr<gd::Layout> newScene = std::shared_ptr<gd::Layout>(new Layout);
|
|
if (position<scenes.size())
|
|
scenes.insert(scenes.begin()+position, newScene);
|
|
else
|
|
scenes.push_back(newScene);
|
|
|
|
newScene->SetName(name);
|
|
#if defined(GD_IDE_ONLY)
|
|
newScene->UpdateBehaviorsSharedData(*this);
|
|
#endif
|
|
|
|
return *newScene;
|
|
}
|
|
|
|
gd::Layout & Project::InsertLayout(const gd::Layout & layout, std::size_t position)
|
|
{
|
|
std::shared_ptr<gd::Layout> newScene = std::shared_ptr<gd::Layout>(new Layout(layout));
|
|
if (position<scenes.size())
|
|
scenes.insert(scenes.begin()+position, newScene);
|
|
else
|
|
scenes.push_back(newScene);
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
newScene->UpdateBehaviorsSharedData(*this);
|
|
#endif
|
|
|
|
return *newScene;
|
|
}
|
|
|
|
void Project::RemoveLayout(const gd::String & name)
|
|
{
|
|
std::vector< std::shared_ptr<gd::Layout> >::iterator scene = find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name));
|
|
if ( scene == scenes.end() ) return;
|
|
|
|
scenes.erase(scene);
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
bool Project::HasExternalEventsNamed(const gd::String & name) const
|
|
{
|
|
return ( find_if(externalEvents.begin(), externalEvents.end(), bind2nd(gd::ExternalEventsHasName(), name)) != externalEvents.end() );
|
|
}
|
|
gd::ExternalEvents & Project::GetExternalEvents(const gd::String & name)
|
|
{
|
|
return *(*find_if(externalEvents.begin(), externalEvents.end(), bind2nd(gd::ExternalEventsHasName(), name)));
|
|
}
|
|
const gd::ExternalEvents & Project::GetExternalEvents(const gd::String & name) const
|
|
{
|
|
return *(*find_if(externalEvents.begin(), externalEvents.end(), bind2nd(gd::ExternalEventsHasName(), name)));
|
|
}
|
|
gd::ExternalEvents & Project::GetExternalEvents(std::size_t index)
|
|
{
|
|
return *externalEvents[index];
|
|
}
|
|
const gd::ExternalEvents & Project::GetExternalEvents (std::size_t index) const
|
|
{
|
|
return *externalEvents[index];
|
|
}
|
|
std::size_t Project::GetExternalEventsPosition(const gd::String & name) const
|
|
{
|
|
for (std::size_t i = 0;i<externalEvents.size();++i)
|
|
{
|
|
if ( externalEvents[i]->GetName() == name ) return i;
|
|
}
|
|
return gd::String::npos;
|
|
}
|
|
std::size_t Project::GetExternalEventsCount() const
|
|
{
|
|
return externalEvents.size();
|
|
}
|
|
|
|
gd::ExternalEvents & Project::InsertNewExternalEvents(const gd::String & name, std::size_t position)
|
|
{
|
|
std::shared_ptr<gd::ExternalEvents> newExternalEvents(new gd::ExternalEvents);
|
|
if (position<externalEvents.size())
|
|
externalEvents.insert(externalEvents.begin()+position, newExternalEvents);
|
|
else
|
|
externalEvents.push_back(newExternalEvents);
|
|
|
|
newExternalEvents->SetName(name);
|
|
return *newExternalEvents;
|
|
}
|
|
|
|
void Project::InsertExternalEvents(const gd::ExternalEvents & events, std::size_t position)
|
|
{
|
|
if (position<externalEvents.size())
|
|
externalEvents.insert(externalEvents.begin()+position, std::shared_ptr<gd::ExternalEvents>(new gd::ExternalEvents(events)));
|
|
else
|
|
externalEvents.push_back(std::shared_ptr<gd::ExternalEvents>(new gd::ExternalEvents(events)));
|
|
}
|
|
|
|
void Project::RemoveExternalEvents(const gd::String & name)
|
|
{
|
|
std::vector< std::shared_ptr<gd::ExternalEvents> >::iterator events = find_if(externalEvents.begin(), externalEvents.end(), bind2nd(gd::ExternalEventsHasName(), name));
|
|
if ( events == externalEvents.end() ) return;
|
|
|
|
externalEvents.erase(events);
|
|
}
|
|
|
|
void Project::SwapExternalEvents(std::size_t first, std::size_t second)
|
|
{
|
|
if ( first >= externalEvents.size() || second >= externalEvents.size() )
|
|
return;
|
|
|
|
std::shared_ptr<gd::ExternalEvents> firstItem = externalEvents[first];
|
|
std::shared_ptr<gd::ExternalEvents> secondItem = externalEvents[second];
|
|
externalEvents[first] = secondItem;
|
|
externalEvents[second] = firstItem;
|
|
}
|
|
|
|
void Project::SwapExternalLayouts(std::size_t first, std::size_t second)
|
|
{
|
|
if ( first >= externalLayouts.size() || second >= externalLayouts.size() )
|
|
return;
|
|
|
|
std::shared_ptr<gd::ExternalLayout> firstItem = externalLayouts[first];
|
|
std::shared_ptr<gd::ExternalLayout> secondItem = externalLayouts[second];
|
|
externalLayouts[first] = secondItem;
|
|
externalLayouts[second] = firstItem;
|
|
}
|
|
#endif
|
|
bool Project::HasExternalLayoutNamed(const gd::String & name) const
|
|
{
|
|
return ( find_if(externalLayouts.begin(), externalLayouts.end(), bind2nd(gd::ExternalLayoutHasName(), name)) != externalLayouts.end() );
|
|
}
|
|
gd::ExternalLayout & Project::GetExternalLayout(const gd::String & name)
|
|
{
|
|
return *(*find_if(externalLayouts.begin(), externalLayouts.end(), bind2nd(gd::ExternalLayoutHasName(), name)));
|
|
}
|
|
const gd::ExternalLayout & Project::GetExternalLayout(const gd::String & name) const
|
|
{
|
|
return *(*find_if(externalLayouts.begin(), externalLayouts.end(), bind2nd(gd::ExternalLayoutHasName(), name)));
|
|
}
|
|
gd::ExternalLayout & Project::GetExternalLayout(std::size_t index)
|
|
{
|
|
return *externalLayouts[index];
|
|
}
|
|
const gd::ExternalLayout & Project::GetExternalLayout (std::size_t index) const
|
|
{
|
|
return *externalLayouts[index];
|
|
}
|
|
std::size_t Project::GetExternalLayoutPosition(const gd::String & name) const
|
|
{
|
|
for (std::size_t i = 0;i<externalLayouts.size();++i)
|
|
{
|
|
if ( externalLayouts[i]->GetName() == name ) return i;
|
|
}
|
|
return gd::String::npos;
|
|
}
|
|
|
|
std::size_t Project::GetExternalLayoutsCount() const
|
|
{
|
|
return externalLayouts.size();
|
|
}
|
|
|
|
gd::ExternalLayout & Project::InsertNewExternalLayout(const gd::String & name, std::size_t position)
|
|
{
|
|
std::shared_ptr<gd::ExternalLayout> newExternalLayout = std::shared_ptr<gd::ExternalLayout>(new gd::ExternalLayout);
|
|
if (position<externalLayouts.size())
|
|
externalLayouts.insert(externalLayouts.begin()+position, newExternalLayout);
|
|
else
|
|
externalLayouts.push_back(newExternalLayout);
|
|
|
|
newExternalLayout->SetName(name);
|
|
return *newExternalLayout;
|
|
}
|
|
|
|
void Project::InsertExternalLayout(const gd::ExternalLayout & layout, std::size_t position)
|
|
{
|
|
std::shared_ptr<gd::ExternalLayout> newLayout(new gd::ExternalLayout(layout));
|
|
|
|
if (position<externalLayouts.size())
|
|
externalLayouts.insert(externalLayouts.begin()+position, newLayout);
|
|
else
|
|
externalLayouts.push_back(newLayout);
|
|
}
|
|
|
|
void Project::RemoveExternalLayout(const gd::String & name)
|
|
{
|
|
std::vector< std::shared_ptr<gd::ExternalLayout> >::iterator externalLayout = find_if(externalLayouts.begin(), externalLayouts.end(), bind2nd(gd::ExternalLayoutHasName(), name));
|
|
if ( externalLayout == externalLayouts.end() ) return;
|
|
|
|
externalLayouts.erase(externalLayout);
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
//Compatibility with GD2.x
|
|
class SpriteObjectsPositionUpdater : public gd::InitialInstanceFunctor
|
|
{
|
|
public:
|
|
SpriteObjectsPositionUpdater(gd::Project & project_, gd::Layout & layout_) :
|
|
project(project_),
|
|
layout(layout_)
|
|
{};
|
|
virtual ~SpriteObjectsPositionUpdater() {};
|
|
|
|
virtual void operator()(gd::InitialInstance * instancePtr)
|
|
{
|
|
gd::InitialInstance & instance = *instancePtr;
|
|
gd::Object * object = NULL;
|
|
if ( layout.HasObjectNamed(instance.GetObjectName()))
|
|
object = &layout.GetObject(instance.GetObjectName());
|
|
else if ( project.HasObjectNamed(instance.GetObjectName()))
|
|
object = &project.GetObject(instance.GetObjectName());
|
|
else return;
|
|
|
|
if ( object->GetType() != "Sprite") return;
|
|
if ( !instance.HasCustomSize() ) return;
|
|
|
|
wxSetWorkingDirectory(wxFileName::FileName(project.GetProjectFile()).GetPath());
|
|
object->LoadResources(project, layout);
|
|
|
|
sf::Vector2f size = object->GetInitialInstanceDefaultSize(instance, project, layout);
|
|
|
|
instance.SetX(instance.GetX() + size.x/2 - instance.GetCustomWidth()/2 );
|
|
instance.SetY(instance.GetY() + size.y/2 - instance.GetCustomHeight()/2 );
|
|
}
|
|
|
|
private:
|
|
gd::Project & project;
|
|
gd::Layout & layout;
|
|
};
|
|
//End of compatibility code
|
|
#endif
|
|
|
|
void Project::UnserializeFrom(const SerializerElement & element)
|
|
{
|
|
//Checking version
|
|
#if defined(GD_IDE_ONLY)
|
|
gd::String updateText;
|
|
|
|
const SerializerElement & gdVersionElement = element.GetChild("gdVersion", 0, "GDVersion");
|
|
GDMajorVersion = gdVersionElement.GetIntAttribute("major", GDMajorVersion, "Major");
|
|
GDMinorVersion = gdVersionElement.GetIntAttribute("minor", GDMinorVersion, "Minor");
|
|
int build = gdVersionElement.GetIntAttribute("build", 0, "Build");
|
|
int revision = gdVersionElement.GetIntAttribute("revision", 0, "Revision");
|
|
|
|
if ( GDMajorVersion > gd::VersionWrapper::Major() )
|
|
gd::LogWarning( _( "The version of GDevelop used to create this game seems to be a new version.\nGDevelop may fail to open the game, or data may be missing.\nYou should check if a new version of GDevelop is available." ) );
|
|
else
|
|
{
|
|
if ( (GDMajorVersion == gd::VersionWrapper::Major() && GDMinorVersion > gd::VersionWrapper::Minor()) ||
|
|
(GDMajorVersion == gd::VersionWrapper::Major() && GDMinorVersion == gd::VersionWrapper::Minor() && build > gd::VersionWrapper::Build()) ||
|
|
(GDMajorVersion == gd::VersionWrapper::Major() && GDMinorVersion == gd::VersionWrapper::Minor() && build == gd::VersionWrapper::Build() && revision > gd::VersionWrapper::Revision()) )
|
|
{
|
|
gd::LogWarning( _( "The version of GDevelop used to create this game seems to be greater.\nGDevelop may fail to open the game, or data may be missing.\nYou should check if a new version of GDevelop is available." ) );
|
|
}
|
|
}
|
|
|
|
//Compatibility code
|
|
if ( GDMajorVersion <= 1 )
|
|
{
|
|
gd::LogError( _("The game was saved with version of GDevelop which is too old. Please open and save the game with one of the first version of GDevelop 2. You will then be able to open your game with this GDevelop version."));
|
|
return;
|
|
}
|
|
//End of Compatibility code
|
|
#endif
|
|
|
|
const SerializerElement & propElement = element.GetChild("properties", 0, "Info");
|
|
SetName(propElement.GetChild("name", 0, "Nom").GetValue().GetString());
|
|
SetDefaultWidth(propElement.GetChild("windowWidth", 0, "WindowW").GetValue().GetInt());
|
|
SetDefaultHeight(propElement.GetChild("windowHeight", 0, "WindowH").GetValue().GetInt());
|
|
SetMaximumFPS(propElement.GetChild("maxFPS", 0, "FPSmax").GetValue().GetInt());
|
|
SetMinimumFPS(propElement.GetChild("minFPS", 0, "FPSmin").GetValue().GetInt());
|
|
SetVerticalSyncActivatedByDefault(propElement.GetChild("verticalSync").GetValue().GetInt());
|
|
#if defined(GD_IDE_ONLY)
|
|
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
|
SetPackageName(propElement.GetStringAttribute("packageName"));
|
|
SetLastCompilationDirectory(propElement.GetChild("latestCompilationDirectory", 0, "LatestCompilationDirectory").GetValue().GetString());
|
|
winExecutableFilename = propElement.GetStringAttribute("winExecutableFilename");
|
|
winExecutableIconFile = propElement.GetStringAttribute("winExecutableIconFile");
|
|
linuxExecutableFilename = propElement.GetStringAttribute("linuxExecutableFilename");
|
|
macExecutableFilename = propElement.GetStringAttribute("macExecutableFilename");
|
|
useExternalSourceFiles = propElement.GetBoolAttribute("useExternalSourceFiles");
|
|
#endif
|
|
|
|
const SerializerElement & extensionsElement = propElement.GetChild("extensions", 0, "Extensions");
|
|
extensionsElement.ConsiderAsArrayOf("extension", "Extension");
|
|
for(std::size_t i = 0;i<extensionsElement.GetChildrenCount();++i)
|
|
{
|
|
gd::String extensionName = extensionsElement.GetChild(i).GetStringAttribute("name");
|
|
if ( find(GetUsedExtensions().begin(), GetUsedExtensions().end(), extensionName ) == GetUsedExtensions().end() )
|
|
GetUsedExtensions().push_back(extensionName);
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
currentPlatform = NULL;
|
|
gd::String currentPlatformName = propElement.GetChild("currentPlatform").GetValue().GetString();
|
|
//Compatibility code
|
|
if ( VersionWrapper::IsOlderOrEqual(GDMajorVersion, GDMajorVersion, GDMinorVersion, 0, 3, 4, 73, 0) )
|
|
{
|
|
if (currentPlatformName == "Game Develop C++ platform") currentPlatformName = "GDevelop C++ platform";
|
|
if (currentPlatformName == "Game Develop JS platform") currentPlatformName = "GDevelop JS platform";
|
|
}
|
|
//End of Compatibility code
|
|
|
|
const SerializerElement & platformsElement = propElement.GetChild("platforms", 0, "Platforms");
|
|
platformsElement.ConsiderAsArrayOf("platform", "Platform");
|
|
for(std::size_t i = 0;i<platformsElement.GetChildrenCount();++i)
|
|
{
|
|
gd::String name = platformsElement.GetChild(i).GetStringAttribute("name");
|
|
//Compatibility code
|
|
if ( VersionWrapper::IsOlderOrEqual(GDMajorVersion, GDMajorVersion, GDMinorVersion, 0, 3, 4, 73, 0) )
|
|
{
|
|
if (name == "Game Develop C++ platform") name = "GDevelop C++ platform";
|
|
if (name == "Game Develop JS platform") name = "GDevelop JS platform";
|
|
}
|
|
//End of Compatibility code
|
|
|
|
gd::Platform * platform = gd::PlatformManager::Get()->GetPlatform(name);
|
|
|
|
if ( platform ) {
|
|
AddPlatform(*platform);
|
|
if ( platform->GetName() == currentPlatformName || currentPlatformName.empty() )
|
|
currentPlatform = platform;
|
|
}
|
|
else {
|
|
std::cout << "Platform \"" << name << "\" is unknown." << std::endl;
|
|
}
|
|
}
|
|
|
|
//Compatibility code
|
|
if ( platformsElement.GetChildrenCount() == 0 )
|
|
{
|
|
//Compatibility with GD2.x
|
|
platforms.push_back(gd::PlatformManager::Get()->GetPlatform("GDevelop C++ platform"));
|
|
currentPlatform = platforms.back();
|
|
}
|
|
//End of Compatibility code
|
|
|
|
if (currentPlatform == NULL && !platforms.empty())
|
|
currentPlatform = platforms.back();
|
|
#endif
|
|
|
|
//Compatibility code
|
|
#if defined(GD_IDE_ONLY)
|
|
if ( VersionWrapper::IsOlder(GDMajorVersion, 0, 0, 0, 3, 0, 0, 0) )
|
|
{
|
|
updateText += _("Sprite scaling has changed since GD 2: The resizing is made so that the origin point of the object won't move whatever the scale of the object.\n");
|
|
updateText += _("You may have to slightly change the position of some objects if you have changed their size.\n\n");
|
|
updateText += _("Thank you for your understanding.\n");
|
|
|
|
}
|
|
#endif
|
|
//End of Compatibility code
|
|
|
|
//Compatibility code
|
|
#if defined(GD_IDE_ONLY)
|
|
if ( VersionWrapper::IsOlderOrEqual(GDMajorVersion, GDMinorVersion, revision, build, 2,2,1,10822) )
|
|
{
|
|
if ( std::find(GetUsedExtensions().begin(), GetUsedExtensions().end(), "BuiltinExternalLayouts") == GetUsedExtensions().end() )
|
|
GetUsedExtensions().push_back("BuiltinExternalLayouts");
|
|
}
|
|
#endif
|
|
|
|
//Compatibility code
|
|
#if defined(GD_IDE_ONLY)
|
|
if ( VersionWrapper::IsOlderOrEqual(GDMajorVersion, GDMinorVersion, revision, build, 3,3,3,0) )
|
|
{
|
|
if ( std::find(GetUsedExtensions().begin(), GetUsedExtensions().end(), "AStarBehavior") != GetUsedExtensions().end() )
|
|
{
|
|
GetUsedExtensions().erase( std::remove( GetUsedExtensions().begin(), GetUsedExtensions().end(), "AStarBehavior" ), GetUsedExtensions().end() );
|
|
GetUsedExtensions().push_back("PathfindingBehavior");
|
|
updateText += _("The project is using the pathfinding behavior. This behavior has been replaced by a new one:\n");
|
|
updateText += _("You must add the new 'Pathfinding' behavior to the objects that need to be moved, and add the 'Pathfinding Obstacle' to the objects that must act as obstacles.");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//Compatibility code
|
|
#if defined(GD_IDE_ONLY)
|
|
if ( VersionWrapper::IsOlderOrEqual(GDMajorVersion, GDMinorVersion, revision, build, 4,0,85,0) )
|
|
{
|
|
for(unsigned int i = 0;i < extensionsUsed.size();++i)
|
|
{
|
|
gd::String oldWord = "Automatism";
|
|
size_t pos = extensionsUsed[i].find(oldWord);
|
|
if (pos != gd::String::npos)
|
|
extensionsUsed[i] = extensionsUsed[i].replace(pos, oldWord.size(), "Behavior");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
ObjectGroup::UnserializeFrom(GetObjectGroups(), element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
|
#endif
|
|
resourcesManager.UnserializeFrom(element.GetChild( "resources", 0, "Resources" ));
|
|
UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
|
|
GetVariables().UnserializeFrom(element.GetChild("variables", 0, "Variables"));
|
|
|
|
const SerializerElement & layoutsElement = element.GetChild("layouts", 0, "Scenes");
|
|
layoutsElement.ConsiderAsArrayOf("layout", "Scene");
|
|
for(std::size_t i = 0;i<layoutsElement.GetChildrenCount();++i)
|
|
{
|
|
const SerializerElement & layoutElement = layoutsElement.GetChild(i);
|
|
|
|
gd::Layout & layout = InsertNewLayout(layoutElement.GetStringAttribute("name", "", "nom"), -1);
|
|
layout.UnserializeFrom(*this, layoutElement);
|
|
|
|
//Compatibility code with GD 2.x
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI)
|
|
if ( GDMajorVersion <= 2 )
|
|
{
|
|
SpriteObjectsPositionUpdater updater(*this, layout);
|
|
gd::InitialInstancesContainer & instances = layout.GetInitialInstances();
|
|
instances.IterateOverInstances(updater);
|
|
}
|
|
#endif
|
|
//End of compatibility code
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
const SerializerElement & externalEventsElement = element.GetChild("externalEvents", 0, "ExternalEvents");
|
|
externalEventsElement.ConsiderAsArrayOf("externalEvents", "ExternalEvents");
|
|
for(std::size_t i = 0;i<externalEventsElement.GetChildrenCount();++i)
|
|
{
|
|
const SerializerElement & externalEventElement = externalEventsElement.GetChild(i);
|
|
|
|
gd::ExternalEvents & externalEvents = InsertNewExternalEvents(externalEventElement.GetStringAttribute("name", "", "Name"),
|
|
GetExternalEventsCount());
|
|
externalEvents.UnserializeFrom(*this, externalEventElement);
|
|
}
|
|
#endif
|
|
|
|
const SerializerElement & externalLayoutsElement = element.GetChild("externalLayouts", 0, "ExternalLayouts");
|
|
externalLayoutsElement.ConsiderAsArrayOf("externalLayout", "ExternalLayout");
|
|
for(std::size_t i = 0;i<externalLayoutsElement.GetChildrenCount();++i)
|
|
{
|
|
const SerializerElement & externalLayoutElement = externalLayoutsElement.GetChild(i);
|
|
|
|
std::shared_ptr<gd::ExternalLayout> newExternalLayout(new gd::ExternalLayout);
|
|
newExternalLayout->UnserializeFrom(externalLayoutElement);
|
|
externalLayouts.push_back(newExternalLayout);
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
const SerializerElement & externalSourceFilesElement = element.GetChild("externalSourceFiles", 0, "ExternalSourceFiles");
|
|
externalSourceFilesElement.ConsiderAsArrayOf("sourceFile", "SourceFile");
|
|
for(std::size_t i = 0;i<externalSourceFilesElement.GetChildrenCount();++i)
|
|
{
|
|
const SerializerElement & sourceFileElement = externalSourceFilesElement.GetChild(i);
|
|
|
|
std::shared_ptr<gd::SourceFile> newSourceFile(new gd::SourceFile);
|
|
newSourceFile->UnserializeFrom(sourceFileElement);
|
|
externalSourceFiles.push_back(newSourceFile);
|
|
}
|
|
|
|
#if !defined(GD_NO_WX_GUI)
|
|
if (!updateText.empty()) //TODO
|
|
{
|
|
ProjectUpdateDialog updateDialog(NULL, updateText);
|
|
updateDialog.ShowModal();
|
|
}
|
|
|
|
dirty = false;
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
#if !defined(EMSCRIPTEN)
|
|
bool Project::LoadFromFile(const gd::String & filename)
|
|
{
|
|
//Load the XML document structure
|
|
TiXmlDocument doc;
|
|
if ( !doc.LoadFile(filename.ToLocale().c_str()) )
|
|
{
|
|
gd::String errorTinyXmlDesc = doc.ErrorDesc();
|
|
gd::String error = _( "Error while loading :" ) + "\n" + errorTinyXmlDesc + "\n\n" +_("Make sure the file exists and that you have the right to open the file.");
|
|
|
|
gd::LogError( error );
|
|
return false;
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
SetProjectFile(filename);
|
|
dirty = false;
|
|
#endif
|
|
|
|
TiXmlHandle hdl( &doc );
|
|
gd::SerializerElement rootElement;
|
|
|
|
//COMPATIBILITY CODE WITH ANSI GDEVELOP ( <= 3.6.83 )
|
|
#if defined(GD_IDE_ONLY) && !defined(GD_NO_WX_GUI) //There should not be any problem with encoding in compiled games
|
|
//Get the declaration element
|
|
TiXmlDeclaration * declXmlElement = hdl.FirstChild().ToNode()->ToDeclaration();
|
|
if(strcmp(declXmlElement->Encoding(), "UTF-8") != 0)
|
|
{
|
|
std::cout << "This is a legacy GDevelop project, checking if it is already encoded in UTF8..." << std::endl;
|
|
|
|
//The document has not been converted for/saved by GDevelop UTF8, now, try to determine if the project
|
|
//was saved on Linux and is already in UTF8 or on Windows and still in the locale encoding.
|
|
bool isNotInUTF8 = false;
|
|
std::ifstream docStream;
|
|
docStream.open(filename.ToLocale(), ios::in);
|
|
|
|
while( !docStream.eof() )
|
|
{
|
|
std::string docLine;
|
|
std::getline(docStream, docLine);
|
|
|
|
if( !gd::String::FromUTF8(docLine).IsValid() )
|
|
{
|
|
//The file contains an invalid character,
|
|
//the file has been saved by the legacy ANSI Windows version of GDevelop
|
|
// -> stop reading the file and start converting from the locale to UTF8
|
|
isNotInUTF8 = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
docStream.close();
|
|
|
|
//If the file is not encoded in UTF8, encode it
|
|
if(isNotInUTF8)
|
|
{
|
|
std::cout << "The project file is not encoded in UTF8, conversion started... ";
|
|
|
|
//Create a temporary file
|
|
#if defined(WINDOWS)
|
|
//Convert using the current locale
|
|
wxString tmpFileName = wxFileName::CreateTempFileName("");
|
|
std::ofstream outStream;
|
|
docStream.open(filename.ToLocale(), ios::in);
|
|
|
|
outStream.open(tmpFileName, ios::out | ios::trunc);
|
|
|
|
while( !docStream.eof() )
|
|
{
|
|
std::string docLine;
|
|
std::string convLine;
|
|
|
|
std::getline(docStream, docLine);
|
|
sf::Utf8::fromAnsi(docLine.begin(), docLine.end(), std::back_inserter(convLine));
|
|
|
|
outStream << convLine << '\n';
|
|
}
|
|
|
|
outStream.close();
|
|
docStream.close();
|
|
|
|
#else
|
|
//Convert using iconv command tool
|
|
wxString tmpFileName = wxStandardPaths::Get().GetUserConfigDir() + "/gdevelop_converted_project";
|
|
gd::String iconvCall = gd::String("iconv -f LATIN1 -t UTF-8 \"") + filename.ToLocale() + "\" ";
|
|
#if defined(MACOS)
|
|
iconvCall += "> \"" + tmpFileName + "\"";
|
|
#else
|
|
iconvCall += "-o \"" + tmpFileName + "\"";
|
|
#endif
|
|
|
|
std::cout << "Executing " << iconvCall << std::endl;
|
|
system(iconvCall.c_str());
|
|
#endif
|
|
|
|
//Reload the converted file, forcing UTF8 encoding as the XML header is false (still written ISO-8859-1)
|
|
doc.LoadFile(std::string(tmpFileName).c_str(), TIXML_ENCODING_UTF8);
|
|
|
|
std::cout << "Finished." << std::endl;
|
|
gd::LogMessage(_("Your project has been converted to the new encoding used by GDevelop 4 (UTF8).\nYou can save it to apply the change but it will be incompatible with old GDevelop version."));
|
|
}
|
|
}
|
|
#endif
|
|
//END OF COMPATIBILITY CODE
|
|
|
|
//Load the root element
|
|
TiXmlElement * rootXmlElement = hdl.FirstChildElement("project").ToElement();
|
|
//Compatibility with GD <= 3.3
|
|
if (!rootXmlElement) rootXmlElement = hdl.FirstChildElement("Project").ToElement();
|
|
if (!rootXmlElement) rootXmlElement = hdl.FirstChildElement("Game").ToElement();
|
|
//End of compatibility code
|
|
gd::Serializer::FromXML(rootElement, rootXmlElement);
|
|
|
|
//Unserialize the whole project
|
|
UnserializeFrom(rootElement);
|
|
|
|
return true;
|
|
}
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
bool Project::LoadFromJSONFile(const gd::String & filename)
|
|
{
|
|
std::ifstream ifs(filename.ToLocale().c_str());
|
|
if (!ifs.is_open())
|
|
{
|
|
gd::String error = _( "Unable to open the file") + _("Make sure the file exists and that you have the right to open the file.");
|
|
gd::LogError( error );
|
|
return false;
|
|
}
|
|
|
|
SetProjectFile(filename);
|
|
dirty = false;
|
|
|
|
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
|
gd::SerializerElement rootElement = gd::Serializer::FromJSON(str);
|
|
UnserializeFrom(rootElement);
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
void Project::SerializeTo(SerializerElement & element) const
|
|
{
|
|
SerializerElement & versionElement = element.AddChild("gdVersion");
|
|
versionElement.SetAttribute("major", gd::VersionWrapper::Major() );
|
|
versionElement.SetAttribute("minor", gd::VersionWrapper::Minor() );
|
|
versionElement.SetAttribute("build", gd::VersionWrapper::Build() );
|
|
versionElement.SetAttribute("revision", gd::VersionWrapper::Revision() );
|
|
|
|
SerializerElement & propElement = element.AddChild("properties");
|
|
propElement.AddChild("name").SetValue(GetName());
|
|
propElement.AddChild("author").SetValue(GetAuthor());
|
|
propElement.AddChild("windowWidth").SetValue(GetMainWindowDefaultWidth());
|
|
propElement.AddChild("windowHeight").SetValue(GetMainWindowDefaultHeight());
|
|
propElement.AddChild("latestCompilationDirectory").SetValue(GetLastCompilationDirectory());
|
|
propElement.AddChild("maxFPS").SetValue(GetMaximumFPS());
|
|
propElement.AddChild("minFPS").SetValue(GetMinimumFPS());
|
|
propElement.AddChild("verticalSync").SetValue(IsVerticalSynchronizationEnabledByDefault());
|
|
propElement.SetAttribute("packageName", packageName);
|
|
propElement.SetAttribute("winExecutableFilename", winExecutableFilename);
|
|
propElement.SetAttribute("winExecutableIconFile", winExecutableIconFile);
|
|
propElement.SetAttribute("linuxExecutableFilename", linuxExecutableFilename);
|
|
propElement.SetAttribute("macExecutableFilename", macExecutableFilename);
|
|
propElement.SetAttribute("useExternalSourceFiles", useExternalSourceFiles);
|
|
|
|
SerializerElement & extensionsElement = propElement.AddChild("extensions");
|
|
extensionsElement.ConsiderAsArrayOf("extension");
|
|
for (std::size_t i =0;i<GetUsedExtensions().size();++i)
|
|
extensionsElement.AddChild("extension").SetAttribute("name", GetUsedExtensions()[i]);
|
|
|
|
SerializerElement & platformsElement = propElement.AddChild("platforms");
|
|
platformsElement.ConsiderAsArrayOf("platform");
|
|
for (std::size_t i =0;i<platforms.size();++i) {
|
|
if (platforms[i] == NULL) {
|
|
std::cout << "ERROR: The project has a platform which is NULL.";
|
|
continue;
|
|
}
|
|
|
|
platformsElement.AddChild("platform").SetAttribute("name", platforms[i]->GetName());
|
|
}
|
|
if (currentPlatform != NULL)
|
|
propElement.AddChild("currentPlatform").SetValue(currentPlatform->GetName());
|
|
else
|
|
std::cout << "ERROR: The project current platform is NULL.";
|
|
|
|
resourcesManager.SerializeTo(element.AddChild("resources"));
|
|
SerializeObjectsTo(element.AddChild("objects"));
|
|
ObjectGroup::SerializeTo(GetObjectGroups(), element.AddChild("objectsGroups"));
|
|
GetVariables().SerializeTo(element.AddChild("variables"));
|
|
|
|
element.SetAttribute("firstLayout", firstLayout);
|
|
gd::SerializerElement & layoutsElement = element.AddChild("layouts");
|
|
layoutsElement.ConsiderAsArrayOf("layout");
|
|
for ( std::size_t i = 0;i < GetLayoutsCount();i++ )
|
|
GetLayout(i).SerializeTo(layoutsElement.AddChild("layout"));
|
|
|
|
SerializerElement & externalEventsElement = element.AddChild("externalEvents");
|
|
externalEventsElement.ConsiderAsArrayOf("externalEvents");
|
|
for (std::size_t i =0;i<GetExternalEventsCount();++i)
|
|
GetExternalEvents(i).SerializeTo(externalEventsElement.AddChild("externalEvents"));
|
|
|
|
SerializerElement & externalLayoutsElement = element.AddChild("externalLayouts");
|
|
externalLayoutsElement.ConsiderAsArrayOf("externalLayout");
|
|
for (std::size_t i =0;i<externalLayouts.size();++i)
|
|
externalLayouts[i]->SerializeTo(externalLayoutsElement.AddChild("externalLayout"));
|
|
|
|
SerializerElement & externalSourceFilesElement = element.AddChild("externalSourceFiles");
|
|
externalSourceFilesElement.ConsiderAsArrayOf("sourceFile");
|
|
for (std::size_t i =0;i<externalSourceFiles.size();++i)
|
|
externalSourceFiles[i]->SerializeTo(externalSourceFilesElement.AddChild("sourceFile"));
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
dirty = false;
|
|
#endif
|
|
}
|
|
|
|
#if !defined(EMSCRIPTEN)
|
|
bool Project::SaveToFile(const gd::String & filename)
|
|
{
|
|
//Serialize the whole project
|
|
gd::SerializerElement rootElement;
|
|
SerializeTo(rootElement);
|
|
|
|
//Create the XML document structure...
|
|
TiXmlDocument doc;
|
|
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" );
|
|
doc.LinkEndChild( decl );
|
|
|
|
TiXmlElement * root = new TiXmlElement( "project" );
|
|
doc.LinkEndChild( root );
|
|
gd::Serializer::ToXML(rootElement, root); //...and put the serialized project in it.
|
|
|
|
//Write XML to file
|
|
if ( !doc.SaveFile( filename.ToLocale().c_str() ) )
|
|
{
|
|
gd::LogError( _( "Unable to save file ") + filename + _("!\nCheck that the drive has enough free space, is not write-protected and that you have read/write permissions." ) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Project::SaveToJSONFile(const gd::String & filename)
|
|
{
|
|
//Serialize the whole project
|
|
gd::SerializerElement rootElement;
|
|
SerializeTo(rootElement);
|
|
|
|
//Write JSON to file
|
|
std::string str = gd::Serializer::ToJSON(rootElement);
|
|
ofstream ofs(filename.ToLocale().c_str());
|
|
if (!ofs.is_open())
|
|
{
|
|
gd::LogError( _( "Unable to save file ")+ filename + _("!\nCheck that the drive has enough free space, is not write-protected and that you have read/write permissions." ) );
|
|
return false;
|
|
}
|
|
|
|
ofs << str;
|
|
ofs.close();
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
bool Project::ValidateObjectName(const gd::String & name)
|
|
{
|
|
gd::String allowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
|
return !(name.find_first_not_of(allowedCharacters) != gd::String::npos);
|
|
}
|
|
|
|
gd::String Project::GetBadObjectNameWarning()
|
|
{
|
|
return _("Please use only letters, digits\nand underscores ( _ ).");
|
|
}
|
|
|
|
void Project::ExposeResources(gd::ArbitraryResourceWorker & worker)
|
|
{
|
|
//Add project resources
|
|
std::vector<gd::String> resources = GetResourcesManager().GetAllResourcesList();
|
|
for ( std::size_t i = 0;i < resources.size() ;i++ )
|
|
{
|
|
if ( GetResourcesManager().GetResource(resources[i]).UseFile() )
|
|
worker.ExposeResource(GetResourcesManager().GetResource(resources[i]));
|
|
}
|
|
#if !defined(GD_NO_WX_GUI)
|
|
gd::SafeYield::Do();
|
|
#endif
|
|
|
|
//Add layouts resources
|
|
for ( std::size_t s = 0;s < GetLayoutsCount();s++ )
|
|
{
|
|
for (std::size_t j = 0;j<GetLayout(s).GetObjectsCount();++j) //Add objects resources
|
|
GetLayout(s).GetObject(j).ExposeResources(worker);
|
|
|
|
LaunchResourceWorkerOnEvents(*this, GetLayout(s).GetEvents(), worker);
|
|
}
|
|
//Add external events resources
|
|
for ( std::size_t s = 0;s < GetExternalEventsCount();s++ )
|
|
{
|
|
LaunchResourceWorkerOnEvents(*this, GetExternalEvents(s).GetEvents(), worker);
|
|
}
|
|
#if !defined(GD_NO_WX_GUI)
|
|
gd::SafeYield::Do();
|
|
#endif
|
|
|
|
//Add global objects resources
|
|
for (std::size_t j = 0;j<GetObjectsCount();++j) {
|
|
GetObject(j).ExposeResources(worker);
|
|
}
|
|
|
|
#if !defined(GD_NO_WX_GUI)
|
|
gd::SafeYield::Do();
|
|
#endif
|
|
}
|
|
|
|
bool Project::HasSourceFile(gd::String name, gd::String language) const
|
|
{
|
|
vector< std::shared_ptr<SourceFile> >::const_iterator sourceFile =
|
|
find_if(externalSourceFiles.begin(), externalSourceFiles.end(),
|
|
bind2nd(gd::ExternalSourceFileHasName(), name));
|
|
|
|
if (sourceFile == externalSourceFiles.end())
|
|
return false;
|
|
|
|
return language.empty() || (*sourceFile)->GetLanguage() == language;
|
|
}
|
|
|
|
gd::SourceFile & Project::GetSourceFile(const gd::String & name)
|
|
{
|
|
return *(*find_if(externalSourceFiles.begin(), externalSourceFiles.end(), bind2nd(gd::ExternalSourceFileHasName(), name)));
|
|
}
|
|
|
|
const gd::SourceFile & Project::GetSourceFile(const gd::String & name) const
|
|
{
|
|
return *(*find_if(externalSourceFiles.begin(), externalSourceFiles.end(), bind2nd(gd::ExternalSourceFileHasName(), name)));
|
|
}
|
|
|
|
void Project::RemoveSourceFile(const gd::String & name)
|
|
{
|
|
std::vector< std::shared_ptr<gd::SourceFile> >::iterator sourceFile =
|
|
find_if(externalSourceFiles.begin(), externalSourceFiles.end(), bind2nd(gd::ExternalSourceFileHasName(), name));
|
|
if ( sourceFile == externalSourceFiles.end() ) return;
|
|
|
|
externalSourceFiles.erase(sourceFile);
|
|
}
|
|
|
|
gd::SourceFile & Project::InsertNewSourceFile(const gd::String & name, const gd::String & language, std::size_t position)
|
|
{
|
|
if (HasSourceFile(name, language))
|
|
return GetSourceFile(name);
|
|
|
|
std::shared_ptr<SourceFile> newSourceFile(new SourceFile);
|
|
newSourceFile->SetLanguage(language);
|
|
newSourceFile->SetFileName(name);
|
|
|
|
if (position<externalSourceFiles.size())
|
|
externalSourceFiles.insert(externalSourceFiles.begin()+position, newSourceFile);
|
|
else
|
|
externalSourceFiles.push_back(newSourceFile);
|
|
|
|
return *newSourceFile;
|
|
}
|
|
|
|
#if !defined(GD_NO_WX_GUI)
|
|
void Project::PopulatePropertyGrid(wxPropertyGrid * grid)
|
|
{
|
|
grid->Append( new wxPropertyCategory(_("Properties")) );
|
|
grid->Append( new wxStringProperty(_("Name of the project"), wxPG_LABEL, GetName()) );
|
|
grid->Append( new wxStringProperty(_("Package name"), wxPG_LABEL, GetPackageName()) );
|
|
grid->Append( new wxStringProperty(_("Author"), wxPG_LABEL, GetAuthor()) );
|
|
grid->Append( new wxStringProperty(_("Globals variables"), wxPG_LABEL, _("Click to edit...")) );
|
|
grid->Append( new wxStringProperty(_("Extensions"), wxPG_LABEL, _("Click to edit...")) );
|
|
grid->Append( new wxPropertyCategory(_("Window")) );
|
|
grid->Append( new wxUIntProperty(_("Width"), wxPG_LABEL, GetMainWindowDefaultWidth()) );
|
|
grid->Append( new wxUIntProperty(_("Height"), wxPG_LABEL, GetMainWindowDefaultHeight()) );
|
|
grid->Append( new wxBoolProperty(_("Vertical Synchronization"), wxPG_LABEL, IsVerticalSynchronizationEnabledByDefault()) );
|
|
grid->Append( new wxBoolProperty(_("Limit the framerate"), wxPG_LABEL, GetMaximumFPS() != -1) );
|
|
grid->Append( new wxIntProperty(_("Maximum FPS"), wxPG_LABEL, GetMaximumFPS()) );
|
|
grid->Append( new wxUIntProperty(_("Minimum FPS"), wxPG_LABEL, GetMinimumFPS()) );
|
|
|
|
grid->SetPropertyCell(wxString(_("Globals variables")), 1, _("Click to edit..."), wxNullBitmap, wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT ));
|
|
grid->SetPropertyReadOnly(wxString(_("Globals variables")));
|
|
grid->SetPropertyCell(wxString(_("Extensions")), 1, _("Click to edit..."), wxNullBitmap, wxSystemSettings::GetColour(wxSYS_COLOUR_HOTLIGHT ));
|
|
grid->SetPropertyReadOnly(wxString(_("Extensions")));
|
|
|
|
if ( GetMaximumFPS() == -1 )
|
|
{
|
|
grid->GetProperty(_("Maximum FPS"))->Enable(false);
|
|
grid->GetProperty(_("Maximum FPS"))->SetValue("");
|
|
}
|
|
else
|
|
grid->GetProperty(_("Maximum FPS"))->Enable(true);
|
|
|
|
grid->Append( new wxPropertyCategory(_("Generation")) );
|
|
grid->Append( new wxStringProperty(_("Windows executable name"), wxPG_LABEL, winExecutableFilename) );
|
|
grid->Append( new wxImageFileProperty(_("Windows executable icon"), wxPG_LABEL, winExecutableIconFile) );
|
|
grid->Append( new wxStringProperty(_("Linux executable name"), wxPG_LABEL, linuxExecutableFilename) );
|
|
grid->Append( new wxStringProperty(_("Mac OS executable name"), wxPG_LABEL, macExecutableFilename) );
|
|
|
|
grid->Append( new wxPropertyCategory(_("C++ features")) );
|
|
grid->Append( new wxBoolProperty(_("Activate the use of C++/JS source files"), wxPG_LABEL, useExternalSourceFiles) );
|
|
}
|
|
|
|
void Project::UpdateFromPropertyGrid(wxPropertyGrid * grid)
|
|
{
|
|
if ( grid->GetProperty(_("Name of the project")) != NULL)
|
|
SetName(grid->GetProperty(_("Name of the project"))->GetValueAsString());
|
|
if ( grid->GetProperty(_("Author")) != NULL)
|
|
SetAuthor(grid->GetProperty(_("Author"))->GetValueAsString());
|
|
if ( grid->GetProperty(_("Package name")) != NULL)
|
|
SetPackageName(grid->GetProperty(_("Package name"))->GetValueAsString());
|
|
if ( grid->GetProperty(_("Width")) != NULL)
|
|
SetDefaultWidth(grid->GetProperty(_("Width"))->GetValue().GetInteger());
|
|
if ( grid->GetProperty(_("Height")) != NULL)
|
|
SetDefaultHeight(grid->GetProperty(_("Height"))->GetValue().GetInteger());
|
|
if ( grid->GetProperty(_("Vertical Synchronization")) != NULL)
|
|
SetVerticalSyncActivatedByDefault(grid->GetProperty(_("Vertical Synchronization"))->GetValue().GetBool());
|
|
if ( grid->GetProperty(_("Limit the framerate")) != NULL && !grid->GetProperty(_("Limit the framerate"))->GetValue().GetBool())
|
|
SetMaximumFPS(-1);
|
|
else if ( grid->GetProperty(_("Maximum FPS")) != NULL)
|
|
SetMaximumFPS(grid->GetProperty(_("Maximum FPS"))->GetValue().GetInteger());
|
|
if ( grid->GetProperty(_("Minimum FPS")) != NULL)
|
|
SetMinimumFPS(grid->GetProperty(_("Minimum FPS"))->GetValue().GetInteger());
|
|
|
|
if ( grid->GetProperty(_("Windows executable name")) != NULL)
|
|
winExecutableFilename = grid->GetProperty(_("Windows executable name"))->GetValueAsString();
|
|
if ( grid->GetProperty(_("Windows executable icon")) != NULL)
|
|
winExecutableIconFile = grid->GetProperty(_("Windows executable icon"))->GetValueAsString();
|
|
if ( grid->GetProperty(_("Linux executable name")) != NULL)
|
|
linuxExecutableFilename = grid->GetProperty(_("Linux executable name"))->GetValueAsString();
|
|
if ( grid->GetProperty(_("Mac OS executable name")) != NULL)
|
|
macExecutableFilename = grid->GetProperty(_("Mac OS executable name"))->GetValueAsString();
|
|
if ( grid->GetProperty(_("Activate the use of C++/JS source files")) != NULL)
|
|
useExternalSourceFiles =grid->GetProperty(_("Activate the use of C++/JS source files"))->GetValue().GetBool();
|
|
}
|
|
|
|
void Project::OnChangeInPropertyGrid(wxPropertyGrid * grid, wxPropertyGridEvent & event)
|
|
{
|
|
if (event.GetPropertyName() == _("Limit the framerate") )
|
|
grid->EnableProperty(wxString(_("Maximum FPS")), grid->GetProperty(_("Limit the framerate"))->GetValue().GetBool());
|
|
|
|
UpdateFromPropertyGrid(grid);
|
|
}
|
|
|
|
void Project::OnSelectionInPropertyGrid(wxPropertyGrid * grid, wxPropertyGridEvent & event)
|
|
{
|
|
if ( event.GetColumn() == 1) //Manage button-like properties
|
|
{
|
|
if ( event.GetPropertyName() == _("Extensions") )
|
|
{
|
|
gd::ProjectExtensionsDialog dialog(NULL, *this);
|
|
dialog.ShowModal();
|
|
}
|
|
else if ( event.GetPropertyName() == _("Globals variables") )
|
|
{
|
|
gd::ChooseVariableDialog dialog(NULL, GetVariables(), /*editingOnly=*/true);
|
|
dialog.SetAssociatedProject(this);
|
|
dialog.ShowModal();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
Project::Project(const Project & other)
|
|
{
|
|
Init(other);
|
|
}
|
|
|
|
Project& Project::operator=(const Project & other)
|
|
{
|
|
if ( this != &other )
|
|
Init(other);
|
|
|
|
return *this;
|
|
}
|
|
|
|
void Project::Init(const gd::Project & game)
|
|
{
|
|
//Some properties
|
|
name = game.name;
|
|
windowWidth = game.windowWidth;
|
|
windowHeight = game.windowHeight;
|
|
maxFPS = game.maxFPS;
|
|
minFPS = game.minFPS;
|
|
verticalSync = game.verticalSync;
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
author = game.author;
|
|
packageName = game.packageName;
|
|
latestCompilationDirectory = game.latestCompilationDirectory;
|
|
objectGroups = game.objectGroups;
|
|
|
|
GDMajorVersion = game.GDMajorVersion;
|
|
GDMinorVersion = game.GDMinorVersion;
|
|
|
|
currentPlatform = game.currentPlatform;
|
|
#endif
|
|
extensionsUsed = game.extensionsUsed;
|
|
platforms = game.platforms;
|
|
|
|
//Resources
|
|
resourcesManager = game.resourcesManager;
|
|
imageManager = std::shared_ptr<ImageManager>(new ImageManager(*game.imageManager));
|
|
imageManager->SetGame(this);
|
|
|
|
GetObjects().clear();
|
|
for (std::size_t i =0;i<game.GetObjects().size();++i)
|
|
GetObjects().push_back( std::shared_ptr<gd::Object>(game.GetObjects()[i]->Clone()) );
|
|
|
|
scenes.clear();
|
|
for (std::size_t i =0;i<game.scenes.size();++i)
|
|
scenes.push_back( std::shared_ptr<gd::Layout>(new gd::Layout(*game.scenes[i])) );
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
externalEvents.clear();
|
|
for (std::size_t i =0;i<game.externalEvents.size();++i)
|
|
externalEvents.push_back( std::shared_ptr<gd::ExternalEvents>(new gd::ExternalEvents(*game.externalEvents[i])) );
|
|
#endif
|
|
|
|
externalLayouts.clear();
|
|
for (std::size_t i =0;i<game.externalLayouts.size();++i)
|
|
externalLayouts.push_back( std::shared_ptr<gd::ExternalLayout>(new gd::ExternalLayout(*game.externalLayouts[i])) );
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
useExternalSourceFiles = game.useExternalSourceFiles;
|
|
|
|
externalSourceFiles.clear();
|
|
for (std::size_t i =0;i<game.externalSourceFiles.size();++i)
|
|
externalSourceFiles.push_back( std::shared_ptr<gd::SourceFile>(new gd::SourceFile(*game.externalSourceFiles[i])) );
|
|
#endif
|
|
|
|
variables = game.GetVariables();
|
|
|
|
#if defined(GD_IDE_ONLY)
|
|
gameFile = game.GetProjectFile();
|
|
imagesChanged = game.imagesChanged;
|
|
|
|
winExecutableFilename = game.winExecutableFilename;
|
|
winExecutableIconFile = game.winExecutableIconFile;
|
|
linuxExecutableFilename = game.linuxExecutableFilename;
|
|
macExecutableFilename = game.macExecutableFilename;
|
|
#endif
|
|
}
|
|
|
|
}
|