Skip to content

Commit

Permalink
Merge pull request Revolutionary-Games#168 from Revolutionary-Games/1…
Browse files Browse the repository at this point in the history
…31-savable-creatures

Added Microbe saving/loading in editor.
Uses existing serialization to read/write foo.microbe files in creations/microbe.
Uses new version file to record save versions, in case of backwards-compatibility issues.
  • Loading branch information
Moopli committed Jul 5, 2014
2 parents ba903ed + b77797d commit fedab0c
Show file tree
Hide file tree
Showing 15 changed files with 527 additions and 13 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,9 @@ nbproject/
# Vim swap files
*.swp


# Version file

!thriveversion.ver
# Temporary/backup files
*~
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@ install(EXPORT lua
DESTINATION bin
)

# Version file

install(FILES
${CMAKE_SOURCE_DIR}/thriveversion.ver
DESTINATION bin
)

# OGRE config and media

install(FILES
Expand Down
13 changes: 13 additions & 0 deletions scripts/microbe_editor/microbe_editor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ function MicrobeEditor:addNucleus()
self.currentMicrobe:addOrganelle(0, 0, nucleusOrganelle)
end

function MicrobeEditor:loadMicrobe(entityId)
self.organelleCount = 0
if self.currentMicrobe ~= nil then
self.currentMicrobe.entity:destroy()
end
self.currentMicrobe = Microbe(Entity(entityId))
self.currentMicrobe.entity:stealName("working_microbe")
self.currentMicrobe.sceneNode.transform.orientation = Quaternion(Radian(Degree(180)), Vector3(0, 0, 1))-- Orientation
self.currentMicrobe.sceneNode.transform:touch()
self.currentMicrobe.collisionHandler:addCollisionGroup("powerupable")
Engine:playerData():setActiveCreature(entityId)
end

function MicrobeEditor:createNewMicrobe()
self.organelleCount = 0
if self.currentMicrobe ~= nil then
Expand Down
72 changes: 67 additions & 5 deletions scripts/microbe_editor/microbe_editor_hud.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ function MicrobeEditorHudSystem:__init()
self.initialized = false
self.editor = MicrobeEditor(self)
self.hoverHex = nil
self.saveLoadPanel = nil
self.creationsListbox = nil
self.creationFileMap = {} -- Map from player creation name to filepath
self.activeButton = nil -- stores button, not name
end

Expand Down Expand Up @@ -43,16 +46,23 @@ function MicrobeEditorHudSystem:init(gameState)
--aminoSynthesizerButton:getChild("AminoSynthesizer"):registerEventHandler("Clicked", aminoSynthesizerClicked)
removeButton:getChild("Remove"):registerEventHandler("Clicked", removeClicked)


self.saveLoadPanel = root:getChild("SaveLoadPanel")
self.creationsListbox = self.saveLoadPanel:getChild("SavedCreations")

root:getChild("BottomSection"):getChild("MicrobeStageButton"):registerEventHandler("Clicked", playClicked)
root:getChild("BottomSection"):getChild("MenuButton"):registerEventHandler("Clicked", menuButtonClicked)

root:getChild("MenuPanel"):getChild("MainMenuButton"):registerEventHandler("Clicked", menuMainMenuClicked)
root:getChild("MenuPanel"):getChild("PlayButton"):registerEventHandler("Clicked", menuPlayClicked)
root:getChild("MenuPanel"):getChild("ReturnButton"):registerEventHandler("Clicked", returnButtonClicked)
root:getChild("MenuPanel"):getChild("QuitButton"):registerEventHandler("Clicked", quitButtonClicked)
root:getChild("BottomSection"):getChild("SaveButton"):registerEventHandler("Clicked", rootSaveCreationClicked)
root:getChild("BottomSection"):getChild("LoadButton"):registerEventHandler("Clicked", rootLoadCreationClicked)
root:getChild("SaveLoadPanel"):getChild("ReturnButton"):registerEventHandler("Clicked", returnButtonClicked)
root:getChild("SaveLoadPanel"):getChild("SaveButton"):registerEventHandler("Clicked", saveCreationClicked)
root:getChild("SaveLoadPanel"):getChild("LoadButton"):registerEventHandler("Clicked", loadCreationClicked)
end


function MicrobeEditorHudSystem:activate()
global_activeMicrobeEditorHudSystem = self -- Global reference for event handlers
self.editor:activate()
Expand All @@ -62,8 +72,7 @@ function MicrobeEditorHudSystem:activate()
else
button:enable()
end
end

end
end

function MicrobeEditorHudSystem:setActiveAction(actionName)
Expand All @@ -77,7 +86,7 @@ end

function MicrobeEditorHudSystem:update(milliseconds)
self.editor:update(milliseconds)
-- Render the hex under the cursor
-- Render the hex under the cursor
local x, y = axialToCartesian(self.editor:getMouseHex())
local translation = Vector3(-x, -y, 0)
local sceneNode = self.hoverHex:getComponent(OgreSceneNodeComponent.TYPE_ID)
Expand Down Expand Up @@ -195,6 +204,59 @@ function removeClicked()
global_activeMicrobeEditorHudSystem:setActiveAction("remove")
end

function rootSaveCreationClicked()
panel = global_activeMicrobeEditorHudSystem.saveLoadPanel
panel:getChild("SaveButton"):show()
panel:getChild("NameTextbox"):show()
panel:getChild("CreationNameDialogLabel"):show()
panel:getChild("LoadButton"):hide()
panel:getChild("SavedCreations"):hide()
panel:show()
end

function rootLoadCreationClicked()
panel = global_activeMicrobeEditorHudSystem.saveLoadPanel
panel:getChild("SaveButton"):hide()
panel:getChild("NameTextbox"):hide()
panel:getChild("CreationNameDialogLabel"):hide()
panel:getChild("LoadButton"):show()
panel:getChild("SavedCreations"):show()
panel:show()
global_activeMicrobeEditorHudSystem.creationsListbox:itemListboxResetList()
global_activeMicrobeEditorHudSystem.creationFileMap = {}
i = 0
pathsString = Engine:getCreationFileList("microbe")
-- using pattern matching for splitting on spaces
for path in string.gmatch(pathsString, "%S+") do
item = CEGUIWindow("Thrive/ListboxItem", "creationItems"..i)
pathSep = package.config:sub(1,1) -- / for unix, \ for windows
text = string.sub(path, string.len(path) - string.find(path:reverse(), pathSep) + 2)
item:setText(text)
global_activeMicrobeEditorHudSystem.creationsListbox:itemListboxAddItem(item)
global_activeMicrobeEditorHudSystem.creationFileMap[text] = path
i = i + 1
end
global_activeMicrobeEditorHudSystem.creationsListbox:itemListboxHandleUpdatedItemData()
end

function saveCreationClicked()
name = panel:getChild("NameTextbox"):getText()
-- Todo: Additional input sanitation
if string.len(name) > 0 then
Engine:saveCreation(global_activeMicrobeEditorHudSystem.editor.currentMicrobe.entity.id, name, "microbe")
panel:hide()
end
end

function loadCreationClicked()
item = global_activeMicrobeEditorHudSystem.creationsListbox:itemListboxGetLastSelectedItem()
if not item:isNull() then
entity = Engine:loadCreation(global_activeMicrobeEditorHudSystem.creationFileMap[item:getText()])
global_activeMicrobeEditorHudSystem.editor:loadMicrobe(entity)
panel:hide()
end
end

function playClicked()
Engine:setCurrentGameState(GameState.MICROBE)
end
Expand Down
2 changes: 2 additions & 0 deletions scripts/microbe_stage/microbe_stage_hud.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ function returnButtonClicked()
if Engine:currentGameState():name() == "microbe" then
Engine:currentGameState():rootGUIWindow():getChild("HelpPanel"):hide()
Engine:currentGameState():rootGUIWindow():getChild("MessagePanel"):hide()
elseif Engine:currentGameState():name() == "microbe_editor" then
Engine:currentGameState():rootGUIWindow():getChild("SaveLoadPanel"):hide()
end
end

Expand Down
116 changes: 115 additions & 1 deletion src/engine/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
#include "ogre/text_overlay.h"

// Scripting
#include <luabind/iterator_policy.hpp>
#include "scripting/luabind.h"
#include "scripting/lua_state.h"
#include "scripting/script_initializer.h"


// Microbe
#include "microbe_stage/compound.h"

Expand Down Expand Up @@ -241,6 +241,7 @@ struct Engine::Implementation : public Ogre::WindowEventListener {
}
savegame.set("gameStates", std::move(gameStates));
savegame.set("playerData", m_playerData.storage());
savegame.set("thriveversion", m_thriveVersion);
std::ofstream stream(
m_serialization.saveFile,
std::ofstream::trunc | std::ofstream::binary
Expand Down Expand Up @@ -361,6 +362,18 @@ struct Engine::Implementation : public Ogre::WindowEventListener {
);
}

void
loadVersionNumber() {
std::ifstream versionFile ("thriveversion.ver");
if (versionFile.is_open()) {
std::getline(versionFile, m_thriveVersion);
}
else {
m_thriveVersion = "unknown";
}
versionFile.close();
}

void
shutdownInputManager() {
if (not m_input.inputManager) {
Expand Down Expand Up @@ -439,6 +452,8 @@ struct Engine::Implementation : public Ogre::WindowEventListener {

GameState* m_nextGameState = nullptr;

std::string m_thriveVersion;

struct Serialization {

std::string loadFile;
Expand Down Expand Up @@ -493,9 +508,13 @@ Engine::luaBindings() {
.def("playerData", &Engine::playerData)
.def("load", &Engine::load)
.def("save", &Engine::save)
.def("saveCreation", static_cast<void(Engine::*)(EntityId, std::string, std::string)const>(&Engine::saveCreation))
.def("loadCreation", static_cast<EntityId(Engine::*)(std::string)>(&Engine::loadCreation))
.def("getCreationFileList", &Engine::getCreationFileList)
.def("quit", &Engine::quit)
.def("timedSystemShutdown", &Engine::timedSystemShutdown)
.def("isSystemTimedShutdown", &Engine::isSystemTimedShutdown)
.def("thriveVersion", &Engine::thriveVersion)
.property("componentFactory", &Engine::componentFactory)
.property("keyboard", &Engine::keyboard)
.property("mouse", &Engine::mouse)
Expand Down Expand Up @@ -577,6 +596,7 @@ Engine::init() {
m_impl->setupInputManager();
m_impl->setupGUI();
m_impl->loadScripts("../scripts");
m_impl->loadVersionNumber();
GameState* previousGameState = m_impl->m_currentGameState;
for (const auto& pair : m_impl->m_gameStates) {
const auto& gameState = pair.second;
Expand Down Expand Up @@ -641,6 +661,94 @@ Engine::save(
m_impl->m_serialization.saveFile = filename;
}

void
Engine::saveCreation(
EntityId entityId,
std::string name,
std::string type
) const {
saveCreation(entityId, this->currentGameState()->entityManager(), name, type);
}

void
Engine::saveCreation(
EntityId entityId,
const EntityManager& entityManager,
std::string name,
std::string type
) const {
namespace fs = boost::filesystem;
StorageContainer creation = entityManager.storeEntity(entityId);
creation.set("thriveversion", this->thriveVersion());
std::ofstream stream(
(fs::path("creations") / fs::path(type) / fs::path(name + "." + type)).string<std::string>(),
std::ofstream::trunc | std::ofstream::binary
);
stream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
if (stream) {
try {
stream << creation;
stream.flush();
stream.close();
}
catch (const std::ofstream::failure& e) {
std::cerr << "Error saving file: " << e.what() << std::endl;
throw;
}
}
else {
std::perror("Could not open file for saving");
}
}

EntityId
Engine::loadCreation(
std::string file
) {
return loadCreation(file, this->currentGameState()->entityManager());
}

EntityId
Engine::loadCreation(
std::string file,
EntityManager& entityManager
) {
std::ifstream stream(
file,
std::ifstream::binary
);
stream.clear();
stream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
StorageContainer creation;
try {
stream >> creation;
}
catch(const std::ofstream::failure& e) {
std::cerr << "Error loading file: " << e.what() << std::endl;
throw;
}
EntityId entityId = entityManager.loadEntity(creation, m_impl->m_componentFactory);
return entityId;
}

std::string
Engine::getCreationFileList(
std::string stage
) const {
namespace fs = boost::filesystem;
fs::path directory("./creations/" + stage);
fs::directory_iterator end_iter;
std::stringstream stringbuilder;
if ( fs::exists(directory) && fs::is_directory(directory)) {
for( fs::directory_iterator dir_iter(directory) ; dir_iter != end_iter ; ++dir_iter) {
if (fs::is_regular_file(dir_iter->status()) )
{
stringbuilder << dir_iter->path().string() << " ";
}
}
}
return stringbuilder.str();
}

void
Engine::setCurrentGameState(
Expand Down Expand Up @@ -758,3 +866,9 @@ Engine::isSystemTimedShutdown(
) const {
return m_impl->m_prevShutdownSystems->find(&system) != m_impl->m_prevShutdownSystems->end();
}

const std::string&
Engine::thriveVersion() const {
return m_impl->m_thriveVersion;
}

Loading

0 comments on commit fedab0c

Please sign in to comment.