Updated VN Scene Parse Tool

This commit is contained in:
2023-02-09 21:42:30 -08:00
parent 399180c2ca
commit 9436b7e98f
18 changed files with 387 additions and 236 deletions

View File

@ -4,9 +4,9 @@
# https://opensource.org/licenses/MIT
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 20)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")

View File

@ -5,6 +5,7 @@
#pragma once
#include "dawnsharedlibs.hpp"
#include "assert/assert.hpp"
#include "util/array.hpp"
namespace Dawn {

View File

@ -32,4 +32,7 @@ target_compile_definitions(vnscenegen
target_link_libraries(vnscenegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)
)
# Subdirs
add_subdirectory(parse)

View File

@ -7,191 +7,6 @@
using namespace Dawn;
int32_t parseInclude(struct HeaderInformation *info, xml_t *node) {
auto attrPath = xmlGetAttributeByName(node, "path");
if(attrPath == -1) {
std::cout << "Missing include path in VN Header Defintions." << std::endl;
return 1;
}
info->includes.push_back(node->attributeDatas[attrPath]);
return 0;
}
int32_t parseCharacter(struct HeaderInformation *info, xml_t *node) {
auto attrClass = xmlGetAttributeByName(node, "class");
if(attrClass == -1) {
std::cout << "Character definition is missing class" << std::endl;
return 1;
}
auto attrName = xmlGetAttributeByName(node, "name");
if(attrName == -1) {
std::cout << "Character definition is missing name" << std::endl;
}
struct CharacterInformation character;
character.clazz = std::string(node->attributeDatas[attrClass]);
character.name = std::string(node->attributeDatas[attrName]);
info->characters.push_back(character);
return 0;
}
int32_t parseScene(struct HeaderInformation *info, xml_t *node) {
auto attrName = xmlGetAttributeByName(node, "name");
if(attrName == -1) {
std::cout << "VN Scene <scene> definition is missing name attribute" << std::endl;
return 1;
}
info->name = std::string(node->attributeDatas[attrName]);
auto attrType = xmlGetAttributeByName(node, "type");
if(attrType == -1) {
info->type = "SimpleVNScene";
} else {
info->type = std::string(node->attributeDatas[attrType]);
}
return 0;
}
int32_t parseAsset(struct HeaderInformation *info, xml_t *node) {
auto attrType = xmlGetAttributeByName(node, "type");
if(attrType == -1) {
std::cout << "VN Scene Asset missing type attribute" << std::endl;
return 1;
}
auto attrName = xmlGetAttributeByName(node, "name");
if(attrName == -1) {
std::cout << "VN Scene Asset missing name attribute" << std::endl;
return 1;
}
struct Asset ass;
ass.type = std::string(node->attributeDatas[attrType]);
ass.name = std::string(node->attributeDatas[attrName]);
info->assets.push_back(ass);
return 0;
}
int32_t parseHeader(struct HeaderInformation *info, xml_t *node) {
for(int32_t i = 0; i < node->childrenCount; i++) {
auto c = node->children + i;
auto n = std::string(c->node);
int32_t ret = 0;
std::cout << n << std::endl;
if(n == "include") {
ret = parseInclude(info, c);
} else if(n == "character") {
ret = parseCharacter(info, c);
} else if(n == "scene") {
ret = parseScene(info, c);
} else if (n == "asset") {
ret = parseAsset(info, c);
} else {
std::cout << "Parsing VN Scene header, unknown node " << n << std::endl;
}
if(ret != 0) return ret;
}
return 0;
}
std::string parseEase(std::string e) {
if(e == "out-quad") return "easeOutQuad";
std::cout << "Invalid ease defined" << std::endl;
return "";
}
std::string parseEvent(xml_t *evt, struct HeaderInformation *header) {
std::string buffer;
std::string node(evt->node);
if(node == "pause") {
header->includes.push_back("visualnovel/events/timing/VisualNovelPauseEvent.hpp");
auto attrDuration = xmlGetAttributeByName(evt, "duration");
if(attrDuration == -1) {
std::cout << "Pause event is missing duration argument." << std::endl;
return "";
}
auto dur = std::string(evt->attributeDatas[attrDuration]);
if(dur.find('.') == std::string::npos) dur += ".0";
buffer += "new VisualNovelPauseEvent(vnManager, " + dur + "f)";
} else if(node == "text") {
header->includes.push_back("visualnovel/events/VisualNovelTextboxEvent.hpp");
auto attrChar = xmlGetAttributeByName(evt, "character");
if(attrChar == -1) {
std::cout << "Text event missing character attribute." << std::endl;
return "";
}
auto attrEmotion = xmlGetAttributeByName(evt, "emotion");
if(attrEmotion == -1) {
std::cout << "Text event missing emotion attribute." << std::endl;
return "";
}
auto attrString = xmlGetAttributeByName(evt, "string");
if(attrString == -1) {
std::cout << "Text event missing string attribute." << std::endl;
return "";
}
std::string charName(evt->attributeDatas[attrChar]);
std::string emo(evt->attributeDatas[attrEmotion]);
emo[0] = toupper(emo[0]);
buffer += "new VisualNovelTextboxEvent(vnManager, ";
buffer += "this->" + charName + "->vnCharacter, ";
buffer += "this->" + charName + "->emotion" + emo + ", ";
buffer += "\"" + std::string(evt->attributeDatas[attrString]) + "\"" ;
buffer += ")";
} else if(node == "character-fade") {
header->includes.push_back("visualnovel/events/characters/VisualNovelFadeCharacterEvent.hpp");
auto attrChar = xmlGetAttributeByName(evt, "character");
auto attrDuration = xmlGetAttributeByName(evt, "duration");
auto attrEase = xmlGetAttributeByName(evt, "ease");
auto attrFade = xmlGetAttributeByName(evt, "fade");
if(attrChar == -1) {
std::cout << "Character fade event missing character attribute." << std::endl;
return "";
}
std::string character = std::string(evt->attributeDatas[attrChar]);
std::string easeIn = "true";
std::string ease = "easeLinear";
std::string duration = "1.0";
if(attrFade != -1) easeIn = std::string(evt->attributeDatas[attrFade]) == "in" ? "true" : "false";
if(attrDuration != -1) duration = std::string(evt->attributeDatas[attrDuration]);
if(duration.find('.') == std::string::npos) duration += ".0";
if(attrEase != -1) {
ease = parseEase(std::string(evt->attributeDatas[attrEase]));
if(ease.size() == 0) return "";
}
buffer += "new VisualNovelFadeCharacterEvent(vnManager, ";
buffer += "this->" + character + "->vnCharacter, ";
buffer += easeIn + ", ";
buffer += "&" + ease + ", ";
buffer += duration + "f";
buffer += ")";
} else if(node == "scene-transition") {
buffer += " ";
}
return buffer;
}
int32_t VnSceneGen::start() {
if(this->args.size() != 3) {
std::cout << "Invalid number of args passed to VNScene Generator" << std::endl;
@ -207,42 +22,52 @@ int32_t VnSceneGen::start() {
}
// Parse XML
xml_t xml;
xmlLoad(&xml, (char*)buffer.c_str());
Xml xml = Xml::load(buffer);
// First, read the header information
struct HeaderInformation header;
for(int32_t i = 0; i < xml.childrenCount; i++) {
auto child = xml.children + i;
if(std::string(child->node) != "head") continue;
auto ret = parseHeader(&header, child);
if(ret != 0) {
xmlDispose(&xml);
return ret;
auto itXml = xml.children.begin();
while(itXml != xml.children.end()) {
auto child = *itXml;
if(child->node != "head") {
++itXml;
continue;
}
auto ret = parseHeader(&header, child);
if(ret != 0) return ret;
break;
}
// Validate header
if(header.name.size() == 0 || header.type.size() == 0) {
if(header.sceneInfo.name.size() == 0 || header.sceneInfo.type.size() == 0) {
std::cout << "VN Scene header wasn't parsed properly." << std::endl;
return 1;
}
// Parse and load events.
std::string bufferEvents;
for(int32_t i = 0; i < xml.childrenCount; i++) {
auto events = xml.children + i;
if(std::string(events->node) != "events") continue;
itXml = xml.children.begin();
while(itXml != xml.children.end()) {
auto events = *itXml;
if(events->node != "events") {
++itXml;
continue;
}
bufferEvents += "\n start\n";
for(int32_t j = 0; j < events->childrenCount; j++) {
auto evt = events->children + j;
if(std::string(evt->node) == "scene-transition") continue;
auto evtParsed = parseEvent(evt, &header);
if(evtParsed.size() == 0) return 1;
bufferEvents += " ->then(" + evtParsed + ")\n";
auto itChildren = events->children.begin();
while(itChildren != events->children.end()) {
auto evt = *itChildren;
if(evt->node != "scene-transition") {
auto evtParsed = parseEvent(&header, evt);
if(evtParsed.size() == 0) return 1;
bufferEvents += " ->then(" + evtParsed + ")\n";
}
++itChildren;
}
bufferEvents += " ;\n";
++itXml;
}
// Now render output to file.
@ -254,7 +79,7 @@ int32_t VnSceneGen::start() {
++itInclude;
}
bufferOut += "\nnamespace Dawn{\n";
bufferOut += " class " + header.name + " : public " + header.type + " {\n";
bufferOut += " class " + header.sceneInfo.name + " : public " + header.sceneInfo.type + " {\n";
bufferOut += " protected:\n";
// Characters (As properties)
@ -265,7 +90,7 @@ int32_t VnSceneGen::start() {
++itCharacters;
}
bufferOut += "\n void vnStage() override {\n";
bufferOut += " " + header.type + "::vnStage();\n";
bufferOut += " " + header.sceneInfo.type + "::vnStage();\n";
// Initialize the characters
itCharacters = header.characters.begin();
@ -278,13 +103,13 @@ int32_t VnSceneGen::start() {
bufferOut += " }\n";
bufferOut += "\n public:\n";
bufferOut += " " + header.name + "(DawnGame *game) : " + header.type + "(game) {\n";
bufferOut += " " + header.sceneInfo.name + "(DawnGame *game) : " + header.sceneInfo.type + "(game) {\n";
bufferOut += " }\n";
// Assets
bufferOut += "\n std::vector<Asset*> getRequiredAssets() override{\n";
bufferOut += " auto man = &this->game->assetManager;\n";
bufferOut += " std::vector<Asset*> assets = " + header.type + "::getRequiredAssets();\n";
bufferOut += " std::vector<Asset*> assets = " + header.sceneInfo.type + "::getRequiredAssets();\n";
itCharacters = header.characters.begin();
while(itCharacters != header.characters.end()) {
auto c = *itCharacters;
@ -305,8 +130,6 @@ int32_t VnSceneGen::start() {
bufferOut += "}";
// Finished with XML data, now we can write data out.
xmlDispose(&xml);
File fileOut(this->args[2] + ".hpp");
if(!fileOut.mkdirp()) {
std::cout << "Failed to make scene output dir" << std::endl;

View File

@ -5,32 +5,11 @@
#pragma once
#include "util/DawnTool.hpp"
#include "util/Xml.hpp"
#include "util/File.hpp"
#include "../../util/file.hpp"
#include "../../util/xml.hpp"
#include <iostream>
#include <vector>
#include "parse/VnSceneParseEvent.hpp"
#include "parse/VnSceneParseHeader.hpp"
namespace Dawn {
struct CharacterInformation {
std::string clazz;
std::string name;
};
struct Asset {
std::string type;
std::string name;
};
struct HeaderInformation {
std::string type;
std::string name;
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct Asset> assets;
};
class VnSceneGen : public DawnTool {
protected:

View File

@ -0,0 +1,15 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(vnscenegen
PRIVATE
VnSceneParseAsset.cpp
VnSceneParseCharacter.cpp
VnSceneParseEvent.cpp
VnSceneParseScene.cpp
VnSceneParseHeader.cpp
VnSceneParseInclude.cpp
)

View File

@ -0,0 +1,27 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseAsset.hpp"
using namespace Dawn;
int32_t parseAsset(std::vector<struct Asset> *assets, Xml *node) {
auto attrType = node->attributes.find("type");
if(attrType == node->attributes.end()) {
std::cout << "VN Scene Asset missing type attribute" << std::endl;
return 1;
}
auto attrName = node->attributes.find("name");
if(attrName == node->attributes.end()) {
std::cout << "VN Scene Asset missing name attribute" << std::endl;
return 1;
}
struct Asset ass;
ass.type = attrType->second;
ass.name = attrType->second;
assets->push_back(ass);
return 0;
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
using namespace Dawn;
struct Asset {
std::string type;
std::string name;
};
int32_t parseAsset(std::vector<struct Asset> *assets, Xml *node);

View File

@ -0,0 +1,27 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseCharacter.hpp"
using namespace Dawn;
int32_t parseCharacter(std::vector<struct CharacterInformation> *characters, Xml *node) {
auto attrClass = node->attributes.find("class");
if(attrClass == node->attributes.end()) {
std::cout << "Character definition is missing class" << std::endl;
return 1;
}
auto attrName = node->attributes.find("name");
if(attrName == node->attributes.end()) {
std::cout << "Character definition is missing name" << std::endl;
}
struct CharacterInformation character;
character.clazz = attrClass->second;
character.name = attrName->second;
characters->push_back(character);
return 0;
}

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
using namespace Dawn;
struct CharacterInformation {
std::string clazz;
std::string name;
};
int32_t parseCharacter(
std::vector<struct CharacterInformation> *characters,
Xml *node
);

View File

@ -0,0 +1,105 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseEvent.hpp"
using namespace Dawn;
std::string parseEase(std::string e) {
if(e == "out-quad") return "easeOutQuad";
std::cout << "Invalid ease defined" << std::endl;
return "";
}
std::string parseEvent(struct HeaderInformation *header, Xml *evt) {
std::string buffer;
std::string node(evt->node);
if(node == "pause") {
// Pause
header->includes.push_back("visualnovel/events/timing/VisualNovelPauseEvent.hpp");
auto attrDuration = evt->attributes.find("duration");
if(attrDuration == evt->attributes.end()) {
std::cout << "Pause event is missing duration argument." << std::endl;
return "";
}
auto dur = attrDuration->second;
if(dur.find('.') == std::string::npos) dur += ".0";
buffer += "new VisualNovelPauseEvent(vnManager, " + dur + "f)";
} else if(node == "text") {
// Text
header->includes.push_back("visualnovel/events/VisualNovelTextboxEvent.hpp");
auto attrChar = evt->attributes.find("character");
if(attrChar == evt->attributes.end()) {
std::cout << "Text event missing character attribute." << std::endl;
return "";
}
auto attrEmotion = evt->attributes.find("emotion");
if(attrEmotion == evt->attributes.end()) {
std::cout << "Text event missing emotion attribute." << std::endl;
return "";
}
auto attrString = evt->attributes.find("string");
if(attrString == evt->attributes.end()) {
std::cout << "Text event missing string attribute." << std::endl;
return "";
}
std::string emo = attrEmotion->second;
emo[0] = toupper(emo[0]);
buffer += "new VisualNovelTextboxEvent(vnManager, ";
buffer += "this->" + attrChar->second + "->vnCharacter, ";
buffer += "this->" + attrChar->second + "->emotion" + emo + ", ";
buffer += "\"" + attrString->second + "\"" ;
buffer += ")";
} else if(node == "character-fade") {
// Character Fade
header->includes.push_back("visualnovel/events/characters/VisualNovelFadeCharacterEvent.hpp");
auto attrChar = evt->attributes.find("character");
auto attrDuration = evt->attributes.find("duration");
auto attrEase = evt->attributes.find("ease");
auto attrFade = evt->attributes.find("fade");
if(attrChar == evt->attributes.end()) {
std::cout << "Character fade event missing character attribute." << std::endl;
return "";
}
std::string character = attrChar->second;
std::string easeIn = "true";
std::string ease = "easeLinear";
std::string duration = "1.0";
if(attrFade != evt->attributes.end()) easeIn = attrFade->second == "in" ? "true" : "false";
if(attrDuration != evt->attributes.end()) duration = attrDuration->second;
if(duration.find('.') == std::string::npos) duration += ".0";
if(attrEase != evt->attributes.end()) {
ease = parseEase(attrEase->second);
if(ease.size() == 0) return "";
}
buffer += "new VisualNovelFadeCharacterEvent(vnManager, ";
buffer += "this->" + character + "->vnCharacter, ";
buffer += easeIn + ", ";
buffer += "&" + ease + ", ";
buffer += duration + "f";
buffer += ")";
} else if(node == "scene-transition") {
buffer += " ";
}
return buffer;
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
#include "parse/VnSceneParseHeader.hpp"
using namespace Dawn;
std::string parseEvent(struct HeaderInformation *header, Xml *evt);

View File

@ -0,0 +1,31 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseHeader.hpp"
using namespace Dawn;
int32_t parseHeader(struct HeaderInformation *info, Xml *node) {
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
int32_t ret = 0;
if(c->node == "include") {
ret = parseInclude(&info->includes, c);
} else if(c->node == "character") {
ret = parseCharacter(&info->characters, c);
} else if(c->node == "scene") {
ret = parseScene(&info->sceneInfo, c);
} else if (c->node == "asset") {
ret = parseAsset(&info->assets, c);
} else {
std::cout << "Parsing VN Scene header, unknown node " << c->node << std::endl;
}
if(ret != 0) return ret;
++itChildren;
}
return 0;
}

View File

@ -0,0 +1,22 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
#include "parse/VnSceneParseCharacter.hpp"
#include "parse/VnSceneParseInclude.hpp"
#include "parse/VnSceneParseScene.hpp"
#include "parse/VnSceneParseAsset.hpp"
using namespace Dawn;
struct HeaderInformation {
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct Asset> assets;
struct SceneInformation sceneInfo;
};
int32_t parseHeader(struct HeaderInformation *info, Xml *node);

View File

@ -0,0 +1,19 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseInclude.hpp"
using namespace Dawn;
int32_t parseInclude(std::vector<std::string> *includes, Xml *node) {
auto attrPath = node->attributes.find("path");
if(attrPath == node->attributes.end()) {
std::cout << "Missing include path in VN Header Defintions." << std::endl;
return 1;
}
includes->push_back(attrPath->second);
return 0;
}

View File

@ -0,0 +1,11 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
using namespace Dawn;
int32_t parseInclude(std::vector<std::string> *includes, Xml *node);

View File

@ -0,0 +1,25 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneParseScene.hpp"
using namespace Dawn;
int32_t parseScene(struct SceneInformation *info, Xml *node) {
auto attrName = node->attributes.find("name");
if(attrName == node->attributes.end()) {
std::cout << "VN Scene <scene> definition is missing name attribute" << std::endl;
return 1;
}
info->name = attrName->second;
auto attrType = node->attributes.find("type");
if(attrType == node->attributes.end()) {
info->type = "SimpleVNScene";
} else {
info->type = attrType->second;
}
return 0;
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
using namespace Dawn;
struct SceneInformation {
std::string type;
std::string name;
};
int32_t parseScene(struct SceneInformation *info, Xml *node);