Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,6 @@ path = repos/pikmin-3
url = https://github.com/PretendoNetwork/pikmin-3
branch = master
ignore = dirty
[submodule "repos/mario-kart-8"]
path = repos/mario-kart-8
url = https://github.com/Newtendo-Network/nex_mario_kart_8.git
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a consistency thing here: tabs can be removed, explicit branch and ignore = dirty can be added.

21 changes: 21 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,27 @@ services:
- ./environment/pikmin-3.env
- ./environment/pikmin-3.local.env

mario-kart-8:
build: ./repos/mario-kart-8
depends_on:
- account
- friends
- mongodb
- redis
- minio
restart: unless-stopped
ports:
# Authentication server
- 5781:5781/udp
# Secure server
- 5782:5782/udp
networks:
internal:
dns: 172.20.0.200
env_file:
- ./environment/mario-kart-8.env
- ./environment/mario-kart-8.local.env

volumes:
mitmproxy-pretendo-data:
mongodb-database:
Expand Down
14 changes: 14 additions & 0 deletions environment/mario-kart-8.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PN_MK8_AUTHENTICATION_SERVER_PORT=5781
PN_MK8_SECURE_SERVER_PORT=5782
PN_MK8_FRIENDS_GRPC_HOST=friends
PN_MK8_FRIENDS_GRPC_PORT=5001
PN_MK8_ACCOUNT_GRPC_HOST=account
PN_MK8_ACCOUNT_GRPC_PORT=5000
PN_MK8_GRPC_PORT=5780
PN_MK8_ACCOUNT_DATABASE=pretendo_account
PN_MK8_MONGO_HOST=mongodb
PN_MK8_MONGO_PORT=27017
PN_MK8_CONFIG_S3_ENDPOINT=minio.pretendo.cc
PN_MK8_CONFIG_S3_ACCESS_KEY=minio_pretendo
PN_MK8_CONFIG_S3_BUCKET=amkj
PN_MK8_REDIS_URI=redis:6379
14 changes: 14 additions & 0 deletions patches/mario-kart-8/create_python_requirements.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..d873a47
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+aioconsole
+requests
+pymongo
+redis
+grpcio-tools
+minio
+nintendoclients
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the CI on ARM failed while installing the dependencies here, while x64 succeeded. I'm seeing error: command 'gcc' failed: No such file or directory. My guess is that one of these packages doesn't have a pre-built wheel for ARM, so we might need to add installing GCC and other build dependencies to the Dockerfile for ARM compatibility.

\ No newline at end of file
104 changes: 104 additions & 0 deletions patches/mario-kart-8/create_server_config.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
diff --git a/server_config.py b/server_config.py
new file mode 100644
index 0000000..dcb8279
--- /dev/null
+++ b/server_config.py
@@ -0,0 +1,98 @@
+from nintendo.nex import settings
+import pymongo
+import pymongo
+import urllib.parse
+import os
+
+GAME_SERVER_ID = 0x1010EB00
+ACCESS_KEY = "25dbf96a"
+NEX_VERSION = 30504
+
+# NEX_SETTINGS = settings.load("friends")
+NEX_SETTINGS = settings.default()
+NEX_SETTINGS.configure(ACCESS_KEY, NEX_VERSION)
+NEX_SETTINGS["prudp.resend_timeout"] = 1.5
+NEX_SETTINGS["prudp.resend_limit"] = 3
+NEX_SETTINGS["prudp.version"] = 1
+NEX_SETTINGS["prudp.max_substream_id"] = 1
+
+
+class MongoCredentials:
+ def __init__(self, host: str, port: int, use_auth: bool = False, username: str = "", password: str = ""):
+ self.host = host
+ self.port = port
+ self.use_auth = use_auth
+ self.username = username
+ self.password = password
+
+ def connect(self):
+ # Username and password must be percent-escaped
+ db_use_auth = self.use_auth
+ db_user = urllib.parse.quote_plus(self.username)
+ db_pass = urllib.parse.quote_plus(self.password)
+ db_host = self.host
+ db_port = self.port
+
+ if db_use_auth:
+ db_uri = 'mongodb://%s:%s@%s:%d' % (db_user, db_pass, db_host, db_port)
+ else:
+ db_uri = 'mongodb://%s:%d' % (db_host, db_port)
+
+ return pymongo.MongoClient(db_uri, serverSelectionTimeoutMS=3000)
+
+
+class NEXConfig:
+ def __init__(self):
+ self.nex_host = "0.0.0.0"
+ self.nex_auth_port = int(os.getenv('PN_MK8_AUTHENTICATION_SERVER_PORT', 1000))
+ self.nex_secure_port = int(os.getenv('PN_MK8_SECURE_SERVER_PORT', 1001))
+ self.nex_secure_user_password = os.getenv('PN_MK8_SECURE_PASSWORD', 'abcdef123456') # PLEASE, make this a real private password.
+ self.nex_external_address = os.getenv('PN_MK8_SECURE_SERVER_HOST', '0.0.0.0') # Your external IP, for external clients to connect.
+
+ self.friends_grpc_host = os.getenv('PN_MK8_FRIENDS_GRPC_HOST', '123.123.123.123')
+ self.friends_grpc_port = int(os.getenv('PN_MK8_FRIENDS_GRPC_PORT', 1002))
+ self.friends_grpc_api_key = os.getenv('PN_MK8_FRIENDS_GRPC_API_KEY', 'abcdefghijklmnopqrstuvwxyz123456789')
+
+ self.account_grpc_host = os.getenv('PN_MK8_ACCOUNT_GRPC_HOST', '124.124.124.124')
+ self.account_grpc_port = int(os.getenv('PN_MK8_ACCOUNT_GRPC_PORT', 1003))
+ self.account_grpc_api_key = os.getenv('PN_MK8_ACCOUNT_GRPC_API_KEY', 'abcdefghijklmnopqrstuvwxyz123456789')
+
+ # These gRPC credentials are for the server we're implementing
+ self.mario_kart_8_grpc_host = "localhost"
+ self.mario_kart_8_grpc_port = int(os.getenv('PN_MK8_GRPC_PORT', 50051))
+ self.mario_kart_8_grpc_api_key = os.getenv('PN_MK8_GRPC_API_KEY', 'abcdefghijklmnopqrstuvwxyz123456789')
+
+ self.account_database = os.getenv('PN_MK8_ACCOUNT_DATABASE', 'pretendo_account')
+
+ self.pnid_collection = "pnids"
+ self.nex_account_collection = "nexaccounts"
+
+ self.game_db_server = MongoCredentials(
+ host=os.getenv('PN_MK8_MONGO_HOST', '222.222.222.222'),
+ port=int(os.getenv('PN_MK8_MONGO_PORT', 1004))
+ )
+
+ self.game_database = "mk8"
+
+ self.sequence_collection = "counters"
+ self.gatherings_collection = "gatherings"
+ self.sessions_collection = "sessions"
+ self.tournaments_collection = "tournaments"
+ self.tournaments_score_collection = "tournaments_scores"
+ self.ranking_common_data_collection = "commondata"
+ self.rankings_score_collection = "rankings"
+ self.secure_reports_collection = "secure_reports"
+ self.datastore_collection = "datastore"
+ self.restriction_collection = "restrictions"
+
+ self.s3_endpoint_domain = os.getenv('PN_MK8_CONFIG_S3_ENDPOINT', 'minio.pretendo.cc')
+ self.s3_endpoint = "http://" + self.s3_endpoint_domain
+ self.s3_access_key = os.getenv('PN_MK8_CONFIG_S3_ACCESS_KEY', 'minio_pretendo')
+ self.s3_secret = os.getenv('PN_MK8_CONFIG_S3_SECRET', '...')
+ self.s3_region = "it"
+ self.bucket_name = os.getenv('PN_MK8_CONFIG_S3_BUCKET', 'amkj')
+
+ self.redis_uri = "redis://" + os.getenv('PN_MK8_REDIS_URI', '53.53.53.53:1005') # redis://HOST[:PORT][?db=DATABASE[&password=PASSWORD]]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Nice way to grab the server configuration from Docker environment variables even though the original server doesn't support it.

I'm not sure that it makes sense to provide default values to getenv, though, when those defaults are basically nonsense (like the invalid IPs and secrets). It might be better to just let them be None and have the server fail fast in case of accidentally-missing variables.

+
+
+NEX_CONFIG = NEXConfig()
31 changes: 31 additions & 0 deletions patches/mario-kart-8/disable-interactive-input.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
diff --git a/main.py b/main-diff.py
index 9fb8233..b9fa3a7 100644
--- a/main.py
+++ b/main.py
@@ -8,6 +8,7 @@ import aioconsole
import contextlib
import datetime
import requests
+import signal

from datetime import datetime, timezone

@@ -246,7 +247,17 @@ async def main():
logging.info("Starting gRPC amkj server on %s", listen_addr)

await server.start()
- await aioconsole.ainput("Press enter to exit...\n")
+
+ # Set signal handlers for graceful shutdown
+ loop = asyncio.get_running_loop()
+ for sig in (signal.SIGINT, signal.SIGTERM):
+ loop.add_signal_handler(sig, lambda: asyncio.create_task(shutdown(server)))
+
+ # Keep server running
+ try:
+ await server.wait_for_termination()
+ except asyncio.CancelledError:
+ pass


async def sync_amkj_status_to_database(task: asyncio.Task):
28 changes: 28 additions & 0 deletions patches/mario-kart-8/dockerfile-creation.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..9fb5b2d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+# Use the official Python image as the base
+FROM python:3.9-slim
+
+# Set the working directory inside the container
+WORKDIR /app
+
+# Copy the requirements file to the working directory
+COPY requirements.txt .
+
+ENV PYTHONPATH="/usr/local/lib/python3.9/site-packages"
+
+# Install dependencies specified in requirements.txt
+RUN python -m pip install --no-cache-dir -r requirements.txt
+
+# Copy all project files into the container
+COPY . .
+
+# Generate gRPC Python files before running the application
+RUN python -m grpc_tools.protoc --proto_path=grpc --python_out=. --grpc_python_out=. grpc/amkj_service.proto
+
+# Set the command to run the application
+CMD ["python", "main.py"]
1 change: 1 addition & 0 deletions repos/mario-kart-8
Submodule mario-kart-8 added at b5f9f9
3 changes: 2 additions & 1 deletion scripts/internal/update-account-servers-database.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ parse_arguments "$@"
print_info "Setting up Pretendo account servers database..."

load_dotenv .env
dotenv_files=("friends" "miiverse-api" "wiiu-chat" "super-mario-maker" "splatoon" "minecraft-wiiu" "pikmin-3")
dotenv_files=("friends" "miiverse-api" "wiiu-chat" "super-mario-maker" "splatoon" "minecraft-wiiu" "pikmin-3" "mario-kart-8")
for file in "${dotenv_files[@]}"; do
load_dotenv "$file.env" "$file.local.env"
done
Expand All @@ -24,6 +24,7 @@ run_verbose docker compose exec -e SERVER_IP="$SERVER_IP" \
-e SPLATOON_PORT="$PN_SPLATOON_AUTHENTICATION_SERVER_PORT" \
-e MINECRAFT_PORT="$PN_MINECRAFT_AUTHENTICATION_SERVER_PORT" \
-e PIKMIN3_PORT="$PN_PIKMIN3_AUTHENTICATION_SERVER_PORT" \
-e MK8_PORT="$PN_MK8_AUTHENTICATION_SERVER_PORT" \
account node -e "$create_server_script"

print_success "Account servers database is set up."
9 changes: 9 additions & 0 deletions scripts/run-in-container/update-account-servers-database.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ async function runAsync() {
1,
"0".repeat(64)
);
await createNexServer(
"Mario Kart 8",
"1010EB00",
["000500001010EB00", "000500001010EC00", "000500001010ED00"],
process.env.SERVER_IP,
process.env.MK8_PORT,
1,
"0".repeat(64)
);
}

runAsync().then(() => {
Expand Down
16 changes: 16 additions & 0 deletions scripts/setup-environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ echo "PN_SMM_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./super-mario-maker.l
echo "PN_SPLATOON_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./splatoon.local.env
echo "PN_MINECRAFT_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./minecraft-wiiu.local.env
echo "PN_PIKMIN3_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./pikmin-3.local.env
echo "PN_MK8_ACCOUNT_GRPC_API_KEY=$account_grpc_api_key" >>./mario-kart-8.local.env

# Generate a secret key for MinIO
minio_secret_key=$(generate_password 32)
Expand All @@ -96,6 +97,7 @@ echo "PN_MIIVERSE_API_CONFIG_S3_ACCESS_SECRET=$minio_secret_key" >>./miiverse-ap
echo "JUXT_CONFIG_AWS_SPACES_SECRET=$minio_secret_key" >>./juxtaposition-ui.local.env
echo "PN_BOSS_CONFIG_S3_ACCESS_SECRET=$minio_secret_key" >>./boss.local.env
echo "PN_SMM_CONFIG_S3_ACCESS_SECRET=$minio_secret_key" >>./super-mario-maker.local.env
echo "PN_MK8_CONFIG_S3_ACCESS_SECRET=$minio_secret_key" >>./mario-kart-8.local.env

# Generate a password for Postgres
postgres_password=$(generate_password 32)
Expand All @@ -113,12 +115,17 @@ echo "PN_FRIENDS_CONFIG_SECURE_PASSWORD=$friends_secure_password" >>./friends.lo
friends_api_key=$(generate_password 32)
echo "PN_FRIENDS_CONFIG_GRPC_API_KEY=$friends_api_key" >>./friends.local.env
echo "PN_WIIU_CHAT_FRIENDS_GRPC_API_KEY=$friends_api_key" >>./wiiu-chat.local.env
echo "PN_MK8_FRIENDS_GRPC_API_KEY=$friends_api_key" >>./wiiu-chat.local.env
echo "PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_API_KEY=$friends_api_key" >>./miiverse-api.local.env
echo "JUXT_CONFIG_GRPC_FRIENDS_API_KEY=$friends_api_key" >>./juxtaposition-ui.local.env
echo "PN_BOSS_CONFIG_GRPC_FRIENDS_SERVER_API_KEY=$friends_api_key" >>./boss.local.env
friends_aes_key=$(generate_hex 64)
echo "PN_FRIENDS_CONFIG_AES_KEY=$friends_aes_key" >>./friends.local.env

# Generate a gRPC API Key for Mario Kart 8 server
mk8_api_key=$(generate_password 32)
echo "PN_MK8_GRPC_API_KEY=$mk8_api_key" >>./mario-kart-8.local.env

# Generate a Kerberos password for the Wii U Chat server
chat_kerberos_password=$(generate_password 32)
echo "PN_WIIU_CHAT_KERBEROS_PASSWORD=$chat_kerberos_password" >>./wiiu-chat.local.env
Expand All @@ -138,6 +145,14 @@ echo "PN_MINECRAFT_KERBEROS_PASSWORD=$minecraft_kerberos_password" >>./minecraft
pikmin3_kerberos_password=$(generate_password 32)
echo "PN_PIKMIN3_KERBEROS_PASSWORD=$pikmin3_kerberos_password" >>./pikmin-3.local.env

# Generate a Kerberos password for the Mario Kart 8 server
mk8_kerberos_password=$(generate_password 32)
echo "PN_MK8_KERBEROS_PASSWORD=$mk8_kerberos_password" >>./mario-kart-8.local.env

# Generate a secure password for the Mario Kart 8 server
mk8_secure_password=$(generate_password 32)
echo "PN_MK8_SECURE_PASSWORD=$mk8_secure_password" >>./mario-kart-8.local.env

# Generate an AES key for the Miiverse servers
miiverse_aes_key=$(generate_hex 64)
echo "PN_MIIVERSE_API_CONFIG_AES_KEY=$miiverse_aes_key" >>./miiverse-api.local.env
Expand All @@ -156,6 +171,7 @@ echo "PN_SMM_SECURE_SERVER_HOST=$server_ip" >>./super-mario-maker.local.env
echo "PN_SPLATOON_SECURE_SERVER_HOST=$server_ip" >>./splatoon.local.env
echo "PN_MINECRAFT_SECURE_SERVER_HOST=$server_ip" >>./minecraft-wiiu.local.env
echo "PN_PIKMIN3_SECURE_SERVER_HOST=$server_ip" >>./pikmin-3.local.env
echo "PN_MK8_SECURE_SERVER_HOST=$server_ip" >>./mario-kart-8.local.env

# Get the Wii U IP address
if [[ -n "$wiiu_ip" ]]; then
Expand Down
14 changes: 7 additions & 7 deletions scripts/setup-submodule-patches.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use this if you're trying to update the submodules to a newer version than is su
fails to apply, a 3-way merge will be attempted."
parse_arguments "$@"

print_info "Resetting all submodules..."
run_verbose git submodule sync
run_verbose git submodule foreach "git reset --hard"
run_verbose git submodule foreach "git clean -fd"
run_verbose git submodule update --init --checkout
print_info "Resetting all submodules (including nested submodules)..."
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit nitpicky but I don't feel like adding this to the info text is necessary.

(same for below)

run_verbose git submodule sync --recursive
run_verbose git submodule foreach --recursive "git reset --hard"
run_verbose git submodule foreach --recursive "git clean -xfd"
run_verbose git submodule update --init --checkout --recursive
if [[ -n "$update_remote" ]]; then
print_info "Updating submodules from their remotes..."
git submodule update --remote
print_info "Updating submodules from their remotes (including nested submodules)..."
run_verbose git submodule update --remote --recursive
fi

print_info "Applying patches to submodules..."
Expand Down
Loading