Files
rr3-apk/WHEN_ASSETS_ARRIVE.md

10 KiB

Real Racing 3 - Asset Import Quick Start Guide

FOR WHEN DISCORD SENDS YOU THE FILES


📥 Step 1: Receive the Assets

Discord will likely send you:

  • A .zip/.7z/.tar.gz archive (2-5 GB)
  • Or a Google Drive/Mega/Dropbox link
  • Or multiple .pak/.pvr/.dat files

📦 Step 2: Extract & Organize

If it's an archive:

# Extract to temporary location
cd E:\rr3\
7z x assets-from-discord.zip -o"assets-temp"

Check what you got:

cd E:\rr3\assets-temp
Get-ChildItem -Recurse | Group-Object Extension | Sort-Object Count -Descending

You should see:

  • .pak files (main game assets)
  • .pvr files (textures - PowerVR format)
  • .dat files (game data)
  • .atlas files (sprite sheets)
  • .z files (compressed data)
  • .fsh/.vsh files (shaders)

Step 3: Verify with Manifests (CRITICAL!)

Run the verification script:

cd E:\rr3\

# Create verification script
@'
$manifestPath = "E:\rr3\RR3CommunityServer\RR3CommunityServer\Assets\manifests\"
$assetsPath = "E:\rr3\assets-temp\"

Write-Host "Verifying assets against manifests..." -ForegroundColor Cyan
Write-Host ""

$verified = 0
$failed = 0
$missing = 0

# Read all manifests
Get-ChildItem $manifestPath -Filter "*.txt" | ForEach-Object {
    $manifest = Get-Content $_.FullName
    
    foreach ($line in $manifest) {
        if ($line -match '^/') {
            $parts = $line -split "`t"
            $path = $parts[0]
            $expectedMd5 = $parts[1]
            $fileName = [System.IO.Path]::GetFileName($path)
            
            # Find file
            $file = Get-ChildItem $assetsPath -Recurse -Filter $fileName | Select-Object -First 1
            
            if ($file) {
                # Calculate MD5
                $md5 = Get-FileHash $file.FullName -Algorithm MD5
                $actualMd5 = $md5.Hash.ToLower()
                
                if ($actualMd5 -eq $expectedMd5) {
                    $verified++
                    Write-Host "✅ $fileName" -ForegroundColor Green
                } else {
                    $failed++
                    Write-Host "❌ $fileName - MD5 mismatch!" -ForegroundColor Red
                    Write-Host "   Expected: $expectedMd5" -ForegroundColor Gray
                    Write-Host "   Got:      $actualMd5" -ForegroundColor Gray
                }
            } else {
                $missing++
                Write-Host "⚠️  $fileName - NOT FOUND" -ForegroundColor Yellow
            }
        }
    }
}

Write-Host ""
Write-Host "═══════════════════════════════════════════" -ForegroundColor Cyan
Write-Host "VERIFICATION COMPLETE" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════" -ForegroundColor Cyan
Write-Host "✅ Verified: $verified" -ForegroundColor Green
Write-Host "❌ Failed:   $failed" -ForegroundColor Red
Write-Host "⚠️  Missing:  $missing" -ForegroundColor Yellow
Write-Host ""

if ($failed -eq 0 -and $missing -lt 100) {
    Write-Host "🎉 Assets are GOOD! Ready to deploy!" -ForegroundColor Green -BackgroundColor DarkGreen
} else {
    Write-Host "⚠️  Some issues found - check with Discord" -ForegroundColor Yellow
}
'@ | Out-File verify-assets.ps1

# Run it
.\verify-assets.ps1

📂 Step 4: Copy to Server

Once verified, copy to the server:

# Copy all verified assets to server
$destination = "E:\rr3\RR3CommunityServer\RR3CommunityServer\Assets\downloaded\"

# Create directory structure
New-Item -ItemType Directory -Force -Path $destination

# Copy files (preserving structure if possible)
Copy-Item -Path "E:\rr3\assets-temp\*" -Destination $destination -Recurse -Force

Write-Host "✅ Assets copied to server!" -ForegroundColor Green

🗄️ Step 5: Import to Database

Create asset records in database:

cd E:\rr3\RR3CommunityServer

# Create import script
@'
using System;
using System.IO;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using RR3CommunityServer.Data;

var dbPath = "rr3community.db";
var assetsPath = "Assets/downloaded";
var manifestsPath = "Assets/manifests";

Console.WriteLine("Importing assets to database...");

using var db = new RR3DbContext(
    new DbContextOptionsBuilder<RR3DbContext>()
        .UseSqlite($"Data Source={dbPath}")
        .Options
);

int imported = 0;

// Read manifests
foreach (var manifestFile in Directory.GetFiles(manifestsPath, "*.txt"))
{
    var lines = File.ReadAllLines(manifestFile);
    
    foreach (var line in lines)
    {
        if (line.StartsWith("/"))
        {
            var parts = line.Split('\t');
            var path = parts[0];
            var md5 = parts[1];
            var compressedSize = long.Parse(parts[2]);
            var uncompressedSize = long.Parse(parts[3]);
            
            var fileName = Path.GetFileName(path);
            
            // Check if asset exists
            if (!db.GameAssets.Any(a => a.EaCdnPath == path))
            {
                // Find local file
                var localFiles = Directory.GetFiles(assetsPath, fileName, SearchOption.AllDirectories);
                var localPath = localFiles.FirstOrDefault();
                
                var asset = new GameAsset
                {
                    AssetType = DetermineAssetType(path),
                    FileName = fileName,
                    EaCdnPath = path,
                    LocalPath = localPath,
                    FileSize = uncompressedSize,
                    CompressedSize = compressedSize,
                    Md5Hash = md5,
                    ContentType = DetermineContentType(path),
                    Category = DetermineCategory(path),
                    DownloadedAt = localPath != null ? DateTime.UtcNow : null,
                    AccessCount = 0
                };
                
                db.GameAssets.Add(asset);
                imported++;
                
                if (imported % 100 == 0)
                {
                    Console.WriteLine($"Imported {imported} assets...");
                    db.SaveChanges();
                }
            }
        }
    }
}

db.SaveChanges();
Console.WriteLine($"✅ Import complete! {imported} assets added to database.");

static string DetermineAssetType(string path)
{
    if (path.Contains("car")) return "car";
    if (path.Contains("track")) return "track";
    if (path.Contains("audio")) return "audio";
    if (path.Contains("gui")) return "ui";
    return "other";
}

static string DetermineContentType(string path)
{
    var ext = Path.GetExtension(path).ToLower();
    return ext switch
    {
        ".pak" => "application/octet-stream",
        ".pvr" => "image/pvr",
        ".dat" => "application/octet-stream",
        ".atlas" => "application/octet-stream",
        ".z" => "application/x-compress",
        _ => "application/octet-stream"
    };
}

static string DetermineCategory(string path)
{
    if (path.Contains("/car")) return "cars";
    if (path.Contains("/track")) return "tracks";
    if (path.Contains("/audio")) return "audio";
    if (path.Contains("/gui")) return "ui";
    return "general";
}
'@ | Out-File -Encoding UTF8 import-assets.csx

# Run with dotnet-script (if installed) or manually add to server
Write-Host "⚠️  Import script created: import-assets.csx" -ForegroundColor Yellow
Write-Host "Run this inside your server project to populate the database" -ForegroundColor Gray

🚀 Step 6: Test Server

cd E:\rr3\RR3CommunityServer\RR3CommunityServer

# Start server
dotnet run

# In another terminal, test:
curl https://localhost:5001/content/api/status

# Should return JSON with:
# "availableAssets": (big number)
# "status": "ready"

📱 Step 7: Modify APK

Option A: APK Tool (Full Recompile)

# Decompile
apktool d realracing3.apk -o rr3-decompiled

# Edit smali or resources to change Director URL
# From: https://syn-dir.sn.eamobile.com
# To:   https://YOUR_SERVER_IP:5001

# Recompile
apktool b rr3-decompiled -o rr3-modded.apk

# Sign
jarsigner -keystore my.keystore rr3-modded.apk my-key

# Install
adb install rr3-modded.apk

Option B: Hosts File (Easier but requires root)

On Android device:

# Root required
su
mount -o remount,rw /system
echo "YOUR_SERVER_IP  syn-dir.sn.eamobile.com" >> /etc/hosts
echo "YOUR_SERVER_IP  cloudcell.ea.com" >> /etc/hosts

On Windows (for emulator):

# Edit C:\Windows\System32\drivers\etc\hosts
# Add these lines:
192.168.1.100  syn-dir.sn.eamobile.com
192.168.1.100  cloudcell.ea.com

🎮 Step 8: LAUNCH THE GAME!

  1. Install modded APK or set up hosts file
  2. Launch Real Racing 3
  3. Game contacts your server (not EA!)
  4. Downloads assets from your server
  5. PROFIT! 🏎️💨

📊 Expected Results

First Launch:

Game → Director Service (your server) ✅
Game → Authentication (your server) ✅
Game → Asset manifest (your server) ✅
Game → Downloads .pak files (your server) ✅
Game → PLAYABLE! 🎮

What You'll See in Server Logs:

[INFO] Director request for package: com.ea.games.r3_row
[INFO] GetDeviceID request: hardware=abc123
[INFO] Asset download request: /gui_assets/sprites.atlas
[INFO] Serving asset: /gui_assets/sprites.atlas (3015 bytes)
[INFO] Asset download request: /cars/porsche_911_gt3.pak
[INFO] Serving asset: /cars/porsche_911_gt3.pak (5.2 MB)

🔥 Quick Checklist

When assets arrive:

  • Download/extract files
  • Run verification script (check MD5s)
  • Copy to Assets/downloaded/
  • Import to database (optional but recommended)
  • Test server: curl https://localhost:5001/content/api/status
  • Modify APK or hosts file
  • Install & launch game
  • CELEBRATE! 🎉

🆘 Troubleshooting

Assets downloaded but game shows black screen?

  • Check server logs for 404 errors
  • Verify file paths match manifest paths
  • Ensure file permissions are correct

Game can't connect to server?

  • Check firewall allows port 5001
  • Verify APK modification worked
  • Try hosts file method instead
  • Check server is running: netstat -an | findstr 5001

MD5 verification failed?

  • Files might be corrupted during transfer
  • Ask Discord for re-upload
  • Check if files were unzipped correctly

📞 Next Step

Just wait for Discord response now!

When they send files, follow this guide step-by-step and you'll have RR3 running in no time! 🏁