diff --git a/docs.py b/docs.py
index 2b4108d..f3d2fc8 100644
--- a/docs.py
+++ b/docs.py
@@ -2,24 +2,70 @@ import datetime
import re
import os
-from urllib.parse import urlparse
-
-from flask import Flask, send_from_directory, render_template, make_response, request
+from flask import Flask, send_from_directory, render_template, make_response, url_for
from livereload import Server
-import xml_lexer
+# Importing performs monkeypatching
+import xml_lexer # NOQA: F401
app = Flask(__name__)
app.jinja_options.setdefault('extensions', []).append('jinja2_highlight.HighlightExtension')
+HTAG = re.compile(r"]*id=\"([^\"]+)\"[^>]*>([^<]*)"
+def generate_toc(base, name, route, start=1):
+ parts = route.strip("/").split("/")
+
+ toc = CONTENTS
+ for i in parts:
+ if i in toc:
+ toc = toc[i]
+ if isinstance(toc, tuple):
+ toc = toc[1]
+ if not isinstance(toc, dict):
+ return ""
+ else:
+ return ""
+
+ def walk(toc, path, start=1):
+ unordered = len(toc) == 1 and 0 in toc
+ out = f'<{"u" if unordered else "o"}l start="{start}">'
+ for url in toc:
+ if isinstance(toc[url], tuple):
+ name, children = toc[url]
+ elif isinstance(toc[url], str):
+ name, children = toc[url], -1
+
+ out += "
"
+ if isinstance(url, str):
+ fqu = f"{ROOT}/{path}"
+ if not url.startswith("#"):
+ fqu += "/"
+ fqu += url
+ while "//" in fqu:
+ fqu = fqu.replace("//", "/")
+ if not fqu.endswith((".html", "/")) and "#" not in fqu:
+ fqu += "/"
+ out += f'{name}'
+ else:
+ out += name
+ out += "
"
+
+ if children == -1:
+ continue
+ if children is None:
+ filename = "/".join((TEMPLATES, PAGES_BASE, path, url))
+ while "//" in filename:
+ filename = filename.replace("//", "/")
+
+ if url == "":
+ filename += "index.html"
+
+ with open(filename) as page:
+ headers = HTAG.findall(page.read())
+
+ children = {}
+ for level, anchor, text in headers:
+ if level in TOC_HTAG_LEVELS:
+ children[f"#{anchor}"] = text
+ if not children:
+ children = None
+
+ if children is not None:
+ out += walk(children, f"{path}/{url}" if isinstance(url, str) else path)
+
+ out += f'{"u" if unordered else "o"}l>'
+
+ return out
+
+ return walk(toc, route, start)
+
+
+def generate_footer(base, name, route):
+ parts = route.strip("/").split("/")
+ if not parts:
+ return ""
+
+ toc = CONTENTS
+ path = []
+ for i in parts[:-1]:
+ if i in toc:
+ path.append(i)
+ toc = toc[i]
+ if isinstance(toc, tuple):
+ toc = toc[1]
+ if not isinstance(toc, dict):
+ toc = None
+ break
+ elif toc == CONTENTS:
+ toc = toc[""]
+ else:
+ toc = None
+ break
+
+ if toc == CONTENTS and len(parts) == 1:
+ toc = toc[""]
+
+ if toc is None:
+ siblings = None
+ else:
+ siblings = [i for i in toc.keys() if isinstance(i, str)]
+ try:
+ us_idx = siblings.index(parts[-1])
+ except ValueError:
+ us_idx = -1
+ parent = "/" + ("/".join(parts[:-1]))
+ if not parent.endswith("/"):
+ parent += "/"
+
+ footer = ""
+ return footer
+
+
@app.route("/styles.css")
def styles():
return send_from_directory(".", "styles.css")
+
+
@app.route("/tango.css")
def tango():
return send_from_directory(".", "tango.css")
+
+
@app.route("/headers.js")
def header_script():
return send_from_directory(".", "headers.js")
@@ -82,12 +262,14 @@ for base, _, files in os.walk(TEMPLATES + "/" + PAGES_BASE):
for name in files:
if name.endswith(".html"):
- def handler(base, name):
+ def handler(base, name, route):
def handler():
return render_template(
os.path.join(base, name).strip("/").replace("\\", "/"),
ROOT=ROOT,
- generate_xrpc_list=generate_xrpc_list
+ generate_xrpc_list=generate_xrpc_list,
+ generate_toc=lambda start=1: generate_toc(base, name, route, start),
+ generate_footer=lambda: generate_footer(base, name, route),
)
return handler
@@ -101,17 +283,14 @@ for base, _, files in os.walk(TEMPLATES + "/" + PAGES_BASE):
if not route.startswith("/"):
route = "/" + route
- handler = handler(base, name)
+ handler = handler(base, name, route)
handler.__name__ == route
app.add_url_rule(route, route, handler)
-from flask import url_for
-
@app.route("/sitemap.xml")
def sitemap():
- host_components = urlparse(request.host_url)
- host_base = "https://bsnk.me" + ROOT
+ host_base = HOST + ROOT
links = []
for rule in app.url_map.iter_rules():
@@ -133,6 +312,7 @@ def sitemap():
response.headers["Content-Type"] = "application/xml"
return response
+
if __name__ == '__main__':
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['DEBUG'] = True
@@ -141,4 +321,4 @@ if __name__ == '__main__':
server = Server(app.wsgi_app)
server.watch(".")
- server.serve(port=3000)
\ No newline at end of file
+ server.serve(port=3000)
diff --git a/headers.js b/headers.js
index c5d44c5..6a7d0ba 100644
--- a/headers.js
+++ b/headers.js
@@ -6,5 +6,3 @@ for (const el of document.querySelectorAll("[id]")) {
pilcrow.innerHTML = "¶"
el.prepend(pilcrow)
}
-
-console.log(hasId);
diff --git a/styles.css b/styles.css
index 85053f1..999eb83 100644
--- a/styles.css
+++ b/styles.css
@@ -154,4 +154,16 @@ table.nav td {
.pilcrow:hover {
opacity: 1;
color: #c7254e;
-}
\ No newline at end of file
+}
+
+footer {
+ width: 100%;
+ text-align: center;
+ margin-top: 8px;
+}
+footer>*:first-child {
+ float: left;
+}
+footer>*:last-child {
+ float: right;
+}
diff --git a/templates/base.html b/templates/base.html
index dba6847..84601be 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -5,7 +5,7 @@
- {% block title %}{% endblock %}{% if self.title() %} | {% endif %}e-Amusement API
+ {% block title %}{% endblock %}{% if self.title() %} | {% endif %}{% block roottitle %}Arcade Reverse Engineering{% endblock %}
@@ -21,16 +21,8 @@
-
Across these pages there are a number of code snippets. They roughly break down into three categories:
@@ -66,7 +34,4 @@
Assembly and C snippets often come with an accompanying filename and address. If you're interested in learning how
things work in more detail, I'd strongly recommend checking them out. Not all games come with the same version of
files; the provided addresses are for build SDVX build KFC-2019020600, using the default base offset.
-
-
-Next page
{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/motivation.html b/templates/pages/motivation.html
index ce94eb1..bc66053 100644
--- a/templates/pages/motivation.html
+++ b/templates/pages/motivation.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "konami.html" %}
{% block body %}
Why?
I was curious how these APIs work, yet could find little to nothing on Google. There are a number of
diff --git a/templates/pages/packet.html b/templates/pages/packet.html
index 64ccbf0..8b227ad 100644
--- a/templates/pages/packet.html
+++ b/templates/pages/packet.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "konami.html" %}
{% block title %}Packet format{% endblock %}
{% block body %}
Packet format
@@ -1023,6 +1023,4 @@
self.request_allocation(4){% endhighlight %}
-
-Prev page | Next page
{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/proto/apsmanager.html b/templates/pages/proto/apsmanager.html
index a53f817..df73d12 100644
--- a/templates/pages/proto/apsmanager.html
+++ b/templates/pages/proto/apsmanager.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "konami.html" %}
{% block title %}apsmanager{% endblock %}
{% block body %}
diff --git a/templates/pages/sega/hardware/index.html b/templates/pages/sega/hardware/index.html
new file mode 100644
index 0000000..d5dfc0e
--- /dev/null
+++ b/templates/pages/sega/hardware/index.html
@@ -0,0 +1,6 @@
+{% extends "sega.html" %}
+{% block title %}Hardware{% endblock %}
+{% block body %}
+
Hardware
+{{ generate_toc()|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/index.html b/templates/pages/sega/index.html
index 5cb43df..5048b00 100644
--- a/templates/pages/sega/index.html
+++ b/templates/pages/sega/index.html
@@ -1,203 +1,11 @@
-{% extends "base.html" %}
-{% block title %}SEGA Games{% endblock %}
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
{% block body %}
-
SEGA Games
-
This may get its own micro-site at some point if it grows large enough. For now it's mostly just a rambling of notes.
-
-
In some ways SEGA's protocols are simpler than Konami's (none of that XML mess) but in other ways they're more
- complicated (hardcoded URLs, multiple services required, etc.)
+
RingEdge 2
+
Welcome to the sub-site for RingEdge 2 games. What started as a simple desire to start games outside of dev mode
+ turned into an incredibly deep dive into the inner workings of the RE2 software. Enjoy.
-
ALL.Net
-
A simple service that exposes two URLs. The hostname must be http://naominet.jp.
-
-
Requests should be made with a number of standard HTTP headers, and must be either HTTP version 1.0 or 1.1
-
-
-
Connection
-
Close
-
-
-
Pragma
-
DFI
-
-
-
User-Agent
-
ALL.Net_PC_Win2/ver1.0
-
-
-
Content-Type
-
application/x-www-form-urlencoded
-
-
-
Content-Length
-
variable
-
-
-
Note that the Pragma header is optional, and the Content-Type header is a lie.
-
-
Requests and responses should be POSTs, and their body should be base64 encoded, zlib compressed,
- x-www-form-urlencoded data. For example, {key: "value", other: "another"} should encode to
- eJwdxcEJACAMA8Bt3CLD5BEQFIXSFtw+4OuWHpq7NG5OBXi+BmwzCRo=.
-
-
-
Responses are expected to contain stat indicating status:
-
-
-
1
-
Success
-
-
-
0
-
Failure
-
-
-
-1
-
Failure
-
-
-
-2
-
Failure
-
-
-
-3
-
Failure
-
-
-
This service provides two endpoints, documented below:
+{{ generate_toc(0)|safe }}
{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/intro.html b/templates/pages/sega/intro.html
new file mode 100644
index 0000000..93f9fc4
--- /dev/null
+++ b/templates/pages/sega/intro.html
@@ -0,0 +1,22 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+
Introduction to RingEdge 2
+
RingEdge 2 (RE2 henceforth) is the main computer used by Sega in a number of their arcade games. In their cronology
+ it exists as the successor to the RingEdge (no huge surprise there), which itself was the successor to the
+ Lindbergh, and is the predecessor of Nu. There also exists the RingWide, a slightly less powerful variant of the
+ Ring* computers. These pages focus on the RE2. I have no reason to believe the RE2 software stack is especially
+ differnet to that of the RE, but I haven't confirmed this. Nu, however, uses different systems in many places, and
+ most of the deep-dive pages will not be applicable.
+
+
Technical Specifications
+
+
Intel Core i3-540, 3.06GHz
+
Nvidia GeForce GT 545
+
2GB RAM
+
32GB SSD (TDK GBDISK RS3)
+
Intel Q57 Express Motherboard
+
+
+Next chapter
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/network/allnet.html b/templates/pages/sega/network/allnet.html
new file mode 100644
index 0000000..39aac0e
--- /dev/null
+++ b/templates/pages/sega/network/allnet.html
@@ -0,0 +1,197 @@
+{% extends "sega.html" %}
+{% block title %}ALL.Net{% endblock %}
+{% block body %}
+
ALL.Net
+
A simple service that exposes two URLs. The hostname must be http://naominet.jp.
+
+
Requests should be made with a number of standard HTTP headers, and must be either HTTP version 1.0 or 1.1
+
+
+
Connection
+
Close
+
+
+
Pragma
+
DFI
+
+
+
User-Agent
+
ALL.Net_PC_Win2/ver1.0
+
+
+
Content-Type
+
application/x-www-form-urlencoded
+
+
+
Content-Length
+
variable
+
+
+
Note that the Pragma header is optional, and the Content-Type header is a lie.
+
+
Requests and responses should be POSTs, and their body should be base64 encoded, zlib compressed,
+ x-www-form-urlencoded data. For example, {key: "value", other: "another"} should encode to
+ eJwdxcEJACAMA8Bt3CLD5BEQFIXSFtw+4OuWHpq7NG5OBXi+BmwzCRo=.
+
+
+
Responses are expected to contain stat indicating status:
+
+
+
1
+
Success
+
+
+
0
+
Failure
+
+
+
-1
+
Failure
+
+
+
-2
+
Failure
+
+
+
-3
+
Failure
+
+
+
This service provides two endpoints, documented below:
+
+
/sys/servlet/PowerOn
+
Request:
+
+
+
+
+
game_id
+
4-character game ID
+
+
+
ver
+
+
+
+
serial
+
+
+
+
ip
+
+
+
+
firm_ver
+
%01d%02d%02d
+
+
+
boot_ver
+
%02X%02X
+
+
+
format_ver
+
+
+
+
hops
+
+
+
+
encode
+
+
+
+
Response:
+
+
+
stat
+
See above
+
+
+
uri
+
+
+
+
host
+
+
+
+
region0
+
+
+
+
region_name0
+
+
+
+
region_name1
+
+
+
+
region_name2
+
+
+
+
region_name3
+
+
+
+
year
+
+
+
+
month
+
+
+
+
day
+
+
+
+
hour
+
+
+
+
minute
+
+
+
+
second
+
+
+
+
place_id
+
+
+
+
setting
+
+
+
+
country
+
+
+
+
timezone
+
+
+
+
res_class
+
+
+
+
+
/sys/servlet/DownloadOrder
+
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/network/index.html b/templates/pages/sega/network/index.html
new file mode 100644
index 0000000..ba29e88
--- /dev/null
+++ b/templates/pages/sega/network/index.html
@@ -0,0 +1,6 @@
+{% extends "sega.html" %}
+{% block title %}Networking{% endblock %}
+{% block body %}
+
Networking
+{{ generate_toc()|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/columba.html b/templates/pages/sega/software/drivers/columba.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/columba.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/index.html b/templates/pages/sega/software/drivers/index.html
new file mode 100644
index 0000000..b6d74bf
--- /dev/null
+++ b/templates/pages/sega/software/drivers/index.html
@@ -0,0 +1,6 @@
+{% extends "sega.html" %}
+{% block title %}Drivers{% endblock %}
+{% block body %}
+
Drivers
+{{ generate_toc()|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxhwreset.html b/templates/pages/sega/software/drivers/mxhwreset.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxhwreset.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxjvs.html b/templates/pages/sega/software/drivers/mxjvs.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxjvs.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxparallel.html b/templates/pages/sega/software/drivers/mxparallel.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxparallel.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxsmbus.html b/templates/pages/sega/software/drivers/mxsmbus.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxsmbus.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxsram.html b/templates/pages/sega/software/drivers/mxsram.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxsram.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/drivers/mxsuperio.html b/templates/pages/sega/software/drivers/mxsuperio.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/drivers/mxsuperio.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/index.html b/templates/pages/sega/software/index.html
new file mode 100644
index 0000000..b000255
--- /dev/null
+++ b/templates/pages/sega/software/index.html
@@ -0,0 +1,6 @@
+{% extends "sega.html" %}
+{% block title %}Software{% endblock %}
+{% block body %}
+
Software
+{{ generate_toc()|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/jvs.html b/templates/pages/sega/software/jvs.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/jvs.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/security/dongle.html b/templates/pages/sega/software/security/dongle.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/security/dongle.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/security/game.html b/templates/pages/sega/software/security/game.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/security/game.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/security/index.html b/templates/pages/sega/software/security/index.html
new file mode 100644
index 0000000..0b31831
--- /dev/null
+++ b/templates/pages/sega/software/security/index.html
@@ -0,0 +1,6 @@
+{% extends "sega.html" %}
+{% block title %}Security{% endblock %}
+{% block body %}
+
Security
+{{ generate_toc()|safe }}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/sega/software/security/keychip.html b/templates/pages/sega/software/security/keychip.html
new file mode 100644
index 0000000..603aaf7
--- /dev/null
+++ b/templates/pages/sega/software/security/keychip.html
@@ -0,0 +1,4 @@
+{% extends "sega.html" %}
+{% block title %}{% endblock %}
+{% block body %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/pages/server.html b/templates/pages/server.html
index 5812bd3..587fdf1 100644
--- a/templates/pages/server.html
+++ b/templates/pages/server.html
@@ -1,4 +1,4 @@
-{% extends "base.html" %}
+{% extends "konami.html" %}
{% block title %}Write a server{% endblock %}
{% block body %}
@@ -118,6 +118,4 @@ int xrpc_key_and_crypt(char *packet, char *eamuse_info, size_t size) {
feasibly perform no compression at all, and instead insert 0xFF every 8 bytes (starting at index 0), to
indicate that all values are literals. While obviously poor for compression, this is an easy way to test without
first implementing a compressor.
-
-Prev page | Next page
{% endblock %}
\ No newline at end of file
diff --git a/templates/sega.html b/templates/sega.html
new file mode 100644
index 0000000..777aebf
--- /dev/null
+++ b/templates/sega.html
@@ -0,0 +1,11 @@
+{% extends "base.html" %}
+{% block roottitle %}RingEdge 2{% endblock %}
+{% block rootbody %}
+