Almost done with new language tools

This commit is contained in:
2023-02-14 23:03:11 -08:00
parent b7db050a5c
commit b8bab7ebed
45 changed files with 416 additions and 289 deletions

View File

@ -0,0 +1,39 @@
# Copyright (c) 2023 Dominic Msters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# VN Scene Generator Tool
project(vnscenegen VERSION 1.1)
add_executable(vnscenegen)
# Sources
target_sources(vnscenegen
PRIVATE
${DAWN_SHARED_SOURCES}
${DAWN_TOOL_SOURCES}
VnSceneGen.cpp
)
# Includes
target_include_directories(vnscenegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${DAWN_TOOL_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}
)
# Definitions
target_compile_definitions(vnscenegen
PUBLIC
${DAWN_SHARED_DEFINITIONS}
DAWN_TOOL_INSTANCE=VnSceneGen
DAWN_TOOL_HEADER="VnSceneGen.hpp"
)
# Libraries
target_link_libraries(vnscenegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}
)

View File

@ -0,0 +1,60 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "VnSceneGen.hpp"
using namespace Dawn;
std::vector<std::string> VnSceneGen::getRequiredFlags() {
return std::vector<std::string>{ "input", "output", "language-out" };
}
int32_t VnSceneGen::start() {
// Open input file.
File file(flags["input"]);
std::string buffer;
if(!file.readString(&buffer)) {
std::cout << "Failed to read scene " << file.filename << std::endl;
return 1;
}
// Parse XML
Xml xml = Xml::load(buffer);
std::string error;
struct RootInformation info;
auto ret = (RootParser()).parse(&xml, &info, &error);
if(ret != 0) {
std::cout << error << std::endl;
return ret;
}
std::vector<std::string> lines;
RootGen::generate(&lines, &info, "");
// Generate buffer
std::string bufferOut;
auto itLine = lines.begin();
while(itLine != lines.end()) {
bufferOut += *itLine + "\n";
++itLine;
}
// Finished with XML data, now we can write data out.
File fileOut(flags["output"] + ".hpp");
if(!fileOut.mkdirp()) {
std::cout << "Failed to make scene output dir" << std::endl;
return 1;
}
if(!fileOut.writeString(bufferOut)) {
std::cout << "Failed to generate scene " << fileOut.filename << std::endl;
return 1;
}
// Now dump out the language strings to be picked up later.
ret = languageSaveStrings(flags["language-out"], info.strings);
if(ret != 0) return ret;
return 0;
}

View File

@ -0,0 +1,20 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/File.hpp"
#include "parse/root.hpp"
#include "util/Language.cpp"
namespace Dawn {
class VnSceneGen : public DawnTool {
protected:
std::vector<std::string> getRequiredFlags() override;
public:
int32_t start();
};
}

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,101 @@
// 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"
#include "util/Language.hpp"
namespace Dawn {
struct TextEventInfo {
std::string character;
std::string emotion;
std::vector<struct LanguageString> strings;
std::string key;
};
class TextStringParser : public XmlParser<struct LanguageString> {
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 LanguageString *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"];
if(out->key.size() <= 0) {
*error = "Text Event requries a language key to be defined.";
return 1;
}
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "string") {
struct LanguageString str;
ret = (TextStringParser()).parse(c, &str, error);
str.key = out->key;
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,121 @@
// 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;
std::vector<struct LanguageString> strings;
std::string key;
};
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;
int32_t languageKeyNumber = 1;
if(out->key.size() <= 0) {
*error = "Events requries a language key to be defined.";
return 1;
}
auto itChildren = node->children.begin();
while(itChildren != node->children.end()) {
auto c = *itChildren;
if(c->node == "text") {
struct TextEventInfo textEvent;
textEvent.key = out->key + "." + std::to_string(languageKeyNumber++);
ret = (TextEventParser()).parse(c, &textEvent, error);
out->eventTypes[i] = EVENT_TYPE_TEXT;
out->textEvents[i++] = textEvent;
vectorAppend(&out->strings, textEvent.strings);
} 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,118 @@
// 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;
std::vector<struct LanguageString> strings;
};
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") {
out->events.key = out->header.scene.name;
ret = (EventsParser()).parse(c, &out->events, error);
vectorAppend(&out->strings, out->events.strings);
}
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;
}
};
}