# RR3 Community Server - Multiplayer & Social Features Implementation Plan
**Date:** February 24, 2026
**Goal:** 100% EA Server Replacement (Future-Proof for EA Shutdown)
**Current Status:** 72 endpoints (core game complete), multiplayer/social needed

---

## 🎯 Mission Statement

When EA shuts down Real Racing 3 servers, players should be able to:
- Continue playing career mode ✅ (DONE)
- Access time trials & leaderboards ✅ (DONE)
- **Race against friends online** ⏳ (TODO)
- **Manage friend lists** ⏳ (TODO)
- **Join clubs/teams** ⏳ (TODO)
- **Compete in multiplayer events** ⏳ (TODO)

**We need multiplayer and social features for a complete replacement.**

---

## 📊 Current Implementation Status

### ✅ Complete (72 endpoints):
1. Director API (1)
2. User Service (3)
3. Product/Catalog (3)
4. DRM (3)
5. Config (4)
6. Progression (7)
7. Rewards/Time Trials (8)
8. Tracking (2)
9. Assets (4)
10. Settings (3)
11. Modding (7)
12. Leaderboards (6)
13. Events (4)
14. Notifications (5)
15. Asset Management (4)
16. Authentication (8)

### ⏳ Missing for 100% Coverage:
17. **Friends/Social Service** (0/11 endpoints) - includes Clubs/Teams
18. **Multiplayer Service** (0/12 endpoints) - includes Ranked

---

## 🔍 Research Findings from APK (v14 Branch)

### EA Nimble SDK Friends System

**Source:** `com/ea/nimble/bridge/FriendsNativeCallback.smali`

**Key Interfaces Found:**
- `NimbleFriendsRefreshCallback` - Friend list sync
- `INimbleOriginFriendsService\` - User search
- `INimbleOriginFriendsService\` - Friend invites

**Friend System Components:**
- `NimbleFriendsList` - Friend list data structure
- `NimbleFriendsRefreshScope` - Refresh strategy (full/partial)
- `NimbleFriendsRefreshResult` - Sync result status
- `NimbleUser` - User profile data

### Google Play Services Integration

**Source:** `com/google/android/gms/games/multiplayer/*`

**Multiplayer APIs Found:**
- Real-time multiplayer (`realtime/` package)
- Room-based matchmaking
- Participant management
- Turn-based multiplayer support

**Note:** These are Google Play Services APIs, not EA's custom protocol. 
RR3 likely uses BOTH:
1. Google Play for matchmaking/lobby
2. EA servers for race data/results

---

## 📋 Friends/Social Service Implementation Plan

### Service: `/synergy/friends` or `/social/api/android`

### Estimated: 11 Endpoints (Clubs/Teams REQUIRED)

#### 1. Friend List Management (4 endpoints)

**GET /synergy/friends/list**
- Get player's friend list
- Parameters: `synergyId`, `page`, `perPage`
- Returns: Array of friend objects (name, level, last online, etc.)

**POST /synergy/friends/add**
- Send friend request
- Parameters: `synergyId` (requester), `targetSynergyId` or `targetUsername`
- Returns: Request status, invitation ID

**POST /synergy/friends/accept**
- Accept friend request
- Parameters: `synergyId`, `invitationId`
- Returns: Updated friend list

**DELETE /synergy/friends/remove**
- Remove friend
- Parameters: `synergyId`, `friendSynergyId`
- Returns: Success status

#### 2. Friend Search & Discovery (2 endpoints)

**GET /synergy/friends/search**
- Search for players by username/Synergy ID
- Parameters: `query`, `limit`
- Returns: Array of matching users

**GET /synergy/friends/suggestions**
- Get friend suggestions (mutual friends, nearby players, etc.)
- Parameters: `synergyId`, `limit`
- Returns: Suggested users

#### 3. Social Interactions (2-3 endpoints)

**POST /synergy/friends/gift/send**
- Send gift to friend (in-game currency, items)
- Parameters: `synergyId`, `friendSynergyId`, `giftType`, `amount`
- Returns: Gift transaction status

**GET /synergy/friends/gifts/pending**
- Get pending gifts
- Parameters: `synergyId`
- Returns: Array of unclaimed gifts

**POST /synergy/friends/gifts/claim**
- Claim a gift
- Parameters: `synergyId`, `giftId`
- Returns: Updated inventory

#### 4. Clubs/Teams (REQUIRED, 3 endpoints)

**GET /synergy/clubs/list**
- Get available clubs/teams
- Returns: Public clubs, recruitment status

**POST /synergy/clubs/join**
- Join a club
- Parameters: `synergyId`, `clubId`

**GET /synergy/clubs/{clubId}/members**
- Get club members and stats

---

## 📋 Multiplayer Service Implementation Plan

### Service: `/synergy/multiplayer` or `/multiplayer/api/android`

### Estimated: 12 Endpoints (Ranked REQUIRED)

#### 1. Matchmaking (3 endpoints)

**POST /synergy/multiplayer/matchmaking/queue**
- Join matchmaking queue
- Parameters: `synergyId`, `carClass`, `track`, `gameMode`
- Returns: Queue status, estimated wait time

**GET /synergy/multiplayer/matchmaking/status**
- Check matchmaking status
- Parameters: `synergyId`, `queueId`
- Returns: Match found status, lobby ID

**DELETE /synergy/multiplayer/matchmaking/leave**
- Leave matchmaking queue
- Parameters: `synergyId`, `queueId`

#### 2. Race Sessions (4 endpoints)

**POST /synergy/multiplayer/session/create**
- Create private race session
- Parameters: `synergyId`, `track`, `carClass`, `maxPlayers`, `settings`
- Returns: Session ID, join code

**POST /synergy/multiplayer/session/join**
- Join race session
- Parameters: `synergyId`, `sessionId` or `joinCode`
- Returns: Session details, participant list

**GET /synergy/multiplayer/session/{sessionId}**
- Get session details
- Returns: Participants, ready status, countdown timer

**POST /synergy/multiplayer/session/{sessionId}/ready**
- Mark player as ready
- Parameters: `synergyId`

#### 3. Ghost Data (2 endpoints)

**POST /synergy/multiplayer/ghost/upload**
- Upload ghost race data
- Parameters: `synergyId`, `track`, `carId`, `ghostData` (telemetry)
- Returns: Ghost ID

**GET /synergy/multiplayer/ghost/download**
- Download friend/top player ghost
- Parameters: `track`, `synergyId` or `leaderboardRank`
- Returns: Ghost telemetry data

#### 4. Race Results (2 endpoints)

**POST /synergy/multiplayer/race/submit**
- Submit race results
- Parameters: `synergyId`, `sessionId`, `raceTime`, `position`, `telemetry`
- Returns: Rewards, rating change

**GET /synergy/multiplayer/race/{sessionId}/results**
- Get race results for all players
- Returns: Final standings, times, rewards

#### 5. Ranked/Competitive (REQUIRED, 2 endpoints)

**GET /synergy/multiplayer/ranked/rating**
- Get player's competitive rating
- Parameters: `synergyId`
- Returns: Rating, rank, division

**GET /synergy/multiplayer/ranked/leaderboard**
- Get competitive leaderboard
- Returns: Top players by rating

---

## 🗄️ Database Schema Extensions

### Friends System Tables

\\\sql
-- Friend relationships
CREATE TABLE Friends (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    User1Id INTEGER NOT NULL,
    User2Id INTEGER NOT NULL,
    Status VARCHAR(20) NOT NULL, -- 'pending', 'accepted', 'blocked'
    RequestedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    AcceptedAt DATETIME,
    FOREIGN KEY (User1Id) REFERENCES Users(Id),
    FOREIGN KEY (User2Id) REFERENCES Users(Id),
    UNIQUE(User1Id, User2Id)
);

-- Friend invitations
CREATE TABLE FriendInvitations (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    FromUserId INTEGER NOT NULL,
    ToUserId INTEGER NOT NULL,
    Status VARCHAR(20) NOT NULL, -- 'pending', 'accepted', 'declined', 'expired'
    CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    ExpiresAt DATETIME,
    FOREIGN KEY (FromUserId) REFERENCES Users(Id),
    FOREIGN KEY (ToUserId) REFERENCES Users(Id)
);

-- Gifts between friends
CREATE TABLE Gifts (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    FromUserId INTEGER NOT NULL,
    ToUserId INTEGER NOT NULL,
    GiftType VARCHAR(50) NOT NULL, -- 'gold', 'cash', 'item'
    Amount INTEGER,
    ItemId VARCHAR(100),
    Message TEXT,
    Status VARCHAR(20) NOT NULL, -- 'sent', 'claimed'
    SentAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    ClaimedAt DATETIME,
    FOREIGN KEY (FromUserId) REFERENCES Users(Id),
    FOREIGN KEY (ToUserId) REFERENCES Users(Id)
);

-- Clubs/Teams
CREATE TABLE Clubs (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    Name VARCHAR(100) NOT NULL UNIQUE,
    Description TEXT,
    Tag VARCHAR(10),
    OwnerId INTEGER NOT NULL,
    MemberCount INTEGER DEFAULT 1,
    MaxMembers INTEGER DEFAULT 50,
    IsPublic BOOLEAN DEFAULT TRUE,
    CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (OwnerId) REFERENCES Users(Id)
);

-- Club memberships
CREATE TABLE ClubMembers (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    ClubId INTEGER NOT NULL,
    UserId INTEGER NOT NULL,
    Role VARCHAR(20) NOT NULL, -- 'owner', 'admin', 'member'
    JoinedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (ClubId) REFERENCES Clubs(Id),
    FOREIGN KEY (UserId) REFERENCES Users(Id),
    UNIQUE(ClubId, UserId)
);
\\\

### Multiplayer System Tables

\\\sql
-- Matchmaking queue
CREATE TABLE MatchmakingQueue (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    UserId INTEGER NOT NULL,
    QueueId VARCHAR(36) NOT NULL,
    GameMode VARCHAR(50) NOT NULL,
    Track VARCHAR(100),
    CarClass VARCHAR(50),
    Rating INTEGER,
    QueuedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    Status VARCHAR(20) NOT NULL, -- 'queued', 'matched', 'cancelled'
    FOREIGN KEY (UserId) REFERENCES Users(Id)
);

-- Race sessions
CREATE TABLE RaceSessions (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    SessionId VARCHAR(36) NOT NULL UNIQUE,
    HostUserId INTEGER NOT NULL,
    Track VARCHAR(100) NOT NULL,
    CarClass VARCHAR(50),
    MaxPlayers INTEGER DEFAULT 8,
    JoinCode VARCHAR(10),
    Status VARCHAR(20) NOT NULL, -- 'waiting', 'ready', 'racing', 'finished'
    CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    StartedAt DATETIME,
    FinishedAt DATETIME,
    FOREIGN KEY (HostUserId) REFERENCES Users(Id)
);

-- Session participants
CREATE TABLE SessionParticipants (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    SessionId INTEGER NOT NULL,
    UserId INTEGER NOT NULL,
    IsReady BOOLEAN DEFAULT FALSE,
    Position INTEGER,
    RaceTime DOUBLE,
    JoinedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (SessionId) REFERENCES RaceSessions(Id),
    FOREIGN KEY (UserId) REFERENCES Users(Id)
);

-- Ghost data
CREATE TABLE GhostData (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    UserId INTEGER NOT NULL,
    Track VARCHAR(100) NOT NULL,
    CarId VARCHAR(100) NOT NULL,
    RaceTime DOUBLE NOT NULL,
    TelemetryData TEXT NOT NULL, -- JSON blob of position/speed data
    UploadedAt DATETIME DEFAULT CURRENT_TIMESTAMP,
    DownloadCount INTEGER DEFAULT 0,
    FOREIGN KEY (UserId) REFERENCES Users(Id)
);

-- Competitive ratings
CREATE TABLE CompetitiveRatings (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    UserId INTEGER NOT NULL UNIQUE,
    Rating INTEGER DEFAULT 1000,
    Division VARCHAR(20) DEFAULT 'Bronze',
    Wins INTEGER DEFAULT 0,
    Losses INTEGER DEFAULT 0,
    TotalRaces INTEGER DEFAULT 0,
    HighestRating INTEGER DEFAULT 1000,
    Season INTEGER DEFAULT 1,
    LastUpdated DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (UserId) REFERENCES Users(Id)
);
\\\

---

## 🚀 Implementation Phases

### Phase 1: Friends/Social (Week 1-2)
- [ ] Create database schema (Friends, FriendInvitations, Gifts, Clubs)
- [ ] Implement FriendsController.cs (8 endpoints)
- [ ] Add friend search functionality
- [ ] Build gift system
- [ ] Test friend features with APK

### Phase 2: Multiplayer Foundation (Week 2-3)
- [ ] Create database schema (MatchmakingQueue, RaceSessions, GhostData)
- [ ] Implement MultiplayerController.cs (basic endpoints)
- [ ] Build matchmaking queue system
- [ ] Implement race session management

### Phase 3: Ghost Racing (Week 3)
- [ ] Ghost data upload/download endpoints
- [ ] Telemetry data storage (JSON)
- [ ] Friend ghost integration
- [ ] Leaderboard ghost download

### Phase 4: Competitive/Ranked (Week 4)
- [ ] Competitive rating system
- [ ] ELO/MMR calculations
- [ ] Ranked leaderboards
- [ ] Season/division system

### Phase 5: Testing & Polish (Week 5)
- [ ] End-to-end multiplayer testing
- [ ] Friend system testing
- [ ] Performance optimization
- [ ] Documentation

---

## 📝 Technical Considerations

### Multiplayer Synchronization

**Challenge:** Real-time race sync without WebSockets

**Solutions:**
1. **Polling:** Clients poll session status every 100-200ms during race
2. **Long-polling:** Keep connection open, server responds when state changes
3. **SignalR (future):** Add WebSocket support for true real-time

**For MVP:** Use polling. It's simpler and works with current HTTP architecture.

### Ghost Data Format

**Telemetry Structure:**
\\\json
{
  "ghostId": "uuid",
  "synergyId": "SYN-xxx",
  "track": "Silverstone",
  "carId": "porsche_911",
  "raceTime": 125.456,
  "recordedAt": "2026-02-24T00:00:00Z",
  "samples": [
    {"t": 0.0, "x": 0.0, "y": 0.0, "z": 0.0, "speed": 0.0},
    {"t": 0.1, "x": 1.2, "y": 0.0, "z": 0.5, "speed": 15.3},
    // ... more samples every 100ms
  ]
}
\\\

### Matchmaking Algorithm

**Simple ELO-based matching:**
1. Get player's rating
2. Find players within ±200 rating
3. Match by closest rating
4. Wait max 30 seconds, expand range

---

## 🎯 Success Criteria

When complete, players should be able to:
- ✅ Add friends by username/ID
- ✅ See friend list with online status
- ✅ Send/receive gifts
- ✅ Join clubs
- ✅ Queue for multiplayer races
- ✅ Race against friends (async via ghosts or sync if lobbies work)
- ✅ Upload/download ghost data
- ✅ Compete in ranked matches
- ✅ View competitive leaderboards

**Result:** 100% EA server replacement. Game remains playable indefinitely.

---

## 📊 Final Endpoint Count Estimate

| Category | Current | After Friends | After Multiplayer | Total |
|----------|---------|---------------|-------------------|-------|
| Core Services | 72 | 72 | 72 | 72 |
| Friends/Social | 0 | 8-10 | 8-10 | 8-10 |
| Multiplayer | 0 | 0 | 10-12 | 10-12 |
| **TOTAL** | **72** | **80-82** | **90-94** | **90-94** |

**Target:** ~90-94 endpoints for complete EA replacement

---

## 🔄 Next Steps

1. **START:** Friends system database schema
2. Create FriendsController.cs
3. Test friend add/remove with basic UI
4. Move to multiplayer once friends work
5. Iterate based on testing

---

**Ready to Begin Implementation?** ✅

Let's start with the Friends/Social system since it's simpler and multiplayer depends on having friends to play with!
