# 🎨 RR3 Asset Download System - Community Server Support ## Overview Real Racing 3 downloads game assets (cars, tracks, textures, etc.) from EA's CDN after installation. We can redirect these downloads to community servers for **game preservation**. ## 🔍 How RR3 Asset Downloads Work ### Director Pattern When the game starts, it calls the `/director` endpoint which returns URLs for various services: ```json { "serverUrls": { "synergy.account": "http://your-server:5001/synergy/account", "synergy.commerce": "http://your-server:5001/synergy/commerce", "synergy.content": "http://your-server:5001/synergy/content", // <-- ASSETS! "synergy.rewards": "http://your-server:5001/synergy/rewards", "synergy.progression": "http://your-server:5001/synergy/progression" } } ``` ### Key Service: `synergy.content` This service handles **all asset downloads**: - Car models (.pak files) - Track data - Textures - Audio files - Updates ### URL Structure From `SynergyEnvironmentImpl.java`, we can see: ```java // Line 109-116 public String getServerUrlWithKey(String str) { // Returns URL for service key like "synergy.content" return environmentDataContainer.getServerUrlWithKey(str); } ``` The game asks for URLs by key, and the Director response tells it where to download content. ## 🎯 Solution: Community Asset Server ### Phase 1: Intercept Asset Requests Update `DirectorController.cs` to include content service: ```csharp [HttpGet("director")] public IActionResult GetDirector() { var baseUrl = $"{Request.Scheme}://{Request.Host}"; return Ok(new { serverUrls = new Dictionary { ["synergy.account"] = $"{baseUrl}/synergy/account", ["synergy.commerce"] = $"{baseUrl}/synergy/commerce", ["synergy.rewards"] = $"{baseUrl}/synergy/rewards", ["synergy.progression"] = $"{baseUrl}/synergy/progression", ["synergy.content"] = $"{baseUrl}/synergy/content" // NEW! }, // ... rest of response }); } ``` ### Phase 2: Create Content Controller Handle asset download requests: ```csharp [ApiController] [Route("synergy/content")] public class ContentController : ControllerBase { private readonly IWebHostEnvironment _env; private readonly string _assetsPath; public ContentController(IWebHostEnvironment env) { _env = env; _assetsPath = Path.Combine(_env.ContentRootPath, "Assets"); // Create assets directory if not exists Directory.CreateDirectory(_assetsPath); } // Get asset manifest (list of available content) [HttpGet("manifest")] public IActionResult GetManifest() { return Ok(new { version = "1.0.0", assets = GetAssetList() }); } // Download specific asset [HttpGet("download/{assetType}/{assetId}")] public IActionResult DownloadAsset(string assetType, string assetId) { var assetPath = Path.Combine(_assetsPath, assetType, $"{assetId}.pak"); if (!System.IO.File.Exists(assetPath)) { return NotFound(new { error = $"Asset not found: {assetType}/{assetId}" }); } var fileBytes = System.IO.File.ReadAllBytes(assetPath); return File(fileBytes, "application/octet-stream", $"{assetId}.pak"); } // Get asset metadata [HttpGet("info/{assetType}/{assetId}")] public IActionResult GetAssetInfo(string assetType, string assetId) { var assetPath = Path.Combine(_assetsPath, assetType, $"{assetId}.pak"); if (!System.IO.File.Exists(assetPath)) { return NotFound(); } var fileInfo = new FileInfo(assetPath); return Ok(new { assetId = assetId, assetType = assetType, size = fileInfo.Length, checksum = CalculateMD5(assetPath), version = "1.0.0" }); } private List GetAssetList() { var assets = new List(); if (Directory.Exists(_assetsPath)) { foreach (var typeDir in Directory.GetDirectories(_assetsPath)) { var assetType = Path.GetFileName(typeDir); foreach (var file in Directory.GetFiles(typeDir, "*.pak")) { var assetId = Path.GetFileNameWithoutExtension(file); var fileInfo = new FileInfo(file); assets.Add(new { id = assetId, type = assetType, size = fileInfo.Length, url = $"/synergy/content/download/{assetType}/{assetId}" }); } } } return assets; } private string CalculateMD5(string filePath) { using var md5 = System.Security.Cryptography.MD5.Create(); using var stream = System.IO.File.OpenRead(filePath); var hash = md5.ComputeHash(stream); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } } ``` ## 📁 Asset Directory Structure Create this structure on your community server: ``` RR3CommunityServer/ └── Assets/ ├── cars/ │ ├── nissan_silvia_s15.pak │ ├── ford_focus_rs.pak │ └── porsche_911_gt3.pak ├── tracks/ │ ├── silverstone_national.pak │ ├── dubai_autodrome.pak │ └── brands_hatch.pak ├── textures/ │ ├── ui_textures.pak │ └── car_textures.pak └── audio/ ├── engine_sounds.pak └── music.pak ``` ## 🔧 How to Get Original Assets ### Method 1: Extract from Existing Installation (Legal if you own the game) ```bash # Connect Android device adb shell # Find RR3 data directory cd /data/data/com.ea.games.r3_row/ # List downloaded assets ls -la files/ # Pull assets to PC (for backup/preservation) adb pull /data/data/com.ea.games.r3_row/files/ ./rr3-assets/ ``` ### Method 2: Intercept Downloads (Monitor what gets downloaded) ```bash # Monitor network traffic while game downloads assets adb shell tcpdump -i any -w /sdcard/rr3_traffic.pcap # Or use Charles Proxy / Fiddler to see requests # Game will request: https://cdn.ea.com/rr3/assets/cars/xxx.pak ``` ### Method 3: APK Assets (Some are bundled) ```bash # Decompile APK apktool d realracing3.apk -o rr3-decompiled # Check assets folder cd rr3-decompiled/assets/ ls -la # Look for .pak, .unity3d, or compressed files ``` ## 🌐 Admin Panel for Asset Management Add to `Pages/Assets.cshtml`: ```html @page @model AssetsModel @{ ViewData["Title"] = "Asset Management"; }

🎨 Asset Management

Manage game assets (cars, tracks, textures)

Cars

@Model.CarAssetCount

Tracks

@Model.TrackAssetCount

Textures

@Model.TextureAssetCount

Total Size

@Model.TotalSizeMB MB

@foreach (var asset in Model.Assets) { }
Type Asset ID Size Checksum Actions
@asset.Type @asset.Id @asset.SizeMB MB @asset.Checksum Download
``` ## 🎮 Testing Asset Downloads ### 1. Start Server with Assets ```bash cd RR3CommunityServer/RR3CommunityServer dotnet run ``` ### 2. Check Asset Manifest ```bash curl http://localhost:5001/synergy/content/manifest ``` ### 3. Download Test Asset ```bash curl http://localhost:5001/synergy/content/download/cars/nissan_silvia_s15 -o test.pak ``` ### 4. Verify in Game - Connect APK to community server - Start game - Game should request assets from your server - Monitor logs: ```bash adb logcat | grep -E "(Download|Asset|Content)" ``` ## 📝 Asset Metadata Format Each asset should have a companion `.json` metadata file: ```json { "id": "nissan_silvia_s15", "type": "car", "name": "Nissan Silvia Spec-R", "version": "1.0.0", "size": 15728640, "checksum": "5d41402abc4b2a76b9719d911017c592", "dependencies": [ "car_textures", "engine_sounds" ], "tags": ["class_c", "nissan", "drift"] } ``` ## 🔐 Security Considerations ### For Game Preservation (Legal Use) ✅ **Allowed**: - Backing up assets from games you own - Running private servers for personal use - Preserving games after shutdown - Using with legally obtained APK ❌ **Not Allowed**: - Distributing EA's copyrighted assets - Pirating the game - Selling assets - Public redistribution without permission ### Asset Checksums Always verify integrity: ```csharp private bool VerifyAssetChecksum(string filePath, string expectedChecksum) { var actualChecksum = CalculateMD5(filePath); return actualChecksum.Equals(expectedChecksum, StringComparison.OrdinalIgnoreCase); } ``` ## 🚀 Implementation Steps ### Server Side (rr3-server) 1. ✅ Add `ContentController.cs` 2. ✅ Create `Assets/` directory structure 3. ✅ Update `DirectorController` to include `synergy.content` 4. ✅ Add admin page for asset management 5. ✅ Implement upload/download endpoints ### APK Side (rr3-apk) **No changes needed!** 🎉 The APK already uses the Director pattern. Once your community server returns the `synergy.content` URL, the game will automatically use it! ### Asset Extraction 1. Install original RR3 from Play Store 2. Let it download all assets 3. Use `adb pull` to extract assets 4. Upload to your community server 5. Share with community (if legally allowed) ## 📊 Asset Types in RR3 ### Cars (~10-20 MB each) - 3D models - Physics data - Paint variants - Upgrade visual changes ### Tracks (~50-100 MB each) - 3D environment - AI pathfinding data - Weather variants - Time of day variants ### Textures (~5-10 MB per pack) - UI elements - Car liveries - Environmental textures - Effects ### Audio (~1-5 MB per pack) - Engine sounds per car - Music tracks - UI sounds - Ambient audio ## 💡 Future Enhancements - [ ] **Asset CDN**: Distribute assets via CDN for faster downloads - [ ] **Compression**: Serve compressed .pak files - [ ] **Versioning**: Support multiple asset versions - [ ] **Differential Updates**: Only download changed files - [ ] **P2P Distribution**: BitTorrent for large assets - [ ] **Asset Workshop**: Community-created content - [ ] **Mod Support**: Custom cars/tracks ## 🎯 Expected Behavior ### Without Community Assets - Game connects to community server ✅ - Gameplay works (with existing assets) ✅ - New cars might not load properly ❌ - Missing tracks won't be available ❌ ### With Community Assets - Game connects to community server ✅ - Downloads assets from community server ✅ - All content available ✅ - Full offline gameplay ✅ ## 📚 Resources - **Unity .pak Format**: Research Unity asset bundle format - **EA Nimble SDK**: Understanding the download system - **Asset Extraction Tools**: QuickBMS, Unity Asset Bundle Extractor - **Network Analysis**: Charles Proxy, Wireshark --- **This enables TRUE game preservation!** 🎮 Players can download all game content from community servers, making RR3 fully playable even if EA shuts down their servers! **Legal Note**: Only use assets you legally own. This is for preservation, not piracy.