mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
btex using xml wip
This commit is contained in:
49
assets/mods/basegame/books/btex.xml
Normal file
49
assets/mods/basegame/books/btex.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<btex cover="hardcover" inner="standard" papersize="standard">
|
||||
<cover>
|
||||
<title>The Way to Mastery of Lorem Ipsum<br />Or, How To Write and Publish a Book</title>
|
||||
<author>Terran Publishing</author>
|
||||
<edition>Test Edition</edition>
|
||||
</cover>
|
||||
|
||||
<toc><tableofcontents /></toc>
|
||||
|
||||
<manuscript>
|
||||
|
||||
<chapter>What Is a Book</chapter>
|
||||
|
||||
<p>This example book is designed to give you the exampe of the Book Language.</p>
|
||||
|
||||
<section>What Really Is a Book</section>
|
||||
|
||||
<p>A book is a collection of texts printed in a special way that allows them to be read easily, with enumerable pages and insertion of other helpful resources, such as illustrations and hyperlinks.</p>
|
||||
|
||||
<newpage />
|
||||
|
||||
<fullpagebox>
|
||||
<span colour="grey">
|
||||
<p>this page is intentionally left blank</p>
|
||||
</span>
|
||||
</fullpagebox>
|
||||
|
||||
<chapter>Writing Book Using Pen and Papers</chapter>
|
||||
|
||||
<p>If you open a book on a writing table, you will be welcomed with a toolbar used to put other book elements, such as chapters, sections.</p>
|
||||
|
||||
<chapter>Writing Book Using Typewriter</chapter>
|
||||
|
||||
<p>Typewriters can only write single style of font, therefore chapters and sections are not available.</p>
|
||||
|
||||
<chapter>Writing Book using Computer</chapter>
|
||||
|
||||
<p>Writing book using a computer requires a use of the Book Typesetting Engine Extended, or <BTeX /></p>
|
||||
|
||||
<section>Full Control of the Shape</section>
|
||||
|
||||
<p>With <BTeX /> you can fully control how your publishing would look like, from a pile of papers that look like they have been typed out using typewriter, a pile of papers but a fully-featured printouts that have illustrations in it, to a fully-featured hardcover book.</p>
|
||||
|
||||
<p>This style is controlled using the <code>cover</code> attribute on the root tag, with following values: <code>typewriter</code>, <code>printout</code>, <code>hardcover</code></p>
|
||||
|
||||
<p>Typewriter and Printout are considered not bound and readers will only see one page at a time, while Hardcover is considered bound and two pages are presented to the readers.</p>
|
||||
|
||||
</manuscript>
|
||||
</btex>
|
||||
60
assets/mods/basegame/books/examination.btex
Normal file
60
assets/mods/basegame/books/examination.btex
Normal file
@@ -0,0 +1,60 @@
|
||||
\usestyle{examination}
|
||||
|
||||
\begin{blocklut}
|
||||
\0\{basegame:0}
|
||||
\1\{basegame:32}
|
||||
\100\{wall@basegame:32}
|
||||
\end{blocklut}
|
||||
|
||||
|
||||
\begin{examination}
|
||||
|
||||
\section{Introduction}
|
||||
|
||||
\begin{tiles}{5x4}
|
||||
\terr{
|
||||
0,1,1,1,0,
|
||||
1,0,0,0,1,
|
||||
1,0,0,0,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\wall{
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\end{tiles}
|
||||
|
||||
This is the first page of the Examination.
|
||||
|
||||
Examination is a way to instruct the player certain gameplay concepts.
|
||||
|
||||
The system is popularised by the Minecraft Mod called ``Create'', of which it was called Pondering.
|
||||
|
||||
Terrarum borrows the concept and implements it using its own language.
|
||||
|
||||
\section{Language}
|
||||
|
||||
\begin{tiles}{5x4}
|
||||
\terr{
|
||||
0,1,1,1,0,
|
||||
1,0,1,0,1,
|
||||
1,0,1,0,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\wall{
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
}
|
||||
\end{tiles}
|
||||
|
||||
Examination relies on the script written in \BTeX.
|
||||
|
||||
\BTeX\ is a \TeX-inspired language to write texts to be displayed onto the game, one example being a book.
|
||||
|
||||
Examination is a special format of the "book" that operates on the same book system.
|
||||
|
||||
\end{examination}
|
||||
57
assets/mods/basegame/books/examination.xml
Normal file
57
assets/mods/basegame/books/examination.xml
Normal file
@@ -0,0 +1,57 @@
|
||||
<btex def="examination">
|
||||
<blocklut>
|
||||
<pair key="0" value="basegame:0" />
|
||||
<pair key="1" value="basegame:32" />
|
||||
</blocklut>
|
||||
|
||||
<manuscript>
|
||||
<section>Introduction</section>
|
||||
|
||||
<tiles w="5" h="4">
|
||||
<terr>
|
||||
0,1,1,1,0,
|
||||
1,0,0,0,1,
|
||||
1,0,0,0,1,
|
||||
0,1,1,1,0
|
||||
</terr>
|
||||
<wall>
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
</wall>
|
||||
</tiles>
|
||||
|
||||
<p>This is the first page of the Examination.</p>
|
||||
|
||||
<p>Examination is a way to instruct the player certain gameplay concepts.</p>
|
||||
|
||||
<p>The system is popularised by the Minecraft Mod called “Create”, of which it was called Pondering.</p>
|
||||
|
||||
<p>Terrarum borrows the concept and implements it using its own language.</p>
|
||||
|
||||
<section>Language</section>
|
||||
|
||||
<tiles w="5" h="4">
|
||||
<terr>
|
||||
0,1,1,1,0,
|
||||
1,0,1,0,1,
|
||||
1,0,1,0,1,
|
||||
0,1,1,1,0
|
||||
</terr>
|
||||
<wall>
|
||||
0,1,1,1,0,
|
||||
1,1,1,1,1,
|
||||
1,1,1,1,1,
|
||||
0,1,1,1,0
|
||||
</wall>
|
||||
</tiles>
|
||||
|
||||
<p>Examination relies on the script written in <BTeX />.</p>
|
||||
|
||||
<p><BTeX /> is a XML-like markup language to write texts to be displayed onto the game, one example being a book.</p>
|
||||
|
||||
<p>Examination is a special format of the “book” that operates on the same book system.</p>
|
||||
|
||||
</manuscript>
|
||||
</btex>
|
||||
93
src/net/torvald/btex/BTeXDocument.kt
Normal file
93
src/net/torvald/btex/BTeXDocument.kt
Normal file
@@ -0,0 +1,93 @@
|
||||
package net.torvald.terrarum.btex
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
class BTeXDocument {
|
||||
var context = "tome" // tome (cover=hardcover), sheets (cover=typewriter or cover=printout), examination (def=examination)
|
||||
var font = "default" // default or typewriter
|
||||
var inner = "standard"
|
||||
var papersize = "standard"
|
||||
|
||||
var pageWidth = 420
|
||||
var pageHeight = 25 * 24
|
||||
|
||||
companion object {
|
||||
val DEFAULT_PAGE_BACK = Color(0xe1e1d7ff.toInt())
|
||||
val DEFAULT_PAGE_FORE = Color(0x131311ff)
|
||||
}
|
||||
|
||||
private val pages = ArrayList<BTeXPage>()
|
||||
|
||||
|
||||
|
||||
fun addNewPage(back: Color = DEFAULT_PAGE_BACK) {
|
||||
pages.add(BTeXPage(back, pageWidth, pageHeight))
|
||||
}
|
||||
|
||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
||||
pages.last().appendDrawCall(drawCall)
|
||||
}
|
||||
|
||||
fun render(batch: SpriteBatch, page: Int, x: Int, y: Int) {
|
||||
pages[page].render(batch, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
class BTeXPage(
|
||||
val back: Color,
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
) {
|
||||
private val drawCalls = ArrayList<BTeXDrawCall>()
|
||||
|
||||
fun appendDrawCall(drawCall: BTeXDrawCall) {
|
||||
drawCalls.add(drawCall)
|
||||
}
|
||||
|
||||
fun render(batch: SpriteBatch, x: Int, y: Int) {
|
||||
batch.color = back
|
||||
Toolkit.fillArea(batch, x, y, width, height)
|
||||
drawCalls.forEach {
|
||||
it.draw(batch, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BTeXDrawCall(
|
||||
val posX: Int,
|
||||
val posY: Int,
|
||||
val theme: String,
|
||||
val colour: Color,
|
||||
val font: BitmapFont,
|
||||
val text: String? = null,
|
||||
val texture: TextureRegion? = null,
|
||||
) {
|
||||
|
||||
fun draw(batch: SpriteBatch, x: Int, y: Int) {
|
||||
val px = (posX + x).toFloat()
|
||||
val py = (posY + y).toFloat()
|
||||
|
||||
if (theme == "code") {
|
||||
// todo draw code background
|
||||
}
|
||||
|
||||
batch.color = colour
|
||||
|
||||
if (text != null && texture == null) {
|
||||
font.draw(batch, text, px, py)
|
||||
}
|
||||
else if (text == null && texture != null) {
|
||||
batch.draw(texture, px, py)
|
||||
}
|
||||
else throw Error("Text and Texture are both non-null")
|
||||
}
|
||||
|
||||
}
|
||||
159
src/net/torvald/btex/BTeXParser.kt
Normal file
159
src/net/torvald/btex/BTeXParser.kt
Normal file
@@ -0,0 +1,159 @@
|
||||
package net.torvald.btex
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.btex.BTeXDocument
|
||||
import net.torvald.terrarum.btex.BTeXDrawCall
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import org.xml.sax.Attributes
|
||||
import org.xml.sax.helpers.DefaultHandler
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
object BTeXParser {
|
||||
|
||||
operator fun invoke(file: FileHandle) = invoke(file.file())
|
||||
|
||||
operator fun invoke(file: File): BTeXDocument {
|
||||
val doc = BTeXDocument()
|
||||
val parser = SAXParserFactory.newDefaultInstance().newSAXParser()
|
||||
val stream = FileInputStream(file)
|
||||
parser.parse(stream, BTeXHandler(doc))
|
||||
return doc
|
||||
}
|
||||
|
||||
private class BTeXHandler(val doc: BTeXDocument) : DefaultHandler() {
|
||||
private val DEFAULT_FONTCOL = Color(0x222222ff)
|
||||
private val LINE_HEIGHT = 24
|
||||
|
||||
private var cover = ""
|
||||
private var inner = ""
|
||||
private var papersize = ""
|
||||
private var def = ""
|
||||
|
||||
private var pageWidth = 420
|
||||
private var pageLines = 25
|
||||
private var pageHeight = 25 * LINE_HEIGHT
|
||||
|
||||
private val blockLut = HashMap<String, ItemID>()
|
||||
|
||||
private val tagStack = ArrayList<String>() // index zero should be "btex"
|
||||
|
||||
|
||||
private var spanColour: String? = null
|
||||
|
||||
|
||||
private var typeX = 0
|
||||
private var typeY = 0
|
||||
|
||||
override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
|
||||
val tag = qName; if (tagStack.isEmpty() && tag != "btex") throw BTeXParsingException("Document is not btex")
|
||||
tagStack.add(tag)
|
||||
|
||||
val attribs = HashMap<String, String>().also {
|
||||
it.putAll((0 until attributes.length).map { attributes.getQName(it) to attributes.getValue(it) })
|
||||
}
|
||||
|
||||
val mode = tagStack.getOrNull(1)
|
||||
|
||||
when (tag) {
|
||||
"btex" -> {
|
||||
if (attribs.containsKey("def"))
|
||||
def = attribs["def"]!!
|
||||
else {
|
||||
cover = attribs["cover"] ?: "printout"
|
||||
inner = attribs["inner"] ?: "standard"
|
||||
papersize = attribs["papersize"] ?: "standard"
|
||||
|
||||
pageWidth = pageWidthMap[papersize]!!
|
||||
pageLines = pageHeightMap[papersize]!!
|
||||
pageHeight = pageLines * LINE_HEIGHT
|
||||
|
||||
doc.pageWidth = pageWidth
|
||||
doc.pageHeight = pageHeight
|
||||
}
|
||||
}
|
||||
"pair" -> {
|
||||
if (tagStack.size == 3 && mode == "blocklut") {
|
||||
blockLut[attribs["key"]!!] = attribs["value"]!!
|
||||
}
|
||||
else {
|
||||
throw BTeXParsingException("<pair> used outside of <blocklut>")
|
||||
}
|
||||
}
|
||||
"span" -> {
|
||||
attribs["span"]?.let {
|
||||
spanColour = it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun endElement(uri: String, localName: String, qName: String) {
|
||||
tagStack.removeLast()
|
||||
|
||||
when (qName) {
|
||||
"span" -> {
|
||||
spanColour = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||
val str = String(ch.sliceArray(start until start+length)).replace('\n',' ').replace(Regex(" +"), " ").trim()
|
||||
val font = getFont()
|
||||
advanceCursorPre(font.getWidth(str), 0)
|
||||
doc.appendDrawCall(BTeXDrawCall(typeX, typeY, inner, getSpanColour(), font, str))
|
||||
advanceCursorPost(font.getWidth(str), 0)
|
||||
}
|
||||
|
||||
private fun advanceCursorPre(w: Int, h: Int) {
|
||||
if (typeX + w > pageWidth) {
|
||||
typeY += LINE_HEIGHT
|
||||
typeX = 0
|
||||
}
|
||||
|
||||
if (typeY + h > pageHeight) {
|
||||
typeX = 0
|
||||
typeY = 0
|
||||
doc.addNewPage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun advanceCursorPost(w: Int, h: Int) {
|
||||
typeX += w
|
||||
typeY += h
|
||||
}
|
||||
|
||||
|
||||
private fun getFont() = when (cover) {
|
||||
"typewriter" -> TODO()
|
||||
else -> App.fontGame
|
||||
}
|
||||
|
||||
private fun getSpanColour(): Color = spanColourMap.getOrDefault(spanColour, DEFAULT_FONTCOL)
|
||||
|
||||
private val spanColourMap = hashMapOf(
|
||||
"grey" to Color.LIGHT_GRAY
|
||||
)
|
||||
|
||||
private val pageWidthMap = hashMapOf(
|
||||
"standard" to 420
|
||||
)
|
||||
private val pageHeightMap = hashMapOf(
|
||||
"standard" to 25
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BTeXParsingException(s: String) : RuntimeException(s) {
|
||||
|
||||
}
|
||||
100
src/net/torvald/terrarum/tests/BTeXTest.kt
Normal file
100
src/net/torvald/terrarum/tests/BTeXTest.kt
Normal file
@@ -0,0 +1,100 @@
|
||||
package net.torvald.terrarum.tests
|
||||
|
||||
import org.xml.sax.Attributes
|
||||
import org.xml.sax.HandlerBase
|
||||
import org.xml.sax.helpers.DefaultHandler
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
fun main() {
|
||||
val csiR = "\u001B[31m"
|
||||
val csiG = "\u001B[32m"
|
||||
val csi0 = "\u001B[m"
|
||||
|
||||
val tex = """<btex cover="hardcover" inner="standard" papersize="standard">
|
||||
<cover>
|
||||
<title>The Way to Mastery of Lorem Ipsum<br />Or, How To Write and Publish a Book</title>
|
||||
<author>Terran Publishing</author>
|
||||
<edition>Test Edition</edition>
|
||||
</cover>
|
||||
|
||||
<toc><tableofcontents /></toc>
|
||||
|
||||
<manuscript>
|
||||
|
||||
<chapter>What Is a Book</chapter>
|
||||
|
||||
<p>This example book is designed to give you the exampe of the Book Language.</p>
|
||||
|
||||
<section>What Really Is a Book</section>
|
||||
|
||||
<p>A book is a collection of texts printed in a special way that allows them to be read easily, with
|
||||
enumerable pages and insertion of other helpful resources, such as illustrations and hyperlinks.</p>
|
||||
|
||||
<newpage />
|
||||
|
||||
<fullpagebox>
|
||||
<span colour="grey">
|
||||
<p>this page is intentionally left blank</p>
|
||||
</span>
|
||||
</fullpagebox>
|
||||
|
||||
<chapter>Writing Book Using Pen and Papers</chapter>
|
||||
|
||||
<p>If you open a book on a writing table, you will be welcomed with a toolbar used to put other book
|
||||
elements, such as chapters, sections.</p>
|
||||
|
||||
<chapter>Writing Book Using Typewriter</chapter>
|
||||
|
||||
<p>Typewriters can only write single style of font, therefore chapters and sections are not available.</p>
|
||||
|
||||
<chapter>Writing Book using Computer</chapter>
|
||||
|
||||
<p>Writing book using a computer requires a use of the Book Typesetting Engine Extended, or <BTeX /></p>
|
||||
|
||||
<section>Full Control of the Shape</section>
|
||||
|
||||
<p>With <BTeX /> you can fully control how your publishing would look like, from a pile of papers that
|
||||
look like they have been typed out using typewriter, a pile of papers but a fully-featured printouts that
|
||||
have illustrations in it, to a fully-featured hardcover book.</p>
|
||||
|
||||
<p>This style is controlled using the <code>cover</code> attribute on the root tag, with following
|
||||
values: <code>typewriter</code>, <code>printout</code>, <code>hardcover</code></p>
|
||||
|
||||
<p>Typewriter and Printout are considered not bound and readers will only see one page at a time,
|
||||
while Hardcover is considered bound and two pages are presented to the readers.</p>
|
||||
|
||||
</manuscript>
|
||||
</btex>
|
||||
|
||||
|
||||
"""
|
||||
|
||||
val parser = SAXParserFactory.newDefaultInstance().newSAXParser()
|
||||
val stream: InputStream = ByteArrayInputStream(tex.encodeToByteArray())
|
||||
val hb = object : DefaultHandler() {
|
||||
override fun startElement(uri: String, localName: String, qName: String, attributes: Attributes) {
|
||||
println(" $csiG$qName$csi0 ${(0 until attributes.length).map { "${attributes.getQName(it)}=${attributes.getValue(it)}" }}")
|
||||
}
|
||||
|
||||
override fun endElement(uri: String, localName: String, qName: String) {
|
||||
println("$csiG/$qName$csi0")
|
||||
}
|
||||
|
||||
override fun characters(ch: CharArray, start: Int, length: Int) {
|
||||
val str = String(ch.sliceArray(start until start+length)).replace('\n',' ').replace(Regex(" +"), " ").trim()
|
||||
if (str.isNotBlank()) {
|
||||
println("$str|")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
parser.parse(stream, hb)
|
||||
}
|
||||
Reference in New Issue
Block a user