diff --git a/README.md b/README.md
index 978fd94..8ca2af9 100644
--- a/README.md
+++ b/README.md
@@ -4,15 +4,15 @@ e-amusement server using [FastAPI](https://github.com/tiangolo/fastapi) and [Tin
for experimental local testing and playing
-**don't host it publicly as-is**
+**don't host it publicly as-is. security and privacy features aren't implemented. tinydb can't handle many users.**
## Instructions
-1. Install [python](https://www.python.org/ftp/python/3.11.4/python-3.11.4-amd64.exe) with "Add python.exe to PATH" checked
+1. Install [python](https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe) with "Add python.exe to PATH" checked
1. Run [start.bat (Windows)](start.bat) or [start.sh (Linux)](start.sh)
-1. Edit prop/ea3-config.xml services *url* and url_slash *1*
+1. Set services *url* in tools or prop/ea3-config.xml
## Playable Games
@@ -39,7 +39,7 @@ for experimental local testing and playing
## Troubleshooting
-- **URL Slash 1 (On)** must be enabled in tools or ea3-config
+- Set **URL Slash 1 (On)** in tools or ea3-config [if a supported game breaks without it](modules/__init__.py#L44)
- GITADORA requires `mdb_*.xml` copied to the server folder
diff --git a/modules/__init__.py b/modules/__init__.py
index 0553b9e..d0dbeab 100644
--- a/modules/__init__.py
+++ b/modules/__init__.py
@@ -2,6 +2,9 @@ from importlib import util
from os import path
from glob import glob
+from fastapi import APIRouter, Request
+from typing import Optional
+
routers = []
for module_path in [
f
@@ -15,3 +18,64 @@ for module_path in [
router = getattr(module, "router", None)
if router is not None:
routers.append(router)
+
+ if path.basename(module_path) != "api.py":
+ for obj in dir(module):
+ globals()[obj] = module.__dict__[obj]
+
+router = APIRouter(tags=["slashless_forwarder"])
+
+
+@router.post("/core_fwdr")
+async def forward_core(
+ request: Request,
+ f: Optional[str] = None,
+ module: Optional[str] = None,
+ method: Optional[str] = None,
+):
+ if f != None:
+ module, method = f.split(".")
+
+ find_response = globals()[f"{module}_{method}"]
+
+ return await find_response(request)
+
+
+@router.post("/fwdr")
+async def forward_game(
+ request: Request,
+ model: Optional[str] = None,
+ f: Optional[str] = None,
+ module: Optional[str] = None,
+ method: Optional[str] = None,
+):
+ if f != None:
+ module, method = f.split(".")
+
+ game_code = model.split(":")[0]
+
+ # TODO: check for more edge cases
+ try:
+ if game_code == "MDX" and module == "eventlog" or module == "eventlog_2":
+ find_response = globals()[f"ddr_{module}_{method}"]
+ elif game_code == "REC":
+ find_response = globals()[f"drs_{module}_{method}"]
+ elif game_code == "KFC" and module == "eventlog":
+ find_response = globals()[f"sdvx_{module}_{method}"]
+ elif game_code == "M32":
+ if module == "lobby":
+ find_response = globals()[f"gitadora_{module}_{method}"]
+ else:
+ gd_module = module.split("_")
+ find_response = globals()[f"gitadora_{gd_module[-1]}_{method}"]
+ return await find_response(gd_module[0], request)
+ else:
+ find_response = globals()[f"{module}_{method}".lower()]
+ except KeyError:
+ print("Try URL Slash 1 (On) if this game is supported.")
+ return Response(status_code=404)
+
+ return await find_response(request)
+
+
+routers.append(router)
diff --git a/modules/ddr/playerdata.py b/modules/ddr/playerdata.py
index 94668e8..083f577 100644
--- a/modules/ddr/playerdata.py
+++ b/modules/ddr/playerdata.py
@@ -35,7 +35,7 @@ def get_common(ddr_id, game_version, idx):
@router.post("/{gameinfo}/playerdata/usergamedata_advanced")
-async def usergamedata_advanced(request: Request):
+async def playerdata_usergamedata_advanced(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
is_omni = True if request_info["rev"] == "O" else False
@@ -541,7 +541,7 @@ async def usergamedata_advanced(request: Request):
@router.post("/{gameinfo}/playerdata/usergamedata_recv")
-async def usergamedata_recv(request: Request):
+async def playerdata_usergamedata_recv(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
@@ -651,7 +651,7 @@ async def usergamedata_recv(request: Request):
@router.post("/{gameinfo}/playerdata/usergamedata_send")
-async def usergamedata_send(request: Request):
+async def playerdata_usergamedata_send(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
diff --git a/modules/ddr/playerdata_2.py b/modules/ddr/playerdata_2.py
index 383cd82..dfcb2a5 100644
--- a/modules/ddr/playerdata_2.py
+++ b/modules/ddr/playerdata_2.py
@@ -35,7 +35,7 @@ def get_common(ddr_id, game_version, idx):
@router.post("/{gameinfo}/playerdata_2/usergamedata_advanced")
-async def usergamedata_advanced(request: Request):
+async def playerdata_2_usergamedata_advanced(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
is_omni = True if request_info["rev"] == "O" else False
@@ -578,7 +578,7 @@ async def usergamedata_advanced(request: Request):
@router.post("/{gameinfo}/playerdata_2/usergamedata_recv")
-async def usergamedata_recv(request: Request):
+async def playerdata_2_usergamedata_recv(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
@@ -688,7 +688,7 @@ async def usergamedata_recv(request: Request):
@router.post("/{gameinfo}/playerdata_2/usergamedata_send")
-async def usergamedata_send(request: Request):
+async def playerdata_2_usergamedata_send(request: Request):
request_info = await core_process_request(request)
game_version = request_info["game_version"]
diff --git a/modules/iidx/iidx30gamesystem.py b/modules/iidx/iidx30gamesystem.py
index 1077fa5..190b81a 100644
--- a/modules/iidx/iidx30gamesystem.py
+++ b/modules/iidx/iidx30gamesystem.py
@@ -17,7 +17,7 @@ async def iidx30gamesystem_systeminfo(request: Request):
unlock = ()
# force unlock LM exclusives to complete unlock all songs server side
# this makes LM exclusive folder disappear, so just use hex edits
- # unlock = (28073, 28008, 29095, 29094, 29027, 30077, 30076, 30098)
+ # unlock = (28073, 28008, 29095, 29094, 29027, 30077, 30076, 30098, 30106, 30107, 30028, 30064, 30027)
current_time = round(time())
diff --git a/modules/iidx/iidx30pc.py b/modules/iidx/iidx30pc.py
index 1ce7aac..c3f6c90 100644
--- a/modules/iidx/iidx30pc.py
+++ b/modules/iidx/iidx30pc.py
@@ -274,7 +274,7 @@ async def iidx30pc_get(request: Request):
tour_id=i,
progress=50, # set to 49 to see WT folders, 50 is completed/hidden
)
- for i in range(13)
+ for i in range(16)
],
),
E.lightning_setting(
@@ -433,6 +433,8 @@ async def iidx30pc_get(request: Request):
E.valkyrie_linkage(music_list_1=-1, music_list_2=-1, music_list_3=-1),
E.bemani_song_battle(music_list=-1),
E.bemani_mixup(music_list=-1),
+ E.ccj_linkage(music_list=-1),
+ E.triple_tribe(music_list=-1),
E.achievements(
E.trophy(profile.get("achievements_trophy", [])[:10], __type="s64"),
pack=profile.get("achievements_pack_id", 0),
@@ -787,6 +789,7 @@ async def iidx30pc_common(request: Request):
# E.fps_fix(),
# E.save_unsync_log(),
E.tourism_booster(),
+ E.ameto_event(),
expire=600,
)
)
diff --git a/pyeamu.py b/pyeamu.py
index 515f583..3ca308b 100644
--- a/pyeamu.py
+++ b/pyeamu.py
@@ -1,9 +1,10 @@
-from urllib.parse import urlunparse, urlencode
+from urllib.parse import urlparse, urlunparse, urlencode
import uvicorn
import ujson as json
from os import name, path
+from typing import Optional
from fastapi import FastAPI, Request, Response
from fastapi.middleware.cors import CORSMiddleware
@@ -16,16 +17,24 @@ import utils.card as conv
from core_common import core_process_request, core_prepare_response, E
+import socket
+
def urlpathjoin(parts, sep="/"):
return sep + sep.join([x.lstrip(sep) for x in parts])
-server_address = f"{config.ip}:{config.port}"
-server_services_url = urlunparse(
- ("http", server_address, config.services_prefix, None, None, None)
-)
-keepalive_address = "127.0.0.1"
+loopback = "127.0.0.1"
+
+server_addresses = []
+for host in ("localhost", config.ip, socket.gethostname()):
+ server_addresses.append(f"{host}:{config.port}")
+
+server_services_urls = []
+for server_address in server_addresses:
+ server_services_urls.append(
+ urlunparse(("http", server_address, config.services_prefix, None, None, None))
+ )
settings = {}
for s in (
@@ -85,23 +94,36 @@ if __name__ == "__main__":
)
print()
print("\033[1mGame Config\033[0m:")
- print(f"\033[92m{server_services_url}\033[0m")
- print('\033[92m1\033[0m')
+ for server_services_url in server_services_urls:
+ print(f"\033[92m{server_services_url}\033[0m")
+ print("")
+ # print('\033[92m0\033[0m')
+ # print('\033[92m1\033[0m')
print()
if webui:
print("\033[1mWeb Interface\033[0m:")
- print(f"http://{server_address}/webui/")
+ for server_address in server_addresses:
+ print(f"http://{server_address}/webui/")
print()
print("\033[1mSource Repository\033[0m:")
print("https://github.com/drmext/MonkeyBusiness")
print()
- uvicorn.run("pyeamu:app", host=config.ip, port=config.port, reload=True)
+ uvicorn.run("pyeamu:app", host="0.0.0.0", port=config.port, reload=True)
+@app.post(urlpathjoin([config.services_prefix]))
@app.post(urlpathjoin([config.services_prefix, "/{gameinfo}/services/get"]))
-async def services_get(request: Request):
+async def services_get(
+ request: Request,
+ model: Optional[str] = None,
+ f: Optional[str] = None,
+ module: Optional[str] = None,
+ method: Optional[str] = None,
+):
request_info = await core_process_request(request)
+ request_address = f"{urlparse(str(request.url)).netloc}:{config.port}"
+
services = {}
for service in modules.routers:
@@ -114,24 +136,42 @@ async def services_get(request: Request):
if model_whitelist and request_info["model"] not in model_whitelist:
continue
+ if (
+ service.tags
+ and service.tags[0].startswith("api_")
+ or service.tags[0] == "slashless_forwarder"
+ ):
+ continue
+
k = (service.tags[0] if service.tags else service.prefix).strip("/")
- if k not in services:
- services[k] = urlunparse(
- ("http", server_address, service.prefix, None, None, None)
- )
+ if f == "services.get" or module == "services" and method == "get":
+ if service.prefix == "/core":
+ non_slash_prefix = "/core_fwdr"
+ else:
+ non_slash_prefix = "/fwdr"
+ if k not in services:
+ services[k] = urlunparse(
+ ("http", request_address, non_slash_prefix, None, None, None)
+ )
+ # url_slash
+ else:
+ if k not in services:
+ services[k] = urlunparse(
+ ("http", request_address, service.prefix, None, None, None)
+ )
keepalive_params = {
- "pa": keepalive_address,
- "ia": keepalive_address,
- "ga": keepalive_address,
- "ma": keepalive_address,
+ "pa": loopback,
+ "ia": loopback,
+ "ga": loopback,
+ "ma": loopback,
"t1": 2,
"t2": 10,
}
services["keepalive"] = urlunparse(
(
"http",
- keepalive_address,
+ loopback,
"/keepalive",
None,
urlencode(keepalive_params),
@@ -139,9 +179,6 @@ async def services_get(request: Request):
)
)
services["ntp"] = urlunparse(("ntp", "pool.ntp.org", "/", None, None, None))
- services["services"] = urlunparse(
- ("http", server_address, "/core", None, None, None)
- )
response = E.response(
E.services(