いいね、その流れかなりきれいにOS化できそう。雛型レベルでまとめてみるね。
全体像
- Roblox側:
HttpService:GetAsync()などで PNG を取得 - Python + Flask: REST API で PNG を返す
- MySQL: 惑星メタ情報+PNGの場所(URL or BLOB)を保持
ここでは:
- 惑星ごとに「地形PNG」を1枚持つシンプル版
- 必要に応じて「タイル分割」などに拡張できる前提
で設計する。
MySQL スキーマ案
CREATE TABLE planets (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
code VARCHAR(64) NOT NULL UNIQUE, -- APIで使う識別子 (例: "terra_001")
description TEXT,
png_path VARCHAR(512) NOT NULL, -- サーバ内パス or ストレージURL
width INT NOT NULL, -- 画像幅(px)
height INT NOT NULL, -- 画像高さ(px)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
codeを Roblox から指定するIDとして使うと扱いやすい。png_pathは- ローカルパス(例:
/data/planets/terra_001.png) - もしくは外部ストレージURL のどちらでもOK。
- ローカルパス(例:
URL設計案
RESTっぽく、かつ Roblox から叩きやすい形にする:
- 惑星一覧(メタ情報のみ)
GET /api/planets
- 惑星詳細(メタ情報)
GET /api/planets/<code>
- 惑星の地形PNG本体
GET /api/planets/<code>/heightmap.png
Roblox側は主に最後のエンドポイントを叩いて PNG を取得する想定。
Flask 雛型コード
from flask import Flask, jsonify, send_file, abort
import mysql.connector
import os
app = Flask(__name__)
# --- DB接続設定(環境変数などで管理するのが本番向き) ---
DB_CONFIG = {
'host': 'localhost',
'user': 'planet_user',
'password': 'planet_pass',
'database': 'planet_db',
'port': 3306,
}
def get_db_connection():
return mysql.connector.connect(**DB_CONFIG)
# --- 惑星一覧 ---
@app.route('/api/planets', methods=['GET'])
def list_planets():
conn = get_db_connection()
cur = conn.cursor(dictionary=True)
cur.execute("""
SELECT id, name, code, description, width, height, created_at
FROM planets
ORDER BY id ASC
""")
rows = cur.fetchall()
cur.close()
conn.close()
return jsonify(rows)
# --- 惑星詳細 ---
@app.route('/api/planets/<code>', methods=['GET'])
def get_planet(code):
conn = get_db_connection()
cur = conn.cursor(dictionary=True)
cur.execute("""
SELECT id, name, code, description, width, height, png_path, created_at
FROM planets
WHERE code = %s
LIMIT 1
""", (code,))
row = cur.fetchone()
cur.close()
conn.close()
if not row:
abort(404, description="Planet not found")
# png_path は内部情報なので返さない or 別フィールド名で返す
row.pop('png_path', None)
return jsonify(row)
# --- 惑星の地形PNGを返す ---
@app.route('/api/planets/<code>/heightmap.png', methods=['GET'])
def get_planet_heightmap(code):
conn = get_db_connection()
cur = conn.cursor(dictionary=True)
cur.execute("""
SELECT png_path
FROM planets
WHERE code = %s
LIMIT 1
""", (code,))
row = cur.fetchone()
cur.close()
conn.close()
if not row:
abort(404, description="Planet not found")
png_path = row['png_path']
if not os.path.exists(png_path):
abort(404, description="PNG file not found")
# Roblox HttpService は基本バイナリOKなので image/png で返す
return send_file(png_path, mimetype='image/png')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Roblox 側からの呼び出しイメージ
local HttpService = game:GetService("HttpService")
local baseUrl = "http://your-flask-server:5000"
local planetCode = "terra_001"
local url = baseUrl .. "/api/planets/" .. planetCode .. "/heightmap.png"
-- ここは実際には ImageLabel.Image にURLを指定するか、
-- 一旦ファイルとして扱うかなど、運用に応じて変わる。
local result = HttpService:GetAsync(url)
-- result はバイナリ文字列なので、そのままでは使いづらい。
-- Robloxでの扱い方は、用途(テクスチャ化 or 外部ホスティング)次第。
(Roblox内で直接PNGバイナリをテクスチャにするのは制約があるので、
CDNに置いてURLをImageに指定する方式も検討対象になる。)
拡張の余地(地形万華鏡っぽくするなら)
- タイル分割:
planet_tilesテーブルを追加してplanet_idtile_x,tile_ypng_path
- URL:
GET /api/planets/<code>/tiles/<int:x>/<int:y>.png
- バリエーション(万華鏡)
variantカラムを持たせてGET /api/planets/<code>/variants/<variant>/heightmap.png
「地形万華鏡」として、
- 惑星メタ情報(名前・説明・サイズ)
- PNG実体へのパス
をMySQLに置いておき、
Flaskは「ルーター兼ファイルサーバ」として動く、という構造はかなり素直で拡張しやすい。
この方向性で、
- タイル制御
- バリエーション
- 生成ログ(どのパラメータで作ったか)
なども一緒に持ちたくなったら、そのスキーマも一緒に設計していこう。