Cross-Platform Scripts: - extract_z_asset.sh: Linux/Unix single file extraction - batch_extract_z_assets.sh: Linux/Unix batch extraction - pack_z_asset.sh: Linux/Unix asset packing - extract_z_asset.ps1: Windows PowerShell extraction Server Integration: - AssetExtractionService.cs: C# service for ZLIB extraction/packing - AssetManagementController.cs: API endpoints for asset management - POST /api/AssetManagement/extract - POST /api/AssetManagement/pack - POST /api/AssetManagement/batch-extract - GET /api/AssetManagement/list - Registered AssetExtractionService in Program.cs Features: - Extracts .z files (ZLIB compressed textures/data) - Packs files to .z format with ZLIB compression - Batch processing support - Cross-platform (Windows/Linux/macOS) - Server-side API for remote asset management - Path traversal protection Documentation: - ASSET_EXTRACTION_GUIDE.md: Complete integration guide - Tools/README.md: CLI tool documentation Based on: Tankonline/Real-Racing-3-Texture-Extraction-Tool Converted to cross-platform bash/PowerShell scripts + C# service Ready for .pak asset extraction when files arrive from community Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
124 lines
3.2 KiB
Bash
124 lines
3.2 KiB
Bash
#!/usr/bin/env bash
|
|
# RR3 Asset Extraction Script - Cross-Platform
|
|
# Extracts .z (ZLIB compressed) texture files from Real Racing 3
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${CYAN}════════════════════════════════════════════════════════════${NC}"
|
|
echo -e "${YELLOW} RR3 Asset Extraction Tool - Linux/Unix${NC}"
|
|
echo -e "${CYAN}════════════════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
|
|
# Check if Python 3 is installed
|
|
if ! command -v python3 &> /dev/null; then
|
|
echo -e "${RED}ERROR: Python 3 is not installed!${NC}"
|
|
echo "Please install Python 3 to continue."
|
|
exit 1
|
|
fi
|
|
|
|
# Check arguments
|
|
if [ "$#" -lt 1 ]; then
|
|
echo "Usage: $0 <input.z> [output_folder]"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 sprites_0.etc.dds.z"
|
|
echo " $0 sprites_0.etc.dds.z /path/to/output"
|
|
exit 1
|
|
fi
|
|
|
|
INPUT_FILE="$1"
|
|
OUTPUT_DIR="${2:-$(dirname "$INPUT_FILE")}"
|
|
|
|
# Validate input file
|
|
if [ ! -f "$INPUT_FILE" ]; then
|
|
echo -e "${RED}ERROR: Input file not found: $INPUT_FILE${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${GREEN}Input file:${NC} $INPUT_FILE"
|
|
echo -e "${GREEN}Output directory:${NC} $OUTPUT_DIR"
|
|
echo ""
|
|
|
|
# Create output directory if it doesn't exist
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
# Extract using Python
|
|
python3 - "$INPUT_FILE" "$OUTPUT_DIR" << 'PYTHON_SCRIPT'
|
|
import sys
|
|
import os
|
|
import zlib
|
|
|
|
def main():
|
|
input_file = sys.argv[1]
|
|
output_dir = sys.argv[2]
|
|
|
|
print("Reading file...")
|
|
|
|
with open(input_file, "rb") as f:
|
|
data = f.read()
|
|
|
|
out = b""
|
|
i = 0
|
|
found = 0
|
|
|
|
print("Scanning for ZLIB blocks...")
|
|
|
|
# Scan for zlib blocks
|
|
while i < len(data) - 2:
|
|
if data[i] == 0x78 and data[i+1] in (0x9C, 0xDA, 0x01):
|
|
try:
|
|
d = zlib.decompress(data[i:])
|
|
out += d
|
|
print(f" [+] Block {found} at {hex(i)}")
|
|
found += 1
|
|
i += len(d)
|
|
continue
|
|
except:
|
|
pass
|
|
i += 1
|
|
|
|
if found == 0:
|
|
print("ERROR: No valid zlib blocks found!")
|
|
sys.exit(1)
|
|
|
|
# Get output filename
|
|
base = os.path.basename(input_file)
|
|
if base.lower().endswith(".z"):
|
|
base = base[:-2]
|
|
|
|
output_file = os.path.join(output_dir, base)
|
|
|
|
# Backup if exists
|
|
if os.path.exists(output_file):
|
|
bak = output_file + ".bak"
|
|
if not os.path.exists(bak):
|
|
os.rename(output_file, bak)
|
|
print(f"Backup created: {bak}")
|
|
|
|
# Write file
|
|
with open(output_file, "wb") as f:
|
|
f.write(out)
|
|
|
|
print("")
|
|
print(f"✅ Extraction complete!")
|
|
print(f"Output: {output_file}")
|
|
print(f"Blocks found: {found}")
|
|
print(f"Size: {len(out):,} bytes")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
PYTHON_SCRIPT
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Done!${NC}"
|