# OpenOSRS Login System Documentation

This document provides comprehensive documentation for the OpenOSRS modernized client login system, designed specifically for AI agent automation.

## Table of Contents

1. [Overview](#overview)
2. [Architecture](#architecture)
3. [Core Components](#core-components)
4. [Agent API](#agent-api)
5. [Usage Examples](#usage-examples)
6. [Error Handling](#error-handling)
7. [Security Features](#security-features)
8. [Advanced Features](#advanced-features)
9. [Configuration](#configuration)
10. [Troubleshooting](#troubleshooting)

## Overview

The OpenOSRS login system provides a complete, agent-friendly authentication solution for Old School RuneScape. It offers both synchronous and asynchronous login methods, comprehensive error handling, OTP support, automatic reconnection, and extensive event monitoring.

### Key Features

- **Agent-Optimized**: Designed specifically for AI agents with programmatic interfaces
- **Comprehensive Authentication**: Support for username/password and OTP authentication
- **Asynchronous Operations**: Non-blocking login operations with CompletableFuture support
- **Event-Driven**: Complete event system for monitoring login state changes
- **Auto-Reconnection**: Automatic reconnection with configurable retry logic
- **Error Handling**: Detailed error codes and messages for all failure scenarios
- **Session Management**: Proper session token and ID handling
- **Security**: Encrypted packet transmission and secure credential handling

## Architecture

The login system follows a layered architecture:

```
┌─────────────────────────────────────────┐
│              Agent API                  │  ← High-level agent interface
├─────────────────────────────────────────┤
│            Login Screen                 │  ← UI abstraction layer
├─────────────────────────────────────────┤
│            Login State                  │  ← State management
├─────────────────────────────────────────┤
│            Event System                 │  ← Event handling
├─────────────────────────────────────────┤
│          Network Protocol               │  ← Network communication
├─────────────────────────────────────────┤
│           Client Core                   │  ← Core client systems
└─────────────────────────────────────────┘
```

## Core Components

### LoginState

**Location**: `com.openosrs.client.core.CoreStates.LoginState`

Manages the current login state and credentials.

```java
// State enumeration
public enum State {
    LOGGED_OUT,     // Not logged in
    LOGGING_IN,     // Login in progress
    LOGGED_IN,      // Successfully logged in
    LOGIN_FAILED,   // Login failed
    LOGGED_OUT_TIMEOUT // Logged out due to timeout
}

// Key methods
public void setCredentials(String username, String password, String otp)
public void attemptLogin()
public void logout()
public State getState()
public boolean isValidCredentials()
```

### LoginScreen

**Location**: `com.openosrs.client.core.LoginScreen`

Provides high-level login screen management for agents.

```java
// Synchronous login methods
public LoginResult login(String username, String password)
public LoginResult login(String username, String password, String otp)
public LoginResult loginWithTimeout(String username, String password, int timeoutSeconds)

// Asynchronous login methods
public CompletableFuture<LoginResult> loginAsync(String username, String password)
public void loginAsync(String username, String password, Consumer<LoginResult> callback)

// State queries
public boolean isLoggedIn()
public boolean isLoginInProgress()
public LoginState.State getCurrentState()
```

### LoginHandler

**Location**: `com.openosrs.client.engine.NetworkProtocol.LoginHandler`

Handles the network protocol for login authentication.

```java
// Core functionality
public void handleLoginResponse(NetworkEngine.IncomingMessage message)
public void sendLoginRequest(NetworkEngine.OutgoingMessage message)
public boolean isLoginInProgress()

// Supported login response codes
LOGIN_SUCCESS = 0
LOGIN_INVALID_CREDENTIALS = 3
LOGIN_ACCOUNT_DISABLED = 4
LOGIN_ALREADY_ONLINE = 5
LOGIN_WORLD_FULL = 7
// ... and 17 more error codes
```

### EventSystem

**Location**: `com.openosrs.client.core.EventSystem`

Provides comprehensive event handling for login operations.

```java
// Login-specific event types
LOGIN_ATTEMPT_STARTED
LOGIN_SUCCESS
LOGIN_FAILED
LOGIN_PROGRESS
LOGOUT
DISCONNECTED
RECONNECTING

// Event listener management
public void addListener(EventType type, Consumer<Event> listener)
public void removeListener(EventType type, Consumer<Event> listener)
public void fireEvent(EventType type, Event event)
```

## Agent API

**Location**: `com.openosrs.client.api.AgentAPI`

The primary interface for AI agents to interact with the login system.

### Basic Login Methods

```java
AgentAPI api = new AgentAPI(clientCore);
api.initialize();

// Synchronous login (blocking)
AgentAPI.LoginResult result = api.login("username", "password");
if (result.isSuccess()) {
    System.out.println("Login successful! Session: " + result.getSessionId());
} else {
    System.out.println("Login failed: " + result.getMessage());
}

// Asynchronous login (non-blocking)
CompletableFuture<AgentAPI.LoginResult> future = api.loginAsync("username", "password");
future.thenAccept(result -> {
    if (result.isSuccess()) {
        System.out.println("Async login successful!");
    }
});
```

### OTP Support

```java
// Login with One-Time Password
AgentAPI.LoginResult result = api.login("username", "password", "123456");
```

### Callback-Based Login

```java
// Set up login callbacks
api.setLoginCallbacks(
    result -> System.out.println("Success: " + result),
    error -> System.out.println("Error: " + error),
    progress -> System.out.println("Progress: " + progress)
);

// Start async login
api.loginAsync("username", "password", "otp");
```

### Auto-Reconnection

```java
// Enable auto-reconnection
api.setAutoReconnect(true, 30, 5); // 30 second delay, 5 max attempts

// Auto-reconnection will now handle disconnections automatically
```

### State Monitoring

```java
// Check login state
boolean loggedIn = api.isLoggedIn();
boolean loginInProgress = api.isLoginInProgress();
LoginState.State state = api.getLoginState();

// Get game state (when logged in)
AgentAPI.Position position = api.getPlayerPosition();
int health = api.getPlayerHealth();
boolean moving = api.isPlayerMoving();
```

### Event Listening

```java
// Listen for login events
api.addEventListener(EventSystem.EventType.LOGIN_SUCCESS, event -> {
    System.out.println("Login successful!");
});

api.addEventListener(EventSystem.EventType.LOGIN_FAILED, event -> {
    System.out.println("Login failed!");
});

api.addEventListener(EventSystem.EventType.DISCONNECTED, event -> {
    System.out.println("Connection lost!");
});
```

## Usage Examples

### Simple Login Example

```java
public class SimpleAgent {
    public static void main(String[] args) {
        ClientCore clientCore = new ClientCore();
        AgentAPI api = new AgentAPI(clientCore);
        
        try {
            clientCore.initialize();
            api.initialize();
            
            AgentAPI.LoginResult result = api.login("myusername", "mypassword");
            
            if (result.isSuccess()) {
                System.out.println("Successfully logged in!");
                
                // Agent is now ready to play
                while (api.isLoggedIn()) {
                    // Game logic here
                    Thread.sleep(1000);
                }
            } else {
                System.out.println("Login failed: " + result.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            api.shutdown();
            clientCore.shutdown();
        }
    }
}
```

### Advanced Agent with Auto-Reconnection

```java
public class AdvancedAgent {
    private ClientCore clientCore;
    private AgentAPI api;
    private volatile boolean running = true;
    
    public void start() {
        clientCore = new ClientCore();
        api = new AgentAPI(clientCore);
        
        try {
            clientCore.initialize();
            api.initialize();
            
            // Enable auto-reconnection
            api.setAutoReconnect(true, 30, 10);
            
            // Set up event monitoring
            setupEventListeners();
            
            // Initial login
            performLogin();
            
            // Main game loop
            gameLoop();
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            cleanup();
        }
    }
    
    private void setupEventListeners() {
        api.addEventListener(EventSystem.EventType.LOGIN_SUCCESS, event -> {
            System.out.println("✅ Connected and ready!");
        });
        
        api.addEventListener(EventSystem.EventType.DISCONNECTED, event -> {
            System.out.println("🔌 Connection lost - auto-reconnection will handle this");
        });
        
        api.addEventListener(EventSystem.EventType.LOGIN_FAILED, event -> {
            System.out.println("❌ Login failed - check credentials");
        });
    }
    
    private void performLogin() {
        String username = System.getenv("OSRS_USERNAME");
        String password = System.getenv("OSRS_PASSWORD");
        String otp = System.getenv("OSRS_OTP");
        
        if (username == null || password == null) {
            throw new IllegalArgumentException("Username and password must be set in environment variables");
        }
        
        api.loginAsync(username, password, otp).thenAccept(result -> {
            if (!result.isSuccess()) {
                System.err.println("Initial login failed: " + result.getMessage());
                running = false;
            }
        });
    }
    
    private void gameLoop() {
        while (running) {
            try {
                if (api.isLoggedIn()) {
                    // Perform game actions
                    doGameAction();
                } else {
                    // Wait for reconnection
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
    
    private void doGameAction() {
        // Example game logic
        AgentAPI.Position pos = api.getPlayerPosition();
        int health = api.getPlayerHealth();
        
        System.out.println("Player at " + pos + ", health: " + health);
        
        try {
            Thread.sleep(5000); // Wait 5 seconds between actions
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private void cleanup() {
        if (api != null) {
            api.logout();
            api.shutdown();
        }
        if (clientCore != null) {
            clientCore.shutdown();
        }
    }
}
```

## Error Handling

The login system provides comprehensive error handling with specific error codes and messages.

### Login Error Codes

| Code | Constant | Description |
|------|----------|-------------|
| 0 | LOGIN_SUCCESS | Login successful |
| 3 | LOGIN_INVALID_CREDENTIALS | Invalid username or password |
| 4 | LOGIN_ACCOUNT_DISABLED | Account has been disabled |
| 5 | LOGIN_ALREADY_ONLINE | Account is already logged in |
| 6 | LOGIN_SERVER_UPDATED | Game updated - reload client |
| 7 | LOGIN_WORLD_FULL | World is full |
| 8 | LOGIN_LOGIN_SERVER_OFFLINE | Login server offline |
| 9 | LOGIN_LOGIN_LIMIT_EXCEEDED | Too many connections |
| 10 | LOGIN_BAD_SESSION_ID | Unable to connect |
| 11 | LOGIN_FORCE_PASSWORD_CHANGE | Password change required |
| 12 | LOGIN_NEED_MEMBERS_ACCOUNT | Members account required |
| 13 | LOGIN_COULD_NOT_COMPLETE_LOGIN | Could not complete login |
| 14 | LOGIN_SERVER_BEING_UPDATED | Server being updated |
| 15 | LOGIN_RECONNECTING | Reconnecting |
| 16 | LOGIN_LOGIN_ATTEMPTS_EXCEEDED | Too many login attempts |
| 17 | LOGIN_MEMBERS_ONLY_AREA | Members only area |
| 18 | LOGIN_LOCKED_ACCOUNT | Account locked |
| 19 | LOGIN_CLOSE_OTHER_CONNECTION | Close other connection |
| 20 | LOGIN_MALFORMED_PACKET | Malformed packet |
| 21 | LOGIN_NO_REPLY_FROM_LOGIN_SERVER | No reply from login server |
| 22 | LOGIN_ERROR_LOADING_PROFILE | Error loading profile |
| 23 | LOGIN_UNKNOWN_REPLY_FROM_LOGIN_SERVER | Unknown reply from login server |
| 26 | LOGIN_IP_BLOCKED | IP address blocked |

### Error Handling Examples

```java
AgentAPI.LoginResult result = api.login("username", "password");

if (!result.isSuccess()) {
    String message = result.getMessage();
    
    if (message.contains("Invalid username or password")) {
        // Handle credential error
        System.out.println("Credentials are incorrect");
    } else if (message.contains("World is full")) {
        // Try different world
        System.out.println("World is full, trying different world");
    } else if (message.contains("too many login attempts")) {
        // Wait before retrying
        System.out.println("Rate limited, waiting before retry");
        Thread.sleep(60000); // Wait 1 minute
    }
}
```

## Security Features

### Credential Security

- Credentials are not stored in plain text
- Passwords are cleared from memory after use
- OTP codes are handled securely
- Session tokens are encrypted in transmission

### Network Security

- All login packets are encrypted
- Session verification prevents replay attacks
- Automatic session timeout handling
- Secure random session ID generation

### Best Practices

```java
// Store credentials securely
String username = System.getenv("OSRS_USERNAME");
String password = System.getenv("OSRS_PASSWORD");
String otp = System.getenv("OSRS_OTP");

// Use environment variables, not hardcoded strings
AgentAPI.LoginResult result = api.login(username, password, otp);

// Clear sensitive data
username = null;
password = null;
otp = null;
```

## Advanced Features

### Session Management

```java
// Get session information
if (api.isLoggedIn()) {
    LoginState loginState = clientCore.getLoginState();
    int sessionId = loginState.getSessionId();
    String sessionToken = loginState.getSessionToken();
    
    System.out.println("Session ID: " + sessionId);
    System.out.println("Session Token: " + sessionToken);
}
```

### Timeout Configuration

```java
// Custom login timeout
AgentAPI.LoginResult result = api.login("username", "password", null, 60); // 60 second timeout
```

### Progress Monitoring

```java
api.setLoginCallbacks(
    null, // success callback
    null, // error callback
    progress -> System.out.println("Login progress: " + progress) // progress callback
);
```

## Configuration

### Environment Variables

```bash
# Required for login
export OSRS_USERNAME="your_username"
export OSRS_PASSWORD="your_password"

# Optional
export OSRS_OTP="123456"  # If using OTP
export OSRS_WORLD="301"   # Preferred world
export OSRS_AUTO_RECONNECT="true"  # Enable auto-reconnection
```

### System Properties

```bash
# Enable debug logging
-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG

# Custom timeouts
-Dosrs.login.timeout=30000
-Dosrs.reconnect.delay=30000
-Dosrs.reconnect.maxAttempts=5
```

## Troubleshooting

### Common Issues

**Login Timeout**
```
Error: Login timeout or error: TimeoutException
```
*Solution*: Increase timeout or check network connectivity

**Invalid Credentials**
```
Error: Invalid username or password
```
*Solution*: Verify credentials, check for typos

**World Full**
```
Error: This world is full. Please use a different world
```
*Solution*: Try different world or wait for space

**Too Many Attempts**
```
Error: Too many login attempts. Please wait a few minutes
```
*Solution*: Wait before retrying, implement exponential backoff

### Debug Logging

Enable debug logging to troubleshoot issues:

```java
// In code
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG");

// Or via JVM arguments
-Dorg.slf4j.simpleLogger.defaultLogLevel=DEBUG
-Dorg.slf4j.simpleLogger.showDateTime=true
-Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss.SSS
```

### Network Issues

```java
// Test network connectivity
if (!api.isLoggedIn()) {
    // Check if it's a network issue
    try {
        InetAddress.getByName("oldschool.runescape.com").isReachable(5000);
        System.out.println("Network connectivity OK");
    } catch (IOException e) {
        System.out.println("Network connectivity issues: " + e.getMessage());
    }
}
```

## Running the Example

To run the login example:

```bash
# Using Gradle
./gradlew runLoginExample

# Or compile and run directly
./gradlew build
java -cp build/libs/modernized-client-1.0.0.jar com.openosrs.client.examples.ExampleLoginAgent
```

The example provides an interactive menu to test different login scenarios:

1. Basic Login (Synchronous)
2. Async Login (CompletableFuture)
3. Login with OTP
4. Login with Callbacks
5. Auto-Reconnection Demo
6. Error Handling Demo
7. Show Game State
8. Logout and Exit

---

**Note**: This documentation covers the complete login system implementation. All features are designed to work seamlessly with AI agents while providing the flexibility and reliability needed for automated gameplay.