mirror of
https://github.com/Lolendor/reVCDOS.git
synced 2026-10-10 11:53:11 +08:00
Merge pull request #4 from Rohamgames/main
Added PHP hosting code to support on shared hosting enviroments
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# JS files
|
||||
AddType application/javascript .js
|
||||
|
||||
# WebAssembly files
|
||||
AddType application/wasm .wasm
|
||||
|
||||
# CSS files
|
||||
AddType text/css .css
|
||||
|
||||
# Brotli-compressed files
|
||||
AddEncoding br .br
|
||||
|
||||
|
||||
|
||||
# Enable rewrite engine
|
||||
RewriteEngine On
|
||||
|
||||
# Set base path if PHP file is not in root
|
||||
RewriteBase /
|
||||
|
||||
# If the request is for an existing file or directory, serve it directly
|
||||
RewriteCond %{REQUEST_FILENAME} -f [OR]
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
RewriteRule ^ - [L]
|
||||
|
||||
# Otherwise, route everything to index.php
|
||||
RewriteRule ^.*$ index.php [L,QSA]
|
||||
|
||||
|
||||
# Correct MIME types
|
||||
AddType application/javascript .js
|
||||
AddType application/wasm .wasm
|
||||
AddType text/css .css
|
||||
|
||||
# Brotli compressed files
|
||||
AddEncoding br .br
|
||||
|
||||
# Optional: force correct MIME for .js.br or .wasm.br
|
||||
<FilesMatch "\.js\.br$">
|
||||
ForceType application/javascript
|
||||
AddEncoding br
|
||||
</FilesMatch>
|
||||
|
||||
<FilesMatch "\.wasm\.br$">
|
||||
ForceType application/wasm
|
||||
AddEncoding br
|
||||
</FilesMatch>
|
||||
@@ -4,9 +4,27 @@ Web-based port of GTA: Vice City running in browser via WebAssembly.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.8+
|
||||
- Docker or Python 3.8+ or PHP 8.0+
|
||||
- Dependencies from `requirements.txt`
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Clone the repository**:
|
||||
```bash
|
||||
git clone https://github.com/Lolendor/reVCDOS.git
|
||||
cd reVCDOS
|
||||
```
|
||||
|
||||
2. **Configure Assets** (Optional):
|
||||
|
||||
By default, the project uses the **DOS Zone CDN**. For local hosting, download and place assets in [(see structure)](#project-structure):
|
||||
* **Resources:** `vcsky/fetched/` (or `fetched-ru/`) — `data`, `audio`, `anim`, `models` folders.
|
||||
* **Binaries:** `vcbr/` — `.wasm.br` and `.data.br` files for your chosen language.
|
||||
4. **Launch the Application**:
|
||||
Choose one of the setup methods below:
|
||||
* **Docker** (Recommended for most users) — fast and isolated.
|
||||
* **PHP** — Simply upload the folder to your web server (FTP/Hosting).
|
||||
* **Manual Installation** — for development and customization.
|
||||
|
||||
## Setup & Running
|
||||
|
||||
@@ -51,6 +69,10 @@ python server.py
|
||||
|
||||
Server starts at `http://localhost:8000`
|
||||
|
||||
### Option 3: Shared Hosting on PHP (No installation)
|
||||
|
||||
If you want to run the game from a hosted environment with `PHP 8.0` or above, just copy the contents of this repo to your desired hosting
|
||||
By default the `index.php` and `.htaccess` will get the job done.
|
||||
## Server Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
@@ -96,6 +118,7 @@ python server.py --port 3000 --custom_saves --login admin --password secret123 -
|
||||
| `lang` | `en`, `ru` | Game language |
|
||||
| `cheats` | `1` | Enable cheat menu (F3) |
|
||||
|
||||
|
||||
**Examples:**
|
||||
- `http://localhost:8000/?lang=ru` — Russian version
|
||||
- `http://localhost:8000/?lang=en&cheats=1` — English + cheats
|
||||
@@ -104,6 +127,8 @@ python server.py --port 3000 --custom_saves --login admin --password secret123 -
|
||||
|
||||
```
|
||||
├── server.py # FastAPI proxy server
|
||||
├── index.php # php proxy server
|
||||
├── .htaccess # apache config for php
|
||||
├── requirements.txt # Python dependencies
|
||||
├── additions/ # Server extensions
|
||||
│ ├── auth.py # HTTP Basic Auth middleware
|
||||
@@ -138,11 +163,16 @@ python server.py --port 3000 --custom_saves --login admin --password secret123 -
|
||||
│ ├── vc-sky-en-v6.wasm.br
|
||||
│ ├── vc-sky-ru-v6.data.br
|
||||
│ └── vc-sky-ru-v6.wasm.br
|
||||
└── vcsky/ # Additional assets (optional)
|
||||
├── data/
|
||||
├── audio/
|
||||
├── models/
|
||||
└── anim/
|
||||
└── vcsky/ # Decompressed assets
|
||||
├── fetched/ # English version files
|
||||
│ ├── data/
|
||||
│ ├── audio/
|
||||
│ ├── models/
|
||||
│ └── anim/
|
||||
└── fetched-ru/ # Russian version files
|
||||
├── data/
|
||||
├── audio/
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
// ---------------- CONFIG ----------------
|
||||
$VCSKY_BASE_URL = "https://cdn.dos.zone/vcsky/";
|
||||
$BR_BASE_URL = "https://br.cdn.dos.zone/vcsky/";
|
||||
$BASE_PATH = ''; // public base URL
|
||||
$DIST_PATH = __DIR__ . '/dist'; // local directory for SPA
|
||||
|
||||
// ---------------- HELPERS ----------------
|
||||
|
||||
// Build URL with query string
|
||||
function build_url($base, $path) {
|
||||
$query = $_SERVER['QUERY_STRING'];
|
||||
$url = rtrim($base, '/') . '/' . ltrim($path, '/');
|
||||
if ($query) {
|
||||
$url .= '?' . $query;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
// Proxy request using cURL
|
||||
function proxy_request($url) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER['REQUEST_METHOD']);
|
||||
|
||||
// Forward headers
|
||||
$headers = [];
|
||||
foreach (getallheaders() as $key => $value) {
|
||||
if (!in_array(strtolower($key), ['host', 'content-length'])) {
|
||||
$headers[] = "$key: $value";
|
||||
}
|
||||
}
|
||||
$headers[] = "Cross-Origin-Opener-Policy: same-origin";
|
||||
$headers[] = "Cross-Origin-Embedder-Policy: require-corp";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
|
||||
// Forward body for POST/PUT/PATCH
|
||||
if (!in_array($_SERVER['REQUEST_METHOD'], ['GET', 'HEAD'])) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents('php://input'));
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
|
||||
$header_text = substr($response, 0, $header_size);
|
||||
$body = substr($response, $header_size);
|
||||
|
||||
foreach (explode("\r\n", $header_text) as $header) {
|
||||
if ($header && stripos($header, 'Content-Length') === false) {
|
||||
header($header, false);
|
||||
}
|
||||
}
|
||||
|
||||
echo $body;
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
// ---------------- ROUTING ----------------
|
||||
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
|
||||
// Proxy /vcsky/*
|
||||
if (preg_match('#^' . $BASE_PATH . '/vcsky/(.*)#', $uri, $matches)) {
|
||||
$url = build_url($VCSKY_BASE_URL, $matches[1]);
|
||||
proxy_request($url);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Proxy /vcbr/*
|
||||
if (preg_match('#^' . $BASE_PATH . '/vcbr/(.*)#', $uri, $matches)) {
|
||||
$url = build_url($BR_BASE_URL, $matches[1]);
|
||||
proxy_request($url);
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
// Serve static files under $BASE_PATH
|
||||
if (strpos($uri, $BASE_PATH) === 0) {
|
||||
$relativePath = substr($uri, strlen($BASE_PATH));
|
||||
if ($relativePath === '' || $relativePath === '/') {
|
||||
$relativePath = '/index.html';
|
||||
}
|
||||
|
||||
$localFile = realpath($DIST_PATH . $relativePath);
|
||||
|
||||
// Ensure the file exists AND is inside $DIST_PATH
|
||||
if ($localFile && is_file($localFile) && str_starts_with($localFile, realpath($DIST_PATH))) {
|
||||
// Set MIME type manually for common extensions
|
||||
$ext = pathinfo($localFile, PATHINFO_EXTENSION);
|
||||
switch (strtolower($ext)) {
|
||||
case 'js':
|
||||
$mimeType = 'application/javascript';
|
||||
break;
|
||||
case 'css':
|
||||
$mimeType = 'text/css';
|
||||
break;
|
||||
case 'html':
|
||||
case 'htm':
|
||||
$mimeType = 'text/html';
|
||||
break;
|
||||
case 'json':
|
||||
$mimeType = 'application/json';
|
||||
break;
|
||||
case 'wasm':
|
||||
$mimeType = 'application/wasm';
|
||||
break;
|
||||
default:
|
||||
$mimeType = mime_content_type($localFile) ?: 'application/octet-stream';
|
||||
}
|
||||
|
||||
header("Content-Type: $mimeType");
|
||||
header("Cross-Origin-Opener-Policy: same-origin");
|
||||
header("Cross-Origin-Embedder-Policy: require-corp");
|
||||
readfile($localFile);
|
||||
exit;
|
||||
}
|
||||
|
||||
// SPA fallback only for HTML requests
|
||||
if (str_ends_with($uri, '/') || preg_match('/\.html$/', $uri)) {
|
||||
$indexFile = $DIST_PATH . '/index.html';
|
||||
if (is_file($indexFile)) {
|
||||
header("Content-Type: text/html");
|
||||
header("Cross-Origin-Opener-Policy: same-origin");
|
||||
header("Cross-Origin-Embedder-Policy: require-corp");
|
||||
readfile($indexFile);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 404 fallback
|
||||
http_response_code(404);
|
||||
echo "Not Found";
|
||||
Reference in New Issue
Block a user