mirror of
https://gitea.tendokyu.moe/eamuse/docs.git
synced 2024-11-12 01:10:48 +01:00
Styles stuff
This commit is contained in:
parent
94a1b713e4
commit
12832ca73b
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
__pycache__/
|
||||
build/
|
||||
kcf/
|
||||
static/main.css
|
||||
|
202
docs.py
202
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 += "<li>"
|
||||
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 = "<footer><span>"
|
||||
links: dict[str, Any] = dict(footer_previous="", footer_crumbs=[], footer_current="", footer_next="")
|
||||
|
||||
if siblings and us_idx > 0:
|
||||
footer += f'<a href="{parent}{siblings[us_idx - 1]}">Previous page</a>'
|
||||
footer += "</span><span>"
|
||||
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'<a href="{built}">{i}</a>')
|
||||
crumbs.append(parts[-1])
|
||||
footer += "/".join(crumbs)
|
||||
|
||||
footer += "</span><span>"
|
||||
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'<a href="{parent}{siblings[us_idx + 1]}">Next page</a>'
|
||||
links["footer_next"] = parent + siblings[us_idx + 1]
|
||||
|
||||
footer += "</span></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)
|
||||
|
||||
|
||||
|
87
headers.js
87
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);
|
||||
|
91
main.scss
Normal file
91
main.scss
Normal file
@ -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
|
4
start_ea.cmd
Normal file
4
start_ea.cmd
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
set EA_PROOT=pages/eamuse
|
||||
set EA_HOST=127.0.0.1:3000
|
||||
py docs.py
|
4
start_sega.cmd
Normal file
4
start_sega.cmd
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
set EA_PROOT=pages/sega
|
||||
set EA_HOST=127.0.0.1:3000
|
||||
py docs.py
|
@ -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 {
|
61
styles/code.scss
Normal file
61
styles/code.scss
Normal file
@ -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);
|
||||
}
|
||||
}
|
99
styles/collapse.scss
Normal file
99
styles/collapse.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
31
styles/footer.scss
Normal file
31
styles/footer.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
styles/misc.scss
Normal file
19
styles/misc.scss
Normal file
@ -0,0 +1,19 @@
|
||||
.client {
|
||||
color: #f5417d;
|
||||
}
|
||||
|
||||
.server {
|
||||
color: #4171f5;
|
||||
}
|
||||
|
||||
.ata-bad {
|
||||
color: #f5417d;
|
||||
}
|
||||
|
||||
.ata-good {
|
||||
color: #4df541;
|
||||
}
|
||||
|
||||
.ata-ignore {
|
||||
color: #f5ad41;
|
||||
}
|
16
styles/nav.scss
Normal file
16
styles/nav.scss
Normal file
@ -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;
|
||||
}
|
351
styles/normalise.scss
Normal file
351
styles/normalise.scss
Normal file
@ -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;
|
||||
}
|
42
styles/part.scss
Normal file
42
styles/part.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
52
styles/sidebar.scss
Normal file
52
styles/sidebar.scss
Normal file
@ -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: {}
|
54
styles/table.scss
Normal file
54
styles/table.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
89
styles/type.scss
Normal file
89
styles/type.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}{% endblock %}{% if self.title() %} | {% endif %}{% block roottitle %}Arcade Reverse Engineering{% endblock %}</title>
|
||||
|
||||
<link rel="stylesheet" href="{{ROOT}}/styles.css?ver=16">
|
||||
<!-- <link rel="stylesheet" href="{{ROOT}}/styles.css?ver=16"> -->
|
||||
<link rel="stylesheet" href="{{ROOT}}/static/main.css">
|
||||
<link rel="stylesheet" href="{{ROOT}}/tango.css">
|
||||
<link rel="canonical" href="{{CANONICAL}}" />
|
||||
|
||||
@ -22,8 +23,11 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block rootbody %}{% endblock %}
|
||||
{{ generate_footer()|safe }}
|
||||
<div id="root">
|
||||
{% block rootbody %}{% endblock %}
|
||||
</div>
|
||||
<div id="gap"></div>
|
||||
{% include "footer.html" %}
|
||||
<script src="{{ROOT}}/headers.js?v=1"></script>
|
||||
</body>
|
||||
|
||||
|
13
templates/footer.html
Normal file
13
templates/footer.html
Normal file
@ -0,0 +1,13 @@
|
||||
<footer>
|
||||
<div class="footer-inner">
|
||||
<div class="footer-links">
|
||||
<span>{%if footer_previous %}<a href="{{footer_previous}}">Previous page</a>{% endif %}</span>
|
||||
|
||||
<span>
|
||||
{% for crumb in footer_crumbs %}<a href="{{crumb[0]}}">{{crumb[1]}}</a>/{% endfor %}{{footer_current}}
|
||||
</span>
|
||||
|
||||
<span>{%if footer_next %}<a href="{{footer_next}}">Next page</a>{% endif %}</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
@ -1,3 +0,0 @@
|
||||
{% extends "sega.html" %} {% block title %}Ring Keychip{% endblock %} {% block body %}
|
||||
{% markdown %}{% include relative("~keychip.md") %}{% endmarkdown %}
|
||||
{% endblock %}
|
@ -1,44 +1,25 @@
|
||||
{% extends "sega.html" %}
|
||||
{% block title %}Touchscreen{% endblock %}
|
||||
{% block body %}
|
||||
<h1>The MaiMai Touchscreen</h1>
|
||||
# The MaiMai Touchscreen
|
||||
|
||||
<p>The touchscreen for MaiMai, pre-DX, is powered by a {{part("838-15221")|safe}} board, connected to <code>COM3</code>.
|
||||
</p>
|
||||
<p>Unlike other IO boards, this board communicates using a custom, text-based, protocol.</p>
|
||||
The touchscreen for MaiMai, pre-DX, is powered by a 838-15221 board, connected to `COM3`.
|
||||
|
||||
<h2 id="serial">Serial configuartion</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Port</td>
|
||||
<td>COM3</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Baud rate</td>
|
||||
<td>9600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bits per byte</td>
|
||||
<td>8</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stop bits</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Parity bits</td>
|
||||
<td>0</td>
|
||||
</tr>
|
||||
</table>
|
||||
Unlike other IO boards, this board communicates using a custom, text-based, protocol.
|
||||
|
||||
<h2 id="packet">Packet format</h2>
|
||||
<p>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.
|
||||
</p>
|
||||
<p>Packets sent from the game to the board are surrounded in braces, <code>{like this}</code>. Packets sent from the
|
||||
board to the game are surrounded in parentheses, <code>(like this)</code>.</p>
|
||||
## 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}`
|
||||
|
||||
<h3 id="halt"><code>{HALT}</code></h3>
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>{</code></td>
|
||||
@ -49,8 +30,9 @@
|
||||
<td><code>}</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This instructs the board to stop sending the state of the touchscreen. No response is expected.</p>
|
||||
<h3 id="stat"><code>{STAT}</code></h3>
|
||||
This instructs the board to stop sending the state of the touchscreen. No response is expected.
|
||||
|
||||
### `{STAT}`
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>{</code></td>
|
||||
@ -61,8 +43,9 @@
|
||||
<td><code>}</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This instructs the board to begin sending the state of the touchscreen (detailed below). No response is expected.</p>
|
||||
<h3 id="xxth"><code>{??th}</code></h3>
|
||||
This instructs the board to begin sending the state of the touchscreen (detailed below). No response is expected.
|
||||
|
||||
### `{??th}`
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>{</code></td>
|
||||
@ -73,8 +56,7 @@
|
||||
<td><code>}</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This requests the configured threshold value for a specific sensor from the board. The expected response is as
|
||||
follows:</p>
|
||||
This requests the configured threshold value for a specific sensor from the board. The expected response is as follows:
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>(</code></td>
|
||||
@ -85,7 +67,8 @@
|
||||
<td><code>)</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3 id="xxth"><code>{??k?}</code></h3>
|
||||
|
||||
### `{??k?}`
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>{</code></td>
|
||||
@ -96,7 +79,7 @@
|
||||
<td><code>}</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This configures the threshold value for a specific sensor. The expected response is as follows:</p>
|
||||
This configures the threshold value for a specific sensor. The expected response is as follows:
|
||||
<table class="code">
|
||||
<tr>
|
||||
<td><code>(</code></td>
|
||||
@ -109,8 +92,8 @@
|
||||
</table>
|
||||
|
||||
<h2 id="push">Active mode</h2>
|
||||
<p>After a <code>{STAT}</code> 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:</p>
|
||||
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:
|
||||
|
||||
<table class="code">
|
||||
<tr>
|
||||
@ -141,16 +124,16 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Each data byte is a bit mask of the 5 values it contains, mapped to <code>1<sub>h</sub></code>,
|
||||
<code>2<sub>h</sub></code>, <code>4<sub>h</sub></code>, <code>8<sub>h</sub></code>, and <code>10<sub>h</sub></code>
|
||||
respectively. While sending <code>1f<sub>h</sub></code> 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
|
||||
<code>40<sub>h</sub></code> (<code>'@'</code>) for this purpose. Values will then range from <code>@</code> to
|
||||
<code>_</code>. Bits indicated with <code>x</code> 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.
|
||||
</p>
|
||||
<p>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 <code>40<sub>h</sub></code> (<code>'@'</code>).</p>
|
||||
|
||||
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~ (`'@'`).
|
||||
|
||||
<details>
|
||||
<summary>Individual bit breakdown</summary>
|
||||
@ -359,7 +342,5 @@
|
||||
</table>
|
||||
</details>
|
||||
|
||||
<p>An example may aid here. The following image is what transmitting <code>(FIBT@@@@@@@@)</code> is interpreted as:</p>
|
||||
An example may aid here. The following image is what transmitting `(FIBT@@@@@@@@)` is interpreted as:
|
||||
<img src="{{ROOT}}/images/maimai_FIBT.png" class="graphic">
|
||||
|
||||
{% endblock %}
|
34
templates/pages/sega/maimai/index.md
Normal file
34
templates/pages/sega/maimai/index.md
Normal file
@ -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`
|
19
templates/pages/sega/maimai/redoc.html
Normal file
19
templates/pages/sega/maimai/redoc.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Maimai API Documentation</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<redoc spec-url="http://134.65.56.170/MaimaiServlet/spec.json"></redoc>
|
||||
<script src="https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +0,0 @@
|
||||
{% extends "sega.html" %} {% block title %}ALL.Net{% endblock %} {% block body %}
|
||||
{% markdown %}{% include relative("~allnet.md") %}{% endmarkdown %}
|
||||
{% endblock %}
|
@ -1,197 +0,0 @@
|
||||
{% extends "sega.html" %}
|
||||
{% block title %}ALL.Net{% endblock %}
|
||||
{% block body %}
|
||||
<h1>ALL.Net</h1>
|
||||
<p>A simple service that exposes two URLs. The hostname must be <code>http://naominet.jp</code>.</p>
|
||||
|
||||
<p>Requests should be made with a number of standard HTTP headers, and must be either HTTP version 1.0 or 1.1</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>Connection</code></td>
|
||||
<td><code>Close</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Pragma</code></td>
|
||||
<td><code>DFI</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>User-Agent</code></td>
|
||||
<td><code>ALL.Net_PC_Win2/ver1.0</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Content-Type</code></td>
|
||||
<td><code>application/x-www-form-urlencoded</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Content-Length</code></td>
|
||||
<td><i>variable</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Note that the <code>Pragma</code> header is optional, and the <code>Content-Type</code> header is a lie.</p>
|
||||
|
||||
<p>Requests and responses should be <code>POST</code>s, and their body should be base64 encoded, zlib compressed,
|
||||
<code>x-www-form-urlencoded</code> data. For example, <code>{key: "value", other: "another"}</code> should encode to
|
||||
<code>eJwdxcEJACAMA8Bt3CLD5BEQFIXSFtw+4OuWHpq7NG5OBXi+BmwzCRo=</code>.
|
||||
</p>
|
||||
|
||||
<p>Responses are expected to contain <code>stat</code> indicating status:</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>1</code></td>
|
||||
<td>Success</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>0</code></td>
|
||||
<td>Failure</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-1</code></td>
|
||||
<td>Failure</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-2</code></td>
|
||||
<td>Failure</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>-3</code></td>
|
||||
<td>Failure</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>This service provides two endpoints, documented below:</p>
|
||||
|
||||
<h3><code>/sys/servlet/PowerOn</code></h3>
|
||||
<h4>Request:</h4>
|
||||
<!--
|
||||
"game_id=%s&ver=%s&serial=%s&ip=%s&firm_ver=%01d%02d%02d&boot_ver=%02X%02X&encode=%s&format_ver=%s&hops=%d\r\n"
|
||||
"game_id=%s&ver=%s&serial=%s&ip=%s&firm_ver=%01d%02d%02d&boot_ver=%02X%02X&format_ver=%s&hops=%d\r\n"
|
||||
"game_id=%s&ver=%s&serial=%s\r\n"
|
||||
"game_id=%s&ver=%s&serial=%s&encode=%s\r\n"
|
||||
|
||||
|
||||
"keychipid=%s&functype=%u&gameid=%s&gamever=%s&boardid=%s&tenpoip=%s&libalibver=%s&datamax=%s&billingtype=%d&protocolver=%s&operatingfix=%d"
|
||||
(libalibver = 1.110, protocolver = 1.000)
|
||||
|
||||
SDBT: Chunithm
|
||||
SBXL: Maimai -->
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>game_id</code></td>
|
||||
<td>4-character game ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ver</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>serial</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ip</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>firm_ver</code></td>
|
||||
<td><code>%01d%02d%02d</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>boot_ver</code></td>
|
||||
<td><code>%02X%02X</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>format_ver</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>hops</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>encode</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h4>Response:</h4>
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>stat</code></td>
|
||||
<td>See above</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>uri</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>host</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>region0</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>region_name0</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>region_name1</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>region_name2</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>region_name3</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>year</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>month</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>day</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>hour</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>minute</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>second</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>place_id</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>setting</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>country</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>timezone</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>res_class</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3><code>/sys/servlet/DownloadOrder</code></h3>
|
||||
|
||||
{% endblock %}
|
@ -1,3 +0,0 @@
|
||||
{% extends "sega.html" %} {% block title %}ALL.Net Service{% endblock %} {% block body %}
|
||||
{% markdown %}{% include relative("~auth.md") %}{% endmarkdown %}
|
||||
{% endblock %}
|
149
templates/pages/sega/network/auth.md
Normal file
149
templates/pages/sega/network/auth.md
Normal file
@ -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 URI<sup>1</sup>. Will be empty if stat<=0 |
|
||||
| `host` | Yes | _empty_ | | | Title server hostname<sup>1</sup>. 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` | <sup>1</sup> | | `,`-seperated list of the serial numbers of machines in the same store with the same game and machine group IDs. |
|
||||
| `uri` | Yes<sup>1</sup> | `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`
|
7
templates/pages/sega/network/billing.md
Normal file
7
templates/pages/sega/network/billing.md
Normal file
@ -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.
|
||||
|
@ -1,6 +0,0 @@
|
||||
{% extends "sega.html" %}
|
||||
{% block title %}Networking{% endblock %}
|
||||
{% block body %}
|
||||
<h1>Networking</h1>
|
||||
{{ generate_toc()|safe }}
|
||||
{% endblock %}
|
@ -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.
|
||||
|
@ -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 URI<sup>1</sup>. Will be empty if stat<=0 |
|
||||
| host | Yes | _empty_ | | | Title server hostname<sup>1</sup>. 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 | <sup>1</sup> | | `,`-seperated list of the serial numbers of machines in the same store with the same game and machine group IDs. |
|
||||
| uri | Yes<sup>1</sup> | `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`
|
@ -5,6 +5,7 @@
|
||||
<tr>
|
||||
<td><a href="{{ROOT}}/">Contents</a></td>
|
||||
<td><a href="{{ROOT}}/intro">Intro</a></td>
|
||||
<td><a href="{{ROOT}}/network/">Networking</a></td>
|
||||
<td><a href="{{ROOT}}/software/">Software</a></td>
|
||||
<td><a href="{{ROOT}}/hardware/">Hardware</a></td>
|
||||
<td><a href="{{ROOT}}/manual/">Manual</a></td>
|
||||
|
Loading…
Reference in New Issue
Block a user