From 12832ca73b40c158b52f88ef328ebe7ab3c1bcc4 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Mon, 19 Jun 2023 02:37:46 +0100 Subject: [PATCH] Styles stuff --- .gitignore | 1 + docs.py | 202 ++++++---- headers.js | 87 ++++- main.scss | 91 +++++ start_ea.cmd | 4 + start_sega.cmd | 4 + styles.css => styles-aswas.css | 8 +- styles/code.scss | 61 +++ styles/collapse.scss | 99 +++++ styles/footer.scss | 31 ++ styles/misc.scss | 19 + styles/nav.scss | 16 + styles/normalise.scss | 351 ++++++++++++++++++ styles/part.scss | 42 +++ styles/sidebar.scss | 52 +++ styles/table.scss | 54 +++ styles/type.scss | 89 +++++ templates/base.html | 10 +- templates/footer.html | 13 + templates/pages/sega/hardware/keychip.html | 3 - .../sega/hardware/{~keychip.md => keychip.md} | 0 .../sega/hardware/{touch.html => touch.md} | 97 ++--- templates/pages/sega/maimai/index.md | 34 ++ templates/pages/sega/maimai/redoc.html | 19 + templates/pages/sega/network/allnet.html | 3 - templates/pages/sega/network/allnet.html.old | 197 ---------- templates/pages/sega/network/auth.html | 3 - templates/pages/sega/network/auth.md | 149 ++++++++ templates/pages/sega/network/billing.md | 7 + templates/pages/sega/network/index.html | 6 - .../sega/network/{~allnet.md => index.md} | 2 +- templates/pages/sega/network/~auth.md | 149 -------- templates/sega.html | 1 + 33 files changed, 1408 insertions(+), 496 deletions(-) create mode 100644 main.scss create mode 100644 start_ea.cmd create mode 100644 start_sega.cmd rename styles.css => styles-aswas.css (97%) create mode 100644 styles/code.scss create mode 100644 styles/collapse.scss create mode 100644 styles/footer.scss create mode 100644 styles/misc.scss create mode 100644 styles/nav.scss create mode 100644 styles/normalise.scss create mode 100644 styles/part.scss create mode 100644 styles/sidebar.scss create mode 100644 styles/table.scss create mode 100644 styles/type.scss create mode 100644 templates/footer.html delete mode 100644 templates/pages/sega/hardware/keychip.html rename templates/pages/sega/hardware/{~keychip.md => keychip.md} (100%) rename templates/pages/sega/hardware/{touch.html => touch.md} (70%) create mode 100644 templates/pages/sega/maimai/index.md create mode 100644 templates/pages/sega/maimai/redoc.html delete mode 100644 templates/pages/sega/network/allnet.html delete mode 100644 templates/pages/sega/network/allnet.html.old delete mode 100644 templates/pages/sega/network/auth.html create mode 100644 templates/pages/sega/network/auth.md create mode 100644 templates/pages/sega/network/billing.md delete mode 100644 templates/pages/sega/network/index.html rename templates/pages/sega/network/{~allnet.md => index.md} (98%) delete mode 100644 templates/pages/sega/network/~auth.md diff --git a/.gitignore b/.gitignore index f21ad55..a2703f9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ build/ kcf/ +static/main.css diff --git a/docs.py b/docs.py index 7abd29d..0b0c4dd 100644 --- a/docs.py +++ b/docs.py @@ -1,11 +1,16 @@ from dataclasses import dataclass +from typing import Any import datetime import re import os import jinja_markdown -from flask import Flask, send_from_directory, render_template, make_response, url_for +from flask import ( + Flask, send_from_directory, render_template, make_response, url_for, + render_template_string +) +import sass from livereload import Server # Importing performs monkeypatching @@ -49,6 +54,10 @@ EAMUSE_CONTENTS = { } SEGA_CONTENTS = { "intro.html": ("Introduction to RingEdge 2", ()), + "network": ("Networking", { + "auth.html": "ALL.Net Authentication", + "billing.html": "ALL.Net Billing", + }), "hardware": ("Hardware", { "jvs.html": "JVS", "touch.html": "Touchscreen", @@ -82,8 +91,8 @@ CONTENTS = { class Part: id: str name: str - description: str = None - page: str = None + description: str | None = None + page: str | None = None PARTS = { @@ -158,6 +167,8 @@ def generate_toc(base, name, route, start=1): name, children = toc[url] elif isinstance(toc[url], str): name, children = toc[url], -1 + else: + raise ValueError out += "
  • " if isinstance(url, str): @@ -206,10 +217,10 @@ def generate_toc(base, name, route, start=1): return walk(toc, route, start) -def generate_footer(base, name, route): +def generate_footer_links(base, name, route): parts = route.strip("/").split("/") if not parts: - return "" + return {} toc = CONTENTS path = [] @@ -229,10 +240,13 @@ def generate_footer(base, name, route): break if toc == CONTENTS and len(parts) == 1: + assert toc is not None toc = toc[PAGES_BASE.partition("/")[2]] if toc is None: siblings = None + us_idx = -1 + parent = "" else: siblings = [i for i in toc.keys() if isinstance(i, str)] try: @@ -243,29 +257,24 @@ def generate_footer(base, name, route): if not parent.endswith("/"): parent += "/" - footer = "
    " + links: dict[str, Any] = dict(footer_previous="", footer_crumbs=[], footer_current="", footer_next="") + if siblings and us_idx > 0: - footer += f'Previous page' - footer += "" + links["footer_previous"] = parent + siblings[us_idx - 1] if parts: - crumbs = [] built = ROOT + "/" for i in parts[:-1]: built += f"{i}" if not built.endswith((".html", "/")): built += "/" - crumbs.append(f'{i}') - crumbs.append(parts[-1]) - footer += "/".join(crumbs) - - footer += "" + links["footer_crumbs"].append((built, i)) + links["footer_current"] = parts[-1] if siblings and us_idx < len(siblings) - 1 and us_idx != -1: - footer += f'Next page' + links["footer_next"] = parent + siblings[us_idx + 1] - footer += "
    " - return footer + return links def ioctl(original): @@ -306,61 +315,106 @@ def header_script(): return send_from_directory(".", "headers.js") -for i in STATIC: - for base, _, files in os.walk(i): +def install_static(): + for i in STATIC: + for base, _, files in os.walk(i): + for name in files: + def handler_factory(base, name): + def handler(): + return send_from_directory(base, name) + return handler + local_base = base.replace("\\", "/").strip(".").strip("/") + route = local_base + "/" + name + if not route.startswith("/"): + route = "/" + route + + app.add_url_rule(route, route, handler_factory(base, name)) + + +def handler_factory_html(base, name, route): + def handler(): + return render_template( + os.path.join(base, name).strip("/").replace("\\", "/"), + HOST=HOST, + ROOT=ROOT, + CANONICAL=ROOT + route, + **generate_footer_links(base, name, route), + + generate_xrpc_list=generate_xrpc_list, + generate_toc=lambda start=1: generate_toc(base, name, route, start), + relative=lambda path: os.path.join(base, path).strip("/").replace("\\", "/"), + part=part, + ioctl=ioctl, + ) + return handler + + +def handler_factory_markdown(base, name, route): + md_name = name[:-5] + ".md" + md_path = os.path.join(base, md_name).strip("/").replace("\\", "/") + + title = "Markdown Page" + with open(os.path.join(TEMPLATES, md_path)) as md_f: + for line in md_f: + line = line.strip() + if line.startswith("#") and not line.startswith("##"): + title = line[1:].strip() + + template = ( + f"{{% extends \"sega.html\" %}}{{% block title %}}{title}{{% endblock %}}" + f"{{% block body %}}" + f"{{% markdown %}}{{% include \"{md_path}\" %}}{{% endmarkdown %}}" + f"{{% endblock %}}" + ) + + def handler(): + return render_template_string( + template, + HOST=HOST, + ROOT=ROOT, + CANONICAL=ROOT + route, + **generate_footer_links(base, name, route), + + generate_xrpc_list=generate_xrpc_list, + generate_toc=lambda start=1: generate_toc(base, name, route, start), + relative=lambda path: os.path.join(base, path).strip("/").replace("\\", "/"), + part=part, + ioctl=ioctl, + ) + return handler + + +def install_pages(): + for base, _, files in os.walk(TEMPLATES + "/" + PAGES_BASE): + if ".git" in base: + continue + if base.startswith(TEMPLATES): + base = base[len(TEMPLATES):] + for name in files: - def handler(base, name): - def handler(): - return send_from_directory(base, name) - return handler - local_base = base.replace("\\", "/").strip(".").strip("/") - route = local_base + "/" + name - if not route.startswith("/"): - route = "/" + route + handler_factory = None - handler = handler(base, name) - handler.__name__ == route - app.add_url_rule(route, route, handler) + if name.endswith(".html"): + handler_factory = handler_factory_html + elif name.endswith(".md") and not name.startswith("~"): + handler_factory = handler_factory_markdown + name = name[:-3] + ".html" + if handler_factory is not None: + local_base = base.replace("\\", "/").strip(".").strip("/") + if local_base.startswith(PAGES_BASE): + local_base = local_base[len(PAGES_BASE):] -for base, _, files in os.walk(TEMPLATES + "/" + PAGES_BASE): - if ".git" in base: - continue - if base.startswith(TEMPLATES): - base = base[len(TEMPLATES):] + if name.endswith(".md"): + route = local_base + "/" + name[:-3] + ".html" + else: + route = local_base + "/" + name + if route.endswith("/index.html"): + route = route[:-10] + if not route.startswith("/"): + route = "/" + route - for name in files: - if name.endswith(".html"): - def handler(base, name, route): - def handler(): - return render_template( - os.path.join(base, name).strip("/").replace("\\", "/"), - ROOT=ROOT, - CANONICAL=ROOT + route, - 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), - relative=lambda path: os.path.join(base, path).strip("/").replace("\\", "/"), - part=part, - ioctl=ioctl, - ) - return handler - - local_base = base.replace("\\", "/").strip(".").strip("/") - if local_base.startswith(PAGES_BASE): - local_base = local_base[len(PAGES_BASE):] - - route = local_base + "/" + name - if route.endswith("/index.html"): - route = route[:-10] - if not route.startswith("/"): - route = "/" + route - - print([route, base, name]) - - handler = handler(base, name, route) - handler.__name__ == route - app.add_url_rule(route, route, handler) + app.add_url_rule(route, route, handler_factory(base, name, route)) @app.route("/sitemap.xml") @@ -369,7 +423,7 @@ def sitemap(): links = [] for rule in app.url_map.iter_rules(): - if "GET" in rule.methods and len(rule.arguments) == 0: + if (not rule.methods or "GET" in rule.methods) and len(rule.arguments) == 0: url = url_for(rule.endpoint, **(rule.defaults or {})) if not url.endswith(("/", ".html", ".png")): continue @@ -388,6 +442,16 @@ def sitemap(): return response +def compile_sass(): + with open("static/main.css", "w") as main_css: + main_css.write(sass.compile(filename="main.scss", output_style="compressed")) # type: ignore + + +install_static() +install_pages() +compile_sass() + + def run_dev(): app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['DEBUG'] = True @@ -396,6 +460,8 @@ def run_dev(): server = Server(app.wsgi_app) server.watch(".") + server.watch("main.scss", func=compile_sass) + server.watch("styles", func=compile_sass) server.serve(port=3000) diff --git a/headers.js b/headers.js index 36e8b90..f0a5baa 100644 --- a/headers.js +++ b/headers.js @@ -1,4 +1,87 @@ -for (const el of document.querySelectorAll("[id]")) { +const ROOT = document.getElementById("root"); + +const sidebar = document.createElement("div"); +sidebar.classList.add("sidebar"); + +let contentsEl = document.createElement("ul"); +sidebar.appendChild(contentsEl); + +const contentsHeadings = []; + +let cDepth = 1; +for (const el of ROOT.querySelectorAll(["h1", "h2", "h3", "h4"])) { + if (el.id.length == 0) { + el.id = el.innerText + .toLowerCase() + .replace(/[^a-zA-Z]+/g, " ") + .trim() + .replace(/ /g, "-"); + } + + let newLi = document.createElement("li"); + const newA = document.createElement("a"); + newA.setAttribute("href", "#" + el.id); + newA.innerHTML = el.innerHTML; + newLi.appendChild(newA); + + contentsHeadings.push([el, newLi]); + + const depth = parseInt(el.tagName[1]); + // We're in too deep + while (cDepth > depth) { + contentsEl = contentsEl.parentElement.parentElement; + cDepth--; + } + + // We're _way_ too shallow + if (cDepth < depth - 1) { + while (cDepth < depth) { + const tempLi = document.createElement("li"); + contentsEl.appendChild(tempLi); + const newUl = document.createElement("ul"); + tempLi.appendChild(newUl); + contentsEl = newUl; + cDepth++; + } + } + // We're only one level too shallow + else if (cDepth < depth) { + const newUl = document.createElement("ul"); + + if (depth == 0) { + newLi.appendChild(newUl); + } else { + contentsEl.childNodes[contentsEl.childNodes.length - 1].appendChild(newUl); + } + contentsEl = newUl; + cDepth++; + } + contentsEl.appendChild(newLi); +} +document.body.appendChild(sidebar); + +contentsHeadings.reverse(); +const onScroll = () => { + for (const [hEl, sbLi] of contentsHeadings) { + sbLi.classList.remove("active"); + } + let set = false; + for (const [hEl, sbLi] of contentsHeadings) { + if (hEl.offsetTop <= window.scrollY + 32) { + sbLi.classList.add("active"); + set = true; + break; + } + } + if (!set && contentsHeadings.length != 0) { + contentsHeadings[contentsHeadings.length - 1][1].classList.add("active"); + } +}; +document.addEventListener("scroll", onScroll); +document.addEventListener("resize", onScroll); +onScroll(); + +for (const el of ROOT.querySelectorAll("[id]")) { if (el.tagName === "marker") continue; el.classList.add("haspara"); const pilcrow = document.createElement("a"); @@ -84,4 +167,4 @@ const make_foldable = (root) => { flush_header(level, end); } }; -make_foldable(document.body); +make_foldable(ROOT); diff --git a/main.scss b/main.scss new file mode 100644 index 0000000..222711e --- /dev/null +++ b/main.scss @@ -0,0 +1,91 @@ +// * { +// margin: 0; +// padding: 0; +// } +@import "styles/normalise.scss"; + +* { + box-sizing: border-box; +} + +html, +body { + width: 100%; + height: 100%; +} + +body { + font-family: "Segoe UI", sans-serif; + line-height: 1.35; + color: #222; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + &::after { + content: ""; + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 32px; + background: linear-gradient(#000, #0000); + z-index: 10; + } +} + +#root { + max-width: #{960px + 16px * 2}; + width: 100%; + padding: 16px; +} + +#gap { + flex-grow: 1; +} + +img { + max-width: 100%; +} + +svg { + transform: translateZ(0); +} + +// We can't fit equal margins either side, so try our best +@media (max-width: #{(960px + 16px * 2) + 260px * 2}) { + body { + padding-left: 260px; + } + #root { + max-width: #{800px + 16 * 2}; + } +} + +// We have no hope of showing the sidebar +@media (max-width: #{(800px + 16px * 2) + 260px * 1}) { + body { + padding-left: 0; + } + .sidebar { + display: none; + } +} + +@media (prefers-color-scheme: dark) { + body { + background-color: #000; + color: #e6e6e6; + } +} + +@import "styles/type.scss"; +@import "styles/code.scss"; +@import "styles/table.scss"; +@import "styles/collapse.scss"; +@import "styles/footer.scss"; +@import "styles/sidebar.scss"; +@import "styles/misc.scss"; +@import "styles/nav.scss"; // TODO: Get rid of this +@import "styles/part.scss"; // TODO: Get rid of this diff --git a/start_ea.cmd b/start_ea.cmd new file mode 100644 index 0000000..872bde7 --- /dev/null +++ b/start_ea.cmd @@ -0,0 +1,4 @@ +@echo off +set EA_PROOT=pages/eamuse +set EA_HOST=127.0.0.1:3000 +py docs.py diff --git a/start_sega.cmd b/start_sega.cmd new file mode 100644 index 0000000..41209e9 --- /dev/null +++ b/start_sega.cmd @@ -0,0 +1,4 @@ +@echo off +set EA_PROOT=pages/sega +set EA_HOST=127.0.0.1:3000 +py docs.py diff --git a/styles.css b/styles-aswas.css similarity index 97% rename from styles.css rename to styles-aswas.css index 5a2486a..9b1a9c9 100644 --- a/styles.css +++ b/styles-aswas.css @@ -71,11 +71,12 @@ code { vertical-align: middle; letter-spacing: .02em; padding: 2px 4px; - font-size: 90%; + /* font-size: 90%; */ color: #c7254e; background-color: #f9f2f4; border-radius: 4px; word-break: break-word; + vertical-align: bottom; } dfn { @@ -266,6 +267,7 @@ mark { .toggle-root { cursor: pointer; position: relative; + padding-left: 22px; } .toggle-root.closed { @@ -280,7 +282,7 @@ mark { border-left-color: transparent; border-top-color: transparent; position: absolute; - left: -18px; + left: 2px; top: 50%; transform: translateY(-50%) rotate(45deg); transition: transform 100ms ease-out, opacity 100ms ease-out; @@ -339,7 +341,7 @@ mark { @media (prefers-color-scheme: dark) { body { background-color: #000; - color: #fff; + color: #e6e6e6; } footer { diff --git a/styles/code.scss b/styles/code.scss new file mode 100644 index 0000000..386c7c8 --- /dev/null +++ b/styles/code.scss @@ -0,0 +1,61 @@ +code { + vertical-align: middle; + letter-spacing: 0.02em; + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; + word-break: break-word; + vertical-align: middle; + + & > a { + color: inherit; + } + + @media (prefers-color-scheme: dark) { + background-color: #221115; + } +} + +pre > code, +.highlight { + display: block; + word-break: normal; + border-radius: 4px; + background: #f8f8f8; + border: 1px solid #ccc; + padding: 4px; + color: #333; + padding: 9.5px; + line-height: 1.4; + width: min-content; +} + +pre { + max-width: 100%; + overflow-x: auto; + display: block; + + & > .highlight { + margin-bottom: -16px; + } +} + +.highlight { + font-size: 95%; + + & > pre { + margin: 0; + + & > code { + border: none; + margin: 0; + padding: 0; + } + } + + @media (prefers-color-scheme: dark) { + filter: invert(1); + } +} diff --git a/styles/collapse.scss b/styles/collapse.scss new file mode 100644 index 0000000..3339eca --- /dev/null +++ b/styles/collapse.scss @@ -0,0 +1,99 @@ +// Paragraph markers +.pilcrow { + position: absolute; + right: calc(100%); + padding-right: 10px; + top: 0.1em; + font-size: 0.9em; + text-decoration: none; + opacity: 0; + color: #e68aa2; + + &:hover { + opacity: 1; + color: #c7254e; + } +} + +.haspara { + position: relative; + &:hover .pilcrow { + opacity: 1; + } +} + +// Section collapsing +.toggle-root { + cursor: pointer; + position: relative; + padding-left: 22px; + + &.closed { + user-select: none; + } + + &::before { + opacity: 0.5; + content: ""; + display: block; + border: 4px solid currentColor; + border-left-color: transparent; + border-top-color: transparent; + position: absolute; + left: 2px; + top: 50%; + transform: translateY(-50%) rotate(45deg); + transition: transform 100ms ease-out, opacity 100ms ease-out; + } + + &:hover::before { + opacity: 1; + } + + &.closed::before { + transform: translateY(-50%) rotate(-45deg); + } +} + +.toggle-section { + opacity: 1; + height: auto; + transition: opacity 50ms ease-out; + overflow: visible; + + &.closed { + opacity: 0; + overflow: hidden; + height: 0; + } +} + +// Notes +summary { + user-select: none; + cursor: pointer; + color: #c7254e; +} + +details { + background: #f9f2f4; + border: 1px solid #c7b3b8; + border-radius: 2px; + padding: 4px 8px; + margin: 4px 0; + overflow-x: auto; + max-width: 100%; + + code { + background: #fff; + } + + @media (prefers-color-scheme: dark) { + background: #1c0d11; + border-color: #3b2b2f; + + & code { + background: #000; + } + } +} diff --git a/styles/footer.scss b/styles/footer.scss new file mode 100644 index 0000000..603a804 --- /dev/null +++ b/styles/footer.scss @@ -0,0 +1,31 @@ +footer { + width: 100%; + margin-top: 32px; + padding-top: 8px; + + background-color: #090a0c; + + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + .footer-inner { + display: flex; + flex-direction: column; + + max-width: 1000px; + width: 100%; + padding: 24px 16px 32px; + + .footer-links { + text-align: center; + + & > *:first-child { + float: left; + } + & > *:last-child { + float: right; + } + } + } +} diff --git a/styles/misc.scss b/styles/misc.scss new file mode 100644 index 0000000..46c893f --- /dev/null +++ b/styles/misc.scss @@ -0,0 +1,19 @@ +.client { + color: #f5417d; +} + +.server { + color: #4171f5; +} + +.ata-bad { + color: #f5417d; +} + +.ata-good { + color: #4df541; +} + +.ata-ignore { + color: #f5ad41; +} diff --git a/styles/nav.scss b/styles/nav.scss new file mode 100644 index 0000000..00c660d --- /dev/null +++ b/styles/nav.scss @@ -0,0 +1,16 @@ +table.nav { + padding-right: 1px; + padding-bottom: 1px; +} + +table.nav td, +table.nav th { + display: inline-block; + margin-right: -1px; + margin-bottom: -1px; +} + +.nav a { + display: block; + padding: 4px 8px; +} diff --git a/styles/normalise.scss b/styles/normalise.scss new file mode 100644 index 0000000..3630694 --- /dev/null +++ b/styles/normalise.scss @@ -0,0 +1,351 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { + /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { + /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/styles/part.scss b/styles/part.scss new file mode 100644 index 0000000..ef27515 --- /dev/null +++ b/styles/part.scss @@ -0,0 +1,42 @@ +.part { + text-decoration: underline dotted; + text-underline-offset: 2px; + position: relative; + display: inline; + cursor: help; + background-color: #fff; + + & span { + display: block; + } + + & > span { + display: none; + position: absolute; + left: 0; + width: 100%; + top: 100%; + margin: 4px; + border: 1px solid currentColor; + padding: 8px; + background-color: inherit; + } + + & > span > span:nth-child(2n - 1) { + font-weight: 600; + } + + & > span > span:nth-child(2n) { + margin-left: 1rem; + } + + &:hover > span, + &:focus > span, + & > span:hover { + display: block; + } + + @media (prefers-color-scheme: dark) { + background-color: #000; + } +} diff --git a/styles/sidebar.scss b/styles/sidebar.scss new file mode 100644 index 0000000..bc98981 --- /dev/null +++ b/styles/sidebar.scss @@ -0,0 +1,52 @@ +.sidebar { + position: fixed; + left: 0; + top: 0; + z-index: 100; + width: 260px; + font-size: 0.875rem; + max-height: 100%; + overflow-y: auto; + + ul { + list-style: none; + margin-left: 4px; + border-left: 2px solid #aaa; + + @media (prefers-color-scheme: dark) { + border-color: #555; + } + } + li { + padding-left: 6px; + margin-left: -1px; + color: #999; + + @media (prefers-color-scheme: dark) { + color: #aaa; + } + + &.active { + padding-left: 4px; + border-left: 2px solid #f5417d; + color: #f5417d; + } + } + + a { + display: block; + padding: 4px 0 4px 6px; + font-weight: 500; + text-decoration: none; + + &, + &:visited { + color: inherit; + } + &:hover { + color: #f5417d; + } + } +} + +// @media (max-width: {} diff --git a/styles/table.scss b/styles/table.scss new file mode 100644 index 0000000..e917d8b --- /dev/null +++ b/styles/table.scss @@ -0,0 +1,54 @@ +table { + border-collapse: collapse; + // letter-spacing: 0.02em; + max-width: 100%; + overflow-x: auto; + display: block; + + &.code { + font-family: monospace; + + td, + th { + text-align: center; + } + } + & ~ table { + margin-top: 1rem; + } +} + +thead { + font-weight: bold; + border-bottom: 2px solid currentColor; +} + +td, +th { + border: 1px solid #111; + padding: 2px; + min-width: 32px; + vertical-align: top; + + & > code { + word-break: normal; + } +} + +table:not(.code) td, +table:not(.code) th { + padding: 2px 6px; +} + +.pad-row { + border-top: 2px solid currentColor; + border-bottom: 2px solid currentColor; + height: 1px; +} + +@media (prefers-color-scheme: dark) { + td, + th { + border: 1px solid #777; + } +} diff --git a/styles/type.scss b/styles/type.scss new file mode 100644 index 0000000..937b9a4 --- /dev/null +++ b/styles/type.scss @@ -0,0 +1,89 @@ +p { + word-break: break-word; +} +// a { +// color: #f5417d; +// } + +small.x-small { + font-size: 0.6em; +} + +// Typography spacing +h1, +h2, +h3, +h4, +h5, +h6 { + padding: 0; + margin: 0; +} + +h1, +h2 { + margin-top: 2.4rem; + + &:first-child { + margin-top: 1rem; + } +} + +h3, +h4, +h5, +h6 { + margin-top: 1.6rem; +} + +h1 + h2, +h2 + h3, +h3 + h4, +h4 + h5, +h5 + h6, +table { + margin-top: 0.8rem; +} + +p { + margin-top: 0.8rem; + margin-bottom: 0.8rem; + overflow-wrap: break-word; +} + +ul { + margin: 0.8rem 0 0 1.6rem; + padding: 0; +} + +ul ul { + margin: 0 0 0 1.6rem; +} + +ol { + margin: 0.8rem 0 0 2.4rem; + padding: 0; +} + +ol ol { + margin: 0 0 0 2.4rem; +} + +dfn { + border-bottom: 1px dashed currentColor; + cursor: help; +} + +@media (prefers-color-scheme: dark) { + a { + text-decoration: none; + + &, + &:visited { + color: #f5417d; + } + &:hover { + color: #dc3264; + } + } +} diff --git a/templates/base.html b/templates/base.html index 50469ff..55612dd 100644 --- a/templates/base.html +++ b/templates/base.html @@ -7,7 +7,8 @@ {% block title %}{% endblock %}{% if self.title() %} | {% endif %}{% block roottitle %}Arcade Reverse Engineering{% endblock %} - + + @@ -22,8 +23,11 @@ - {% block rootbody %}{% endblock %} - {{ generate_footer()|safe }} +
    + {% block rootbody %}{% endblock %} +
    +
    + {% include "footer.html" %} diff --git a/templates/footer.html b/templates/footer.html new file mode 100644 index 0000000..023dab4 --- /dev/null +++ b/templates/footer.html @@ -0,0 +1,13 @@ +
    + +
    \ No newline at end of file diff --git a/templates/pages/sega/hardware/keychip.html b/templates/pages/sega/hardware/keychip.html deleted file mode 100644 index b767071..0000000 --- a/templates/pages/sega/hardware/keychip.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "sega.html" %} {% block title %}Ring Keychip{% endblock %} {% block body %} -{% markdown %}{% include relative("~keychip.md") %}{% endmarkdown %} -{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/hardware/~keychip.md b/templates/pages/sega/hardware/keychip.md similarity index 100% rename from templates/pages/sega/hardware/~keychip.md rename to templates/pages/sega/hardware/keychip.md diff --git a/templates/pages/sega/hardware/touch.html b/templates/pages/sega/hardware/touch.md similarity index 70% rename from templates/pages/sega/hardware/touch.html rename to templates/pages/sega/hardware/touch.md index f6d549e..008f8e1 100644 --- a/templates/pages/sega/hardware/touch.html +++ b/templates/pages/sega/hardware/touch.md @@ -1,44 +1,25 @@ -{% extends "sega.html" %} -{% block title %}Touchscreen{% endblock %} -{% block body %} -

    The MaiMai Touchscreen

    +# The MaiMai Touchscreen -

    The touchscreen for MaiMai, pre-DX, is powered by a {{part("838-15221")|safe}} board, connected to COM3. -

    -

    Unlike other IO boards, this board communicates using a custom, text-based, protocol.

    +The touchscreen for MaiMai, pre-DX, is powered by a 838-15221 board, connected to `COM3`. -

    Serial configuartion

    - - - - - - - - - - - - - - - - - - - - - -
    PortCOM3
    Baud rate9600
    Bits per byte8
    Stop bits0
    Parity bits0
    +Unlike other IO boards, this board communicates using a custom, text-based, protocol. -

    Packet format

    -

    As previously mentioned, all packets are text. This means, for the most part, values will stay within a normal - printable range. More importantly, null bytes are not permitted as they will be interpted as the end of the string. -

    -

    Packets sent from the game to the board are surrounded in braces, {like this}. Packets sent from the - board to the game are surrounded in parentheses, (like this).

    +## Serial configuartion +| | | +| ------------- | ---- | +| Port | COM3 | +| Baud Rate | 9600 | +| Bits per byte | 8 | +| Stop bits | 0 | +| Parity bits | 0 | + +## Packet format +As previously mentioned, all packets are text. This means, for the most part, values will stay within a normal printable range. More importantly, null bytes are not permitted as they will be interpted as the end of the string. + +Packets sent from the game to the board are surrounded in braces, `{like this}`. Packets sent from the board to the game are surrounded in parentheses, `(like this)`. + +### `{HALT}` -

    {HALT}

    @@ -49,8 +30,9 @@
    {}
    -

    This instructs the board to stop sending the state of the touchscreen. No response is expected.

    -

    {STAT}

    +This instructs the board to stop sending the state of the touchscreen. No response is expected. + +### `{STAT}` @@ -61,8 +43,9 @@
    {}
    -

    This instructs the board to begin sending the state of the touchscreen (detailed below). No response is expected.

    -

    {??th}

    +This instructs the board to begin sending the state of the touchscreen (detailed below). No response is expected. + +### `{??th}` @@ -73,8 +56,7 @@
    {}
    -

    This requests the configured threshold value for a specific sensor from the board. The expected response is as - follows:

    +This requests the configured threshold value for a specific sensor from the board. The expected response is as follows: @@ -85,7 +67,8 @@
    ()
    -

    {??k?}

    + +### `{??k?}` @@ -96,7 +79,7 @@
    {}
    -

    This configures the threshold value for a specific sensor. The expected response is as follows:

    +This configures the threshold value for a specific sensor. The expected response is as follows: @@ -109,8 +92,8 @@
    (

    Active mode

    -

    After a {STAT} packet is received, the board enters a mode where it begins constantly transmitting the - state of the touchscreen. The data sent is in the following format:

    +After a `{STAT}` packet is received, the board enters a mode where it begins constantly transmitting the + state of the touchscreen. The data sent is in the following format: @@ -141,16 +124,16 @@
    -

    Each data byte is a bit mask of the 5 values it contains, mapped to 1h, - 2h, 4h, 8h, and 10h - respectively. While sending 1fh would be a valid byte, it is recommended to make use of the +Each data byte is a bit mask of the 5 values it contains, mapped to `1`~h~, + `2`~h~, `4`~h~, `8`~h~, and `10`~h~ + respectively. While sending `1f`~h~ would be a valid byte, it is recommended to make use of the upper bits to keep the value within a printable range. I personally recommend masking with - 40h ('@') for this purpose. Values will then range from @ to - _. Bits indicated with x are unused. It is recommended, but not required, to leave them + `40`~h~ (`'@'`) for this purpose. Values will then range from `@` to + `_`. Bits indicated with `x` are unused. It is recommended, but not required, to leave them unset. -

    -

    The four bytes marked as padding are unused, with the only requirement being that they are non-null. It is - recommended, but not required, to set them to 40h ('@').

    + +The four bytes marked as padding are unused, with the only requirement being that they are non-null. It is + recommended, but not required, to set them to `40`~h~ (`'@'`).
    Individual bit breakdown @@ -359,7 +342,5 @@
    -

    An example may aid here. The following image is what transmitting (FIBT@@@@@@@@) is interpreted as:

    +An example may aid here. The following image is what transmitting `(FIBT@@@@@@@@)` is interpreted as: - -{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/maimai/index.md b/templates/pages/sega/maimai/index.md new file mode 100644 index 0000000..b5cb57b --- /dev/null +++ b/templates/pages/sega/maimai/index.md @@ -0,0 +1,34 @@ +# MaiMai API Reference +This API reference is currently accurate for versions: + +- 1.97 +- 1.98 + +Support for older versions is in the works. + +## `POST /MaimaiServlet/UserLoginApi` +## `POST /MaimaiServlet/UserLogoutApi` +## `POST /MaimaiServlet/UpsertTransferApi` +## `POST /MaimaiServlet/UpsertUserAppApi` +## `POST /MaimaiServlet/GetUserActivityApi` +## `POST /MaimaiServlet/GetUserBossApi` +## `POST /MaimaiServlet/GetUserCharacterApi` +## `POST /MaimaiServlet/GetUserCourseApi` +## `POST /MaimaiServlet/GetUserDataApi` +## `POST /MaimaiServlet/GetTransferFriendApi` +## `POST /MaimaiServlet/GetUserItemApi` +## `POST /MaimaiServlet/GetUserMusicApi` +## `POST /MaimaiServlet/GetUserOptionApi` +## `POST /MaimaiServlet/GetUserPresentEventApi` +## `POST /MaimaiServlet/GetUserPreviewApi` +## `POST /MaimaiServlet/GetUserGradeApi` +## `POST /MaimaiServlet/GetUserRecentRatingApi` +## `POST /MaimaiServlet/GetUserSurvivalApi` +## `POST /MaimaiServlet/GetUserWebOptionApi` + +## `POST /MaimaiServlet/UpsertClientBookkeepingApi` +## `POST /MaimaiServlet/UpsertClientSettingApi` +## `POST /MaimaiServlet/UpsertClientTestmodeApi` +## `POST /MaimaiServlet/GetGameSettingApi` +## `POST /MaimaiServlet/GetGameEventApi` +## `POST /MaimaiServlet/GetGameRankingApi` diff --git a/templates/pages/sega/maimai/redoc.html b/templates/pages/sega/maimai/redoc.html new file mode 100644 index 0000000..ededb8d --- /dev/null +++ b/templates/pages/sega/maimai/redoc.html @@ -0,0 +1,19 @@ + + + + Maimai API Documentation + + + + + + + + + + diff --git a/templates/pages/sega/network/allnet.html b/templates/pages/sega/network/allnet.html deleted file mode 100644 index a69cb1f..0000000 --- a/templates/pages/sega/network/allnet.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "sega.html" %} {% block title %}ALL.Net{% endblock %} {% block body %} -{% markdown %}{% include relative("~allnet.md") %}{% endmarkdown %} -{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/network/allnet.html.old b/templates/pages/sega/network/allnet.html.old deleted file mode 100644 index 39aac0e..0000000 --- a/templates/pages/sega/network/allnet.html.old +++ /dev/null @@ -1,197 +0,0 @@ -{% 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

    - - - - - - - - - - - - - - - - - - - - - -
    ConnectionClose
    PragmaDFI
    User-AgentALL.Net_PC_Win2/ver1.0
    Content-Typeapplication/x-www-form-urlencoded
    Content-Lengthvariable
    -

    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:

    - - - - - - - - - - - - - - - - - - - - - -
    1Success
    0Failure
    -1Failure
    -2Failure
    -3Failure
    -

    This service provides two endpoints, documented below:

    - -

    /sys/servlet/PowerOn

    -

    Request:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    game_id4-character game ID
    ver
    serial
    ip
    firm_ver%01d%02d%02d
    boot_ver%02X%02X
    format_ver
    hops
    encode
    -

    Response:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    statSee 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/auth.html b/templates/pages/sega/network/auth.html deleted file mode 100644 index 1ed6989..0000000 --- a/templates/pages/sega/network/auth.html +++ /dev/null @@ -1,3 +0,0 @@ -{% extends "sega.html" %} {% block title %}ALL.Net Service{% endblock %} {% block body %} -{% markdown %}{% include relative("~auth.md") %}{% endmarkdown %} -{% endblock %} \ No newline at end of file diff --git a/templates/pages/sega/network/auth.md b/templates/pages/sega/network/auth.md new file mode 100644 index 0000000..2a989b1 --- /dev/null +++ b/templates/pages/sega/network/auth.md @@ -0,0 +1,149 @@ +# ALL.Net Authentication + +The ALL.Net authentication service is divided into four primary categories. They are ordered in decreasing importance on this page. + +**This entire service is HTTP-only!** + +## Auth API +These four endpoints handle the primary functions of the ALL.Net authentication service. Requests and responses are sent as a url-encoded query-value string. + +Some endpoints make use of a mildly obfuscated version of this. When the `Pragma: DFI` header is present for a request or response, it indicates that the content is a base64 encoded, deflated, version of its real value. If a request was made with `Pragma: DFI`, the response will be too. + +All responses have the `Content-Type` of `text/plain; charset=%s`, where the charset is `EUC-JP` if unspecified in the request body. + +Requests can be made using both the `GET` and `POST` verbs, and function identically. + +### `/sys/servlet/PowerOn` +All requests to this endpoint **MUST** be DFI-encoded. The request is as follows: + +| Name | Required | Default | Meaning | +| ------------ | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | +| `game_id` | Yes | | The four-digit game ID | +| `ver` | Yes | | The game version | +| `serial` | Yes | | The keychip serial number | +| `ip` | Yes | | The tenpo router IP address (%d.%d.%d.%d) | +| `firm_ver` | Yes | | The ALL.Net library version (a semantic version, formatted as %01d%02d%02d) | +| `boot_ver` | Yes | | Unknown. Just pass 0000. (%02X%02X) | +| `encode` | | `EUC-JP` | Request encoding. "EUC-JP", "Shift_JIS" and "UTF-8" are common, but be prepared to handle more. | +| `format_ver` | | `1.00` | Request format version. Parsed as a float, however "1.00", "2.00" and "3" are the only values that should be observed. | +| `hops` | | `-1` | | +| `token` | | | Added in format 3, this value is echoed in the response. | + +Observed values for `firm_ver` are listed below, however other versions likely exist: + +- 0.01.00 +- 0.02.00 +- 2.00.07 +- 2.00.08 +- 2.01.02 +- 3.00.00 +- 3.00.01 +- 3.00.02 +- 3.00.03 +- 3.00.04 +- 3.00.05 +- 3.00.09 +- 5.00.00 +- 6.00.00 + +The server should then use the provided information to authenticate the machine as it sees fit, and will then return the information required for use of ALL.Net services. The response structure varies depending on the format version in use. + +| Name | Required | Default | Version added | Final version present | Meaning | +| ----------------- | -------- | ------- | ------------- | --------------------- | ------------------------------------------------------------------------------- | +| `stat` | Yes | | | | Success: `1`, Game failure: `-1`, Machine failure: `-2`, Location failure: `-3` | +| `uri` | Yes | _empty_ | | | Title server URI1. Will be empty if stat<=0 | +| `host` | Yes | _empty_ | | | Title server hostname1. Will be empty if stat<=0 | +| `place_id` | | | | | ALL.Net location ID | +| `name` | | | | | ALL.Net location name | +| `nickname` | | | | | ALL.Net location nickname | +| `region0` | Yes | `0` | | | Region information. | +| `region_name0` | Yes | _empty_ | | | | +| `region_name1` | Yes | _empty_ | | | | +| `region_name2` | Yes | _empty_ | | | | +| `region_name3` | Yes | _empty_ | | | ^ | +| `country` | | | 2 | | ALL.Net 3-character country code | +| `allnet_id` | | | 3 | | | +| `client_timezone` | Yes | _empty_ | 3 | | Example `+0900` | +| `utc_time` | Yes | | 3 | | `yyyy-MM-dd'T'HH:mm:ss'Z'` | +| `res_ver` | Yes | | 3 | | Will always be the literal `3` | +| `token` | Yes | | 3 | | The token from the request | +| `year` | Yes | | | 2 | Current time | +| `month` | Yes | | | 2 | | +| `day` | Yes | | | 2 | | +| `hour` | Yes | | | 2 | | +| `minute` | Yes | | | 2 | ^ | +| `timezone` | Yes | | 2 | 2 | Will always be the literal `+09:00` | +| `res_class` | Yes | | 2 | 2 | Will always be the literal `PowerOnResponseVer2` | +| `setting` | Yes | | | | Machine setting. `1` indicates the machine is OK, and should always be set. | + + +1. The hostname (if) present in `uri` is used for name resolution. The value in `host` is passed to the title server in the `Host` header, and can be utilised as an extra authentication step. + +### `/sys/servlet/Alive` +There is no request for this endpoint. The response is the two bytes `OK` (that is, `Content-Length: 2`). + +### `/sys/servlet/DownloadOrder` +All requests to this endpoint **MAY** be DFI-encoded. The request is as follows: + + +| Name | Required | Default | Meaning | +| --------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | +| `game_id` | Yes | | The four-digit game ID | +| `ver` | Yes | | The game version | +| `serial` | Yes | | The keychip serial number | +| `ip` | | | The tenpo router IP address (%d.%d.%d.%d) | +| `encode` | | | Request encoding. "EUC-JP", "Shift_JIS" and "UTF-8" are common, but be prepared to handle more. | + +The response is: + + +| Name | Required | Default | Meaning | +| -------- | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | +| `stat` | Yes | | Machine setting | +| `serial` | 1 | | `,`-seperated list of the serial numbers of machines in the same store with the same game and machine group IDs. | +| `uri` | Yes1 | `null` | Download order URI(s) | + +1. Omitted if `stat` is not `1`. + +`uri` can contain both an app download order url, and an option image download order url. The two are concatinated, with the option image having `|` prefixed. That is, if only an option image is available, this will take the obscure-looking value of `|https://url.to/opt`. + +### `/sys/servlet/LoaderStateRecorder` +All requests to this endpoint **MUST NOT** be DFI-encoded. The request is as follows: + + +| Name | Required | Meaning | +| ----------- | -------- | ---------------------------------- | +| `serial` | Yes | The keychip serial number | +| `dvd` | Yes | | +| `net` | Yes | | +| `work` | Yes | | +| `old_net` | Yes | | +| `deliver` | Yes | | +| `nb_ftd` | Yes | Number of files to download | +| `nb_dld` | Yes | Number of files downloaded | +| `last_sysa` | Yes | Last authentication unix timestamp | +| `sysa_st` | Yes | Last authentication state | +| `dld_st` | Yes | Download state | + +The response is either `OK` if the request was formatted correctly, otherwise `NG`. + +## Report API +Used to report download status for an ongoing network-based game delivery, this category contains just a single endpoint. + +### `/sys/servlet/Report` + +## Title API +These legacy endpoints are used to request title-specific information. I've not seen any games use these, and they're a low priority for documentation. + +### `/sys/servlet/GetMachineList` +### `/sys/servlet/GetPlaceList` +### `/sys/servlet/GetRegionList` +### `/sys/servlet/MachineTable` +### `/sys/servlet/PlaceRegionTable` +### `/sys/servlet/PlaceRegionTableAll` + +## Admin API +These endpoints are used for ALL.Net system administration and are not of interest. Their endpoints are recorded here for prosperity. Custom network authors should consider implementing their own administration functionality however best suits their architecture. + +### `/sys/servlet/AdminRegister` +### `/sys/servlet/AdminView` diff --git a/templates/pages/sega/network/billing.md b/templates/pages/sega/network/billing.md new file mode 100644 index 0000000..9d479bd --- /dev/null +++ b/templates/pages/sega/network/billing.md @@ -0,0 +1,7 @@ +# ALL.Net Billing + +The ALL.Net billing service is provided by `ib.naominet.jp`, and is a single HTTPS endpoint running on port `8443`. This port number is hardcoded in games. + +## `POST /request/`, `POST /request`, `POST /request.php` +This endpoint is accessible at three URIs, which all function identically. + diff --git a/templates/pages/sega/network/index.html b/templates/pages/sega/network/index.html deleted file mode 100644 index ba29e88..0000000 --- a/templates/pages/sega/network/index.html +++ /dev/null @@ -1,6 +0,0 @@ -{% 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/network/~allnet.md b/templates/pages/sega/network/index.md similarity index 98% rename from templates/pages/sega/network/~allnet.md rename to templates/pages/sega/network/index.md index 7c2ca97..c362973 100644 --- a/templates/pages/sega/network/~allnet.md +++ b/templates/pages/sega/network/index.md @@ -5,7 +5,7 @@ ALL.Net, short for Amusement Linkage Live Network, is SEGA's standadised arcade The ALL.Net model is compresed of four networked services: 1. [Authentication. This is `naominet.jp`, and handles basic operations.](./auth) -2. The billing service. This is `ib.naominet.jp`, and handles tracking and updating play counters. +2. [The billing service. This is `ib.naominet.jp`, and handles tracking and updating play counters.](./billing) 3. AiMeDB. This is `aime.naominet.jp`, and handles user management. 4. The title server. The URL for this is provided by ALL.Net, as different games use different services for this. diff --git a/templates/pages/sega/network/~auth.md b/templates/pages/sega/network/~auth.md deleted file mode 100644 index f689c5b..0000000 --- a/templates/pages/sega/network/~auth.md +++ /dev/null @@ -1,149 +0,0 @@ -# ALL.Net Authentication - -The ALL.Net authentication service is divided into four primary categories. They are ordered in decreasing importance on this page. - -**This entire service is HTTP-only!** - -## Auth API -These four endpoints handle the primary functions of the ALL.Net authentication service. Requests and responses are sent as a url-encoded query-value string. - -Some endpoints make use of a mildly obfuscated version of this. When the `Pragma: DFI` header is present for a request or response, it indicates that the content is a base64 encoded, deflated, version of its real value. If a request was made with `Pragma: DFI`, the response will be too. - -All responses have the `Content-Type` of `text/plain; charset=%s`, where the charset is `EUC-JP` if unspecified in the request body. - -Requests can be made using both the `GET` and `POST` verbs, and function identically. - -### `/sys/servlet/PowerOn` -All requests to this endpoint **MUST** be DFI-encoded. The request is as follows: - -| Name | Required | Default | Meaning | -| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | -| game_id | Yes | | The four-digit game ID | -| ver | Yes | | The game version | -| serial | Yes | | The keychip serial number | -| ip | Yes | | The tenpo router IP address (%d.%d.%d.%d) | -| firm_ver | Yes | | The ALL.Net library version (a semantic version, formatted as %01d%02d%02d) | -| boot_ver | Yes | | Unknown. Just pass 0000. (%02X%02X) | -| encode | | EUC-JP | Request encoding. "EUC-JP", "Shift_JIS" and "UTF-8" are common, but be prepared to handle more. | -| format_ver | | 1.00 | Request format version. Parsed as a float, however "1.00", "2.00" and "3" are the only values that should be observed. | -| hops | | -1 | | -| token | | | Added in format 3, this value is echoed in the response. | - -Observed values for `firm_ver` are listed below, however other versions likely exist: - -- 0.01.00 -- 0.02.00 -- 2.00.07 -- 2.00.08 -- 2.01.02 -- 3.00.00 -- 3.00.01 -- 3.00.02 -- 3.00.03 -- 3.00.04 -- 3.00.05 -- 3.00.09 -- 5.00.00 -- 6.00.00 - -The server should then use the provided information to authenticate the machine as it sees fit, and will then return the information required for use of ALL.Net services. The response structure varies depending on the format version in use. - -| Name | Required | Default | Version added | Final version present | Meaning | -| --------------- | -------- | ------- | ------------- | --------------------- | ------------------------------------------------------------------------------- | -| stat | Yes | | | | Success: `1`, Game failure: `-1`, Machine failure: `-2`, Location failure: `-3` | -| uri | Yes | _empty_ | | | Title server URI1. Will be empty if stat<=0 | -| host | Yes | _empty_ | | | Title server hostname1. Will be empty if stat<=0 | -| place_id | | | | | ALL.Net location ID | -| name | | | | | ALL.Net location name | -| nickname | | | | | ALL.Net location nickname | -| region0 | Yes | `0` | | | Region information. | -| region_name0 | Yes | _empty_ | | | | -| region_name1 | Yes | _empty_ | | | | -| region_name2 | Yes | _empty_ | | | | -| region_name3 | Yes | _empty_ | | | ^ | -| country | | | 2 | | ALL.Net 3-character country code | -| allnet_id | | | 3 | | | -| client_timezone | Yes | _empty_ | 3 | | Example `+0900` | -| utc_time | Yes | | 3 | | `yyyy-MM-dd'T'HH:mm:ss'Z'` | -| res_ver | Yes | | 3 | | Will always be the literal `3` | -| token | Yes | | 3 | | The token from the request | -| year | Yes | | | 2 | Current time | -| month | Yes | | | 2 | | -| day | Yes | | | 2 | | -| hour | Yes | | | 2 | | -| minute | Yes | | | 2 | ^ | -| timezone | Yes | | 2 | 2 | Will always be the literal `+09:00` | -| res_class | Yes | | 2 | 2 | Will always be the literal `PowerOnResponseVer2` | -| setting | Yes | | | | Machine setting. `1` indicates the machine is OK, and should always be set. | - - -1. The hostname (if) present in `uri` is used for name resolution. The value in `host` is passed to the title server in the `Host` header, and can be utilised as an extra authentication step. - -### `/sys/servlet/Alive` -There is no request for this endpoint. The response is the two bytes `OK` (that is, `Content-Length: 2`). - -### `/sys/servlet/DownloadOrder` -All requests to this endpoint **MAY** be DFI-encoded. The request is as follows: - - -| Name | Required | Default | Meaning | -| ------- | -------- | ------- | ----------------------------------------------------------------------------------------------- | -| game_id | Yes | | The four-digit game ID | -| ver | Yes | | The game version | -| serial | Yes | | The keychip serial number | -| ip | Yes | | The tenpo router IP address (%d.%d.%d.%d) | -| encode | | | Request encoding. "EUC-JP", "Shift_JIS" and "UTF-8" are common, but be prepared to handle more. | - -The response is: - - -| Name | Required | Default | Meaning | -| ------ | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | -| stat | Yes | | Machine setting | -| serial | 1 | | `,`-seperated list of the serial numbers of machines in the same store with the same game and machine group IDs. | -| uri | Yes1 | `null` | Download order URI(s) | - -1. Omitted if `stat` is not `1`. - -`uri` can contain both an app download order url, and an option image download order url. The two are concatinated, with the option image having `|` prefixed. That is, if only an option image is available, this will take the obscure-looking value of `|https://url.to/opt`. - -### `/sys/servlet/LoaderStateRecorder` -All requests to this endpoint **MUST NOT** be DFI-encoded. The request is as follows: - - -| Name | Required | Meaning | -| --------- | -------- | ---------------------------------- | -| serial | Yes | The keychip serial number | -| dvd | Yes | | -| net | Yes | | -| work | Yes | | -| old_net | Yes | | -| deliver | Yes | | -| nb_ftd | Yes | Number of files to download | -| nb_dld | Yes | Number of files downloaded | -| last_sysa | Yes | Last authentication unix timestamp | -| sysa_st | Yes | Last authentication state | -| dld_st | Yes | Download state | - -The response is either `OK` if the request was formatted correctly, otherwise `NG`. - -## Report API -Used to report download status for an ongoing network-based game delivery, this category contains just a single endpoint. - -### `/sys/servlet/Report` - -## Title API -These legacy endpoints are used to request title-specific information. I've not seen any games use these, and they're a low priority for documentation. - -### `/sys/servlet/GetMachineList` -### `/sys/servlet/GetPlaceList` -### `/sys/servlet/GetRegionList` -### `/sys/servlet/MachineTable` -### `/sys/servlet/PlaceRegionTable` -### `/sys/servlet/PlaceRegionTableAll` - -## Admin API -These endpoints are used for ALL.Net system administration and are not of interest. Their endpoints are recorded here for prosperity. Custom network authors should consider implementing their own administration functionality however best suits their architecture. - -### `/sys/servlet/AdminRegister` -### `/sys/servlet/AdminView` diff --git a/templates/sega.html b/templates/sega.html index cc5a8f7..bbe1348 100644 --- a/templates/sega.html +++ b/templates/sega.html @@ -5,6 +5,7 @@ Contents Intro + Networking Software Hardware Manual