Redid the VN Scene Parser

This commit is contained in:
2023-02-12 21:38:12 -08:00
parent 9436b7e98f
commit f1d13d2e45
32 changed files with 941 additions and 516 deletions

View File

@ -39,7 +39,7 @@ tool_truetype(truetype_alice ${DIR_GAME_ASSETS}/font/Alice-Regular.ttf truetype_
tool_audio(audio_test borrowed/sample_short.wav)
tool_vnscene(vnscene_1 ${DIR_GAME_ASSETS}/vn/Scene_1.xml)
tool_vnscene(Scene_1 ${DIR_GAME_ASSETS}/vn/Scene_1.xml)
add_dependencies(${DAWN_TARGET_NAME}
locale_poker
@ -53,5 +53,5 @@ add_dependencies(${DAWN_TARGET_NAME}
audio_test
vnscene_1
Scene_1
)

View File

@ -4,7 +4,7 @@
// https://opensource.org/licenses/MIT
#include "DawnGame.hpp"
#include "scenes/vnscene_1.hpp"
#include "scenes/Scene_1.hpp"
using namespace Dawn;
@ -24,7 +24,7 @@ int32_t DawnGame::init() {
this->renderManager.init();
this->audioManager.init();
this->scene = new vnscene_1(this);
this->scene = new Scene_1(this);
return DAWN_GAME_INIT_RESULT_SUCCESS;
}

View File

@ -1,58 +0,0 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "visualnovel/scene/SimpleVNScene.hpp"
#include "scenes/Scene_2.hpp"
#include "prefabs/characters/DeathPrefab.hpp"
#include "visualnovel/events/characters/VisualNovelFadeCharacterEvent.hpp"
#include "visualnovel/events/characters/VisualNovelTransformItemEvent.hpp"
#include "visualnovel/events/timing/VisualNovelBatchEvent.hpp"
namespace Dawn {
class Scene_1 : public SimpleVNScene {
protected:
DeathPrefab *death;
void vnStage() override {
this->death = DeathPrefab::create(this);
this->death->material->color.a = 0;
}
void onSceneEnded() {
auto scene = new Scene_2(this->game);
game->assetManager.queueSwap(
scene->getRequiredAssets(), this->getRequiredAssets()
);
game->assetManager.syncLoad();
scene->stage();
this->game->sceneCutover(scene);
}
public:
Scene_1(DawnGame *game) : SimpleVNScene(game) {
}
std::vector<Asset*> getRequiredAssets() override {
auto man = &this->game->assetManager;
std::vector<Asset*> assets = SimpleVNScene::getRequiredAssets();
vectorAppend(&assets, DeathPrefab::getRequiredAssets(man));
assets.push_back(man->get<AudioAsset>("audio_test"));
return assets;
}
IVisualNovelEvent * getVNEvent() override {
auto start = new VisualNovelPauseEvent(vnManager, 0.1f);
start
->then(new VisualNovelTextboxEvent(vnManager, this->death->vnCharacter, this->death->emotionHappy, "scene.1.1"))
->then(new VisualNovelFadeCharacterEvent(vnManager, this->death->vnCharacter, true, &easeOutQuad, 1.0f))
// ->then(new VisualNovelCallbackEvent<Scene_1>(vnManager, this, &Scene_1::onSceneEnded))
;
return start;
}
};
}

View File

@ -0,0 +1,100 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
namespace Dawn {
struct ClassGenInfo {
std::vector<std::string> includes;
std::string clazz = "Unknown";
std::string extend = "";
std::string constructorArgs = "";
std::string extendArgs = "";
std::vector<std::string> protectedCode;
std::vector<std::string> protectedProperties;
std::vector<std::string> publicCode;
std::vector<std::string> publicProperties;
};
struct MethodGenInfo {
std::string name;
std::string type = "void";
std::vector<std::string> body;
std::string args = "";
bool_t isStatic = false;
bool_t isOverride = false;
};
class CodeGen {
protected:
static void line(
std::vector<std::string> *out,
std::string contents,
std::string tabs
) {
out->push_back(tabs + contents);
}
static void lines(
std::vector<std::string> *out,
std::vector<std::string> lines,
std::string tabs
) {
auto itLine = lines.begin();
while(itLine != lines.end()) {
line(out, *itLine, tabs);
++itLine;
}
}
static void classGen(
std::vector<std::string> *out,
struct ClassGenInfo info
) {
std::vector<std::string> buffer;
line(out, "#pragma once", "");
line(out, "", "");
if(info.includes.size() > 0) {
lines(out, info.includes, "");
line(out, "", "");
}
line(out, "namespace Dawn {", "");
line(out, "class " + info.clazz + (info.extend.size() == 0 ? "{" : " : public " + info.extend + " {" ), " ");
if(info.protectedCode.size() > 0) {
line(out, "protected:", " ");
lines(out, info.protectedProperties, " ");
line(out, "", " ");
lines(out, info.protectedCode, " ");
}
if(info.publicCode.size() > 0 || info.constructorArgs.size() > 0) {
line(out, "public:", " ");
lines(out, info.publicProperties, " ");
line(out, "", " ");
line(out, info.clazz + "(" + info.constructorArgs + ")" + (info.extend.size() > 0 ? " : " + info.extend + "(" + info.extendArgs + ")" : "") + " {", " ");
line(out, "}", " ");
if(info.publicCode.size() > 0) {
line(out, "", " ");
lines(out, info.publicCode, " ");
}
}
line(out, "};", " ");
line(out, "}", "");
}
static void methodGen(
std::vector<std::string> *out,
struct MethodGenInfo info
) {
line(out, info.type + " " + info.name + "(" + info.args + ") " + ( info.isOverride ? "override" : "" ) + "{", "");
lines(out, info.body, " ");
line(out, "}", "");
}
};
}

View File

@ -63,13 +63,13 @@ bool_t File::readString(std::string *out) {
out->clear();
size_t i = 0;
char buffer[FILE_BUFFER_SIZE + 1];
char buffer[FILE_BUFFER_SIZE + 1];// +1 for null term
while(i != this->length) {
size_t amt = mathMin<size_t>(FILE_BUFFER_SIZE, (this->length - i));
auto amtRead = fread(buffer, sizeof(char), amt, this->file);
if(amtRead != amt) return false;
i += amtRead;
buffer[amtRead + 1] = '\0';
buffer[amtRead] = '\0';
out->append(buffer);
}

View File

@ -0,0 +1,72 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/Xml.hpp"
namespace Dawn {
template<typename T>
class XmlParser {
protected:
virtual std::vector<std::string> getRequiredAttributes() = 0;
virtual std::map<std::string, std::string> getOptionalAttributes() = 0;
virtual int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
T *output,
std::string *error
) = 0;
public:
static std::string parseDuration(std::string duration) {
std::string dur = duration;
if(dur.find('.') == std::string::npos) dur += ".0";
return dur + "f";
}
static std::string parseEase(std::string e) {
if(e == "out-quad") return "&easeOutQuad";
if(e == "linear") return "&easeLinear";
return "";
}
int32_t parse(Xml *xml, T *output, std::string *error) {
std::map<std::string, std::string> values;
// First get the required attributes
auto required = this->getRequiredAttributes();
auto itRequired = required.begin();
while(itRequired != required.end()) {
auto s = *itRequired;
auto attr = xml->attributes.find(s);
if(attr == xml->attributes.end()) {
std::cout << "Missing required attribute \"" << s << "\"" << std::endl;
return 1;
}
values[s] = attr->second;
++itRequired;
}
// Now get the optional attributes
auto optional = this->getOptionalAttributes();
auto itOptional = optional.begin();
while(itOptional != optional.end()) {
auto key = itOptional->first;
auto defaultValue = itOptional->second;
auto attr = xml->attributes.find(key);
if(attr == xml->attributes.end()) {
values[key] = defaultValue;
} else {
values[key] = attr->second;
}
++itOptional;
}
// Now send to parser
return this->onParse(xml, values, output, error);
}
};
}

View File

@ -33,6 +33,3 @@ target_link_libraries(vnscenegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)
# Subdirs
add_subdirectory(parse)

View File

@ -23,111 +23,24 @@ int32_t VnSceneGen::start() {
// Parse XML
Xml xml = Xml::load(buffer);
// First, read the header information
struct HeaderInformation header;
auto itXml = xml.children.begin();
while(itXml != xml.children.end()) {
auto child = *itXml;
if(child->node != "head") {
++itXml;
continue;
std::string error;
struct RootInformation info;
auto ret = (RootParser()).parse(&xml, &info, &error);
if(ret != 0) {
std::cout << error << std::endl;
return ret;
}
auto ret = parseHeader(&header, child);
if(ret != 0) return ret;
break;
}
std::vector<std::string> lines;
RootGen::generate(&lines, &info, "");
// Validate header
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;
itXml = xml.children.begin();
while(itXml != xml.children.end()) {
auto events = *itXml;
if(events->node != "events") {
++itXml;
continue;
}
bufferEvents += "\n start\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.
// Generate buffer
std::string bufferOut;
bufferOut += "#pragma once\n\n";
auto itInclude = header.includes.begin();
while(itInclude != header.includes.end()) {
bufferOut += "#include \"" + (*itInclude) + "\"\n";
++itInclude;
auto itLine = lines.begin();
while(itLine != lines.end()) {
bufferOut += *itLine + "\n";
++itLine;
}
bufferOut += "\nnamespace Dawn{\n";
bufferOut += " class " + header.sceneInfo.name + " : public " + header.sceneInfo.type + " {\n";
bufferOut += " protected:\n";
// Characters (As properties)
auto itCharacters = header.characters.begin();
while(itCharacters != header.characters.end()) {
auto c = *itCharacters;
bufferOut += " " + c.clazz + " *" + c.name + ";\n";
++itCharacters;
}
bufferOut += "\n void vnStage() override {\n";
bufferOut += " " + header.sceneInfo.type + "::vnStage();\n";
// Initialize the characters
itCharacters = header.characters.begin();
while(itCharacters != header.characters.end()) {
auto c = *itCharacters;
bufferOut += " this->" + c.name + " = " + c.clazz + "::create(this);\n";
++itCharacters;
}
bufferOut += " }\n";
bufferOut += "\n public:\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.sceneInfo.type + "::getRequiredAssets();\n";
itCharacters = header.characters.begin();
while(itCharacters != header.characters.end()) {
auto c = *itCharacters;
bufferOut += " vectorAppend(&assets, " + c.clazz + "::getRequiredAssets(man));\n";
++itCharacters;
}
bufferOut += " return assets;\n";
bufferOut += " }\n";
// VN Events
bufferOut += "\n IVisualNovelEvent * getVNEvent() override {\n";
bufferOut += " auto start = new VisualNovelPauseEvent(vnManager, 0.01f);\n";
bufferOut += bufferEvents;
bufferOut += "\n return start;\n";
bufferOut += " }\n";
bufferOut += " };\n";
bufferOut += "}";
// Finished with XML data, now we can write data out.
File fileOut(this->args[2] + ".hpp");

View File

@ -6,14 +6,13 @@
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "parse/VnSceneParseEvent.hpp"
#include "parse/VnSceneParseHeader.hpp"
#include "parse/root.hpp"
namespace Dawn {
class VnSceneGen : public DawnTool {
protected:
public:
int32_t start() override;
int32_t start();
};
}

View File

@ -1,15 +0,0 @@
# 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

@ -1,27 +0,0 @@
// 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

@ -1,16 +0,0 @@
// 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

@ -1,27 +0,0 @@
// 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

@ -1,19 +0,0 @@
// 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

@ -1,105 +0,0 @@
// 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

@ -1,12 +0,0 @@
// 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

@ -1,31 +0,0 @@
// 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

@ -1,22 +0,0 @@
// 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

@ -1,19 +0,0 @@
// 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

@ -1,11 +0,0 @@
// 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

@ -1,25 +0,0 @@
// 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

@ -1,16 +0,0 @@
// 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);

View File

@ -0,0 +1,56 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct AssetInformation {
std::string type;
std::string name;
};
class AssetParser : public XmlParser<struct AssetInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"name",
"type"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct AssetInformation *out,
std::string *error
) {
out->name = values["name"];
out->type = values["type"];
return 0;
}
std::string convert(struct AssetInformation info) {
std::string out;
return out;
}
};
class AssetGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct AssetInformation *info,
std::string tabs
) {
return line(out, "// Asset will be generated here", tabs);
}
};
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct CharacterInformation {
std::string clazz;
std::string name;
};
class CharacterParser : public XmlParser<struct CharacterInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"class",
"name"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct CharacterInformation *out,
std::string *error
) {
out->clazz = values["class"];
out->name = values["name"];
if(out->clazz.size() == 0) {
*error = "Character class cannot be empty.";
return 1;
}
if(out->name.size() == 0) {
*error = "Character name cannot be empty.";
return 1;
}
return 0;
}
};
class CharacterGen : public CodeGen {
public:
static void generateProperty(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, info.clazz + " *" + info.name + ";", tabs);
}
static void generateInitializer(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, "this->" + info.name + " = " + info.clazz + "::create(this);", tabs);
}
static void generateAssets(
std::vector<std::string> *out,
struct CharacterInformation info,
std::string tabs
) {
line(out, "vectorAppend(&assets, " + info.clazz + "::getRequiredAssets(man));", "");
}
};
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct CharacterFadeEventInfo {
std::string character;
std::string duration;
std::string ease;
std::string fade;
std::string include;
};
class CharacterFadeParser : public XmlParser<struct CharacterFadeEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"character"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>{
{ "fade", "in" },
{ "ease", "linear" },
{ "duration", "1" }
};
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct CharacterFadeEventInfo *out,
std::string *error
) {
out->character = values["character"];
out->duration = parseDuration(values["duration"]);
out->ease = parseEase(values["ease"]);
out->fade = values["fade"] == "in" ? "true" : "false";
out->include = "visualnovel/events/characters/VisualNovelFadeCharacterEvent.hpp";
if(out->ease.size() == 0) {
*error = "Invalid ease";
return 1;
}
return 0;
}
};
class CharacterFadeGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct CharacterFadeEventInfo *info,
std::string tabs = ""
) {
line(out, "new VisualNovelFadeCharacterEvent(vnManager,", tabs + " ");
line(out, "this->" + info->character + "->vnCharacter,", tabs + " ");
line(out, info->fade + ",", tabs + " ");
line(out, info->ease + ",", tabs + " ");
line(out, info->duration, tabs + " ");
line(out, ")", tabs);
}
};
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct PauseEventInfo {
std::string duration;
std::string include;
};
class PauseEventParser : public XmlParser<struct PauseEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{ "duration" };
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct PauseEventInfo *out,
std::string *error
) {
out->duration = parseDuration(values["duration"]);
out->include = "visualnovel/events/timing/VisualNovelPauseEvent.hpp";
return 0;
}
};
class PauseEventGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct PauseEventInfo *info,
std::string tabs = ""
) {
line(out, "new VisualNovelPauseEvent(vnManager, " + info->duration + ")", tabs);
}
};
}

View File

@ -0,0 +1,100 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
struct TextStringInfo {
std::string lang;
std::string text;
};
struct TextEventInfo {
std::string character;
std::string emotion;
std::vector<struct TextStringInfo> strings;
std::string key = "scene.1.1";
};
class TextStringParser : public XmlParser<struct TextStringInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{ "lang" };
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct TextStringInfo *out,
std::string *error
) {
out->lang = values["lang"];
out->text = node->value;
return 0;
}
};
class TextEventParser : public XmlParser<struct TextEventInfo> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"character",
"emotion"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct TextEventInfo *out,
std::string *error
) {
int32_t ret = 0;
out->character = values["character"];
out->emotion = values["emotion"];
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "string") {
struct TextStringInfo str;
ret = (TextStringParser()).parse(c, &str, error);
out->strings.push_back(str);
}
++itChildren;
}
return ret;
}
};
class TextEventGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct TextEventInfo *info,
std::string tabs = ""
) {
std::string emo = info->emotion;
emo[0] = toupper(emo[0]);
line(out, "new VisualNovelTextboxEvent(vnManager,", tabs);
line(out, "this->" + info->character + "->vnCharacter, ", tabs + " ");
line(out, "this->" + info->character + "->emotion" + emo + ", ", tabs + " ");
line(out, "\"" + info->key + "\"", tabs + " ");
line(out, ")", tabs);
}
};
}

View File

@ -0,0 +1,109 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "parse/event/textevent.hpp"
#include "parse/event/characterfadeevent.hpp"
#include "parse/event/pauseevent.hpp"
namespace Dawn {
enum EventType {
EVENT_TYPE_TEXT,
EVENT_TYPE_CHARACTER_FADE,
EVENT_TYPE_PAUSE
};
struct EventsInformation {
std::map<int32_t, enum EventType> eventTypes;
std::map<int32_t, struct TextEventInfo> textEvents;
std::map<int32_t, struct CharacterFadeEventInfo> characterFadeEvents;
std::map<int32_t, struct PauseEventInfo> pauseEvents;
std::vector<std::string> includes;
};
class EventsParser : public XmlParser<struct EventsInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct EventsInformation *out,
std::string *error
) {
int32_t ret = 0;
int32_t i = 0;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "text") {
struct TextEventInfo textEvent;
ret = (TextEventParser()).parse(c, &textEvent, error);
out->eventTypes[i] = EVENT_TYPE_TEXT;
out->textEvents[i++] = textEvent;
} else if(c->node == "character-fade") {
struct CharacterFadeEventInfo charFadeEvent;
ret = (CharacterFadeParser()).parse(c, &charFadeEvent, error);
out->eventTypes[i] = EVENT_TYPE_CHARACTER_FADE;
out->characterFadeEvents[i++] = charFadeEvent;
out->includes.push_back(charFadeEvent.include);
} else if(c->node == "pause") {
struct PauseEventInfo pauseEvent;
ret = (PauseEventParser()).parse(c, &pauseEvent, error);
out->eventTypes[i] = EVENT_TYPE_PAUSE;
out->pauseEvents[i++] = pauseEvent;
out->includes.push_back(pauseEvent.include);
}
++itChildren;
}
return ret;
}
};
class EventsGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct EventsInformation *info,
std::string tabs
) {
auto itEvents = info->eventTypes.begin();
while(itEvents != info->eventTypes.end()) {
auto e = *itEvents;
line(out, "->then(", tabs);
switch(e.second) {
case EVENT_TYPE_TEXT:
TextEventGen::generate(out, &info->textEvents[e.first], tabs + " ");
break;
case EVENT_TYPE_CHARACTER_FADE:
CharacterFadeGen::generate(out, &info->characterFadeEvents[e.first], tabs + " ");
break;
case EVENT_TYPE_PAUSE:
PauseEventGen::generate(out, &info->pauseEvents[e.first], tabs + " ");
break;
}
line(out, ")", tabs);
++itEvents;
}
}
};
}

View File

@ -0,0 +1,67 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "parse/include.hpp"
#include "parse/character.hpp"
#include "parse/scene.hpp"
#include "parse/asset.hpp"
namespace Dawn {
struct HeaderInformation {
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct AssetInformation> assets;
std::map<std::string, std::map<std::string, std::string>> languages;
struct SceneInformation scene;
};
class HeaderParser : public XmlParser<struct HeaderInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>();
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct HeaderInformation *out,
std::string *error
) {
int32_t ret = 0;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "include") {
ret = (IncludeParser()).parse(c, &out->includes, error);
} else if (c->node == "character") {
struct CharacterInformation character;
ret = (CharacterParser()).parse(c, &character, error);
if(ret != 0) return ret;
out->characters.push_back(character);
} else if(c->node == "asset") {
struct AssetInformation asset;
ret = (AssetParser()).parse(c, &asset, error);
if(ret != 0) return ret;
out->assets.push_back(asset);
} else if(c->node == "scene") {
ret = (SceneParser()).parse(c, &out->scene, error);
}
if(ret != 0) return ret;
++itChildren;
}
return ret;
}
};
}

View File

@ -0,0 +1,59 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
#include "util/CodeGen.hpp"
namespace Dawn {
typedef std::vector<std::string> include_t;
class IncludeParser : public XmlParser<include_t> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"path"
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
include_t *out,
std::string *error
) {
if(values["path"].size() == 0) {
*error = "";
return 1;
}
out->push_back(values["path"]);
return 0;
}
};
class IncludeGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
include_t includes,
std::string tabs
) {
std::vector<std::string> generated;
auto it = includes.begin();
while(it != includes.end()) {
if(std::find(generated.begin(), generated.end(), *it) == generated.end()) {
line(out, "#include \"" + *it + "\"", tabs);
generated.push_back(*it);
}
++it;
}
}
};
}

View File

@ -0,0 +1,114 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "parse/header.hpp"
#include "parse/events.hpp"
namespace Dawn {
struct RootInformation {
struct HeaderInformation header;
struct EventsInformation events;
};
class RootParser : public XmlParser<struct RootInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>();
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>();
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct RootInformation *out,
std::string *error
) {
int32_t ret = 0;
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "head") {
ret = (HeaderParser()).parse(c, &out->header, error);
} else if(c->node == "events") {
ret = (EventsParser()).parse(c, &out->events, error);
}
if(ret != 0) return ret;
++itChildren;
}
return ret;
}
};
class RootGen : public CodeGen {
public:
static void generate(
std::vector<std::string> *out,
struct RootInformation *info,
std::string tabs = ""
) {
struct ClassGenInfo c;
c.clazz = info->header.scene.name;
c.extend = info->header.scene.type;
c.constructorArgs = "DawnGame *game";
c.extendArgs = "game";
struct MethodGenInfo vnStage;
vnStage.name = "vnStage";
vnStage.type = "void";
vnStage.isOverride = true;
line(&vnStage.body, info->header.scene.type+ "::vnStage();", "");
struct MethodGenInfo getAssets;
getAssets.name = "getRequiredAssets";
getAssets.type = "std::vector<Asset*>";
getAssets.isOverride = true;
line(&getAssets.body, "auto man = &this->game->assetManager;", "");
line(&getAssets.body, "auto assets = " + info->header.scene.type + "::getRequiredAssets();", "");
struct MethodGenInfo getVNEvent;
getVNEvent.name = "getVNEvent";
getVNEvent.type = "IVisualNovelEvent *";
getVNEvent.isOverride = true;
line(&getVNEvent.body, "auto start = new VisualNovelPauseEvent(vnManager, 1.0f);", "");
IncludeGen::generate(&c.includes, info->header.includes, "");
IncludeGen::generate(&c.includes, info->events.includes, "");
// Characters
auto itChar = info->header.characters.begin();
while(itChar != info->header.characters.end()) {
CharacterGen::generateProperty(&c.publicProperties, *itChar, "");
CharacterGen::generateInitializer(&vnStage.body, *itChar, "");
CharacterGen::generateAssets(&getAssets.body, *itChar, "");
++itChar;
}
// Events
if(info->events.eventTypes.size() > 0) {
line(&getVNEvent.body, "start", "");
EventsGen::generate(&getVNEvent.body, &info->events, " ");
line(&getVNEvent.body, ";", "");
}
// Wrap up methods
line(&getAssets.body, "return assets;", "");
line(&getVNEvent.body, "return start;", "");
methodGen(&c.publicCode, vnStage);
line(&c.publicCode, "", "");
methodGen(&c.publicCode, getAssets);
methodGen(&c.publicCode, getVNEvent);
classGen(out, c);
}
};
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/XmlParser.hpp"
namespace Dawn {
struct SceneInformation {
std::string type;
std::string name;
};
class SceneParser : public XmlParser<struct SceneInformation> {
protected:
std::vector<std::string> getRequiredAttributes() {
return std::vector<std::string>{
"name",
};
}
std::map<std::string, std::string> getOptionalAttributes() {
return std::map<std::string, std::string>{
{ "type", "SimpleVNScene" }
};
}
int32_t onParse(
Xml *node,
std::map<std::string, std::string> values,
struct SceneInformation *out,
std::string *error
) {
out->name = values["name"];
out->type = values["type"];
return 0;
}
};
}