Skip to content

Feature Request - Communication System + YNOP Data Get/Set system #55

@jetrotal

Description

@jetrotal

Heyo @Desdaemon, I put together some of what we spoke earlier about this feature:

Simple Communication System + YNOP Data receiver for EasyRPG

Allows the player to recieve or send data to the server

1. Basic Operations

GET Operation (0)

// Client sends:
{
    "request": "path/to/data",
    "type": 0,              // GET operation
}

// Server responds:
{
    "status": "ok",
    "data": "string_value"  // Converted based on target_type
}

SET Operation (1)

// Client sends:
{
    "request": "path/to/data",
    "type": 1,              // SET operation
    "data": "string_value", // Value to set
}

// Server responds:
{
    "status": "ok",
    "error": null          // Optional: contains error message if status is "error"
}

2. Other Features

Player Data Operations

// GET Player Name: "player/name"
Request:
{
    "request": "player/name",
    "type": 0
}

Response:
{
    "status": "ok",
    "data": "PlayerName"
}

3. Error Handling

// Error Response Format
{
    "status": "error",
    "error": "Detailed error message",
    "code": 404           // Optional: HTTP-style error code
}

// Common Error Types
{
    "status": "error",
    "error": "File not found",
    "code": 404
}

{
    "status": "error",
    "error": "Invalid JSON format",
    "code": 400
}

4. Command Structure (5000)

(Just for reference, code is almost pseudo-code)

//Inside GAME_INTERPRETER.CPP edit ExecuteCommand:
bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) { 
    switch (static_cast<Cmd>(com.code)) {
        case static_cast<Cmd>(5000):  // or "Cmd::YNOP_Bridge" If you want to mess with liblcf
            return CommandYNOPBridge(com);
    }
}

// Then add this method:
bool Game_Interpreter::CommandYNOPBridge(lcf::rpg::EventCommand const& com) { //5000
    
    std::string request_path = ToString(CommandStringOrVariable(com, 8, 9));
    int operation = ValueOrVariable(com.parameters[0], com.parameters[1]);
    int source_var_id = ValueOrVariable(com.parameters[2], com.parameters[3]);
    int target_type = ValueOrVariable(com.parameters[4], com.parameters[5]);
    int target_var_id = ValueOrVariable(com.parameters[6], com.parameters[7]);

    std::stringstream json;

    if (operation == 0) { //get
        json << "{"
             << "\"request\":\"" << request_path << "\","
             << "\"type\":" << operation 
             << "}";

        std::string response = ProcessBridgeRequest(json.str()); // Process GET request
        
        // Handle the response
        if (!response.empty()) {
            switch (target_type) {
                case 0: // Switch
                    Main_Data::game_switches->Set(target_var_id, atoi(response.c_str()) != 0);
                    break;
                case 1: // Variable
                    Main_Data::game_variables->Set(target_var_id, atoi(response.c_str()));
                    break;
                case 2: // String
                    Main_Data::game_strings->Set(target_var_id, response);
                    break;
                default:
                    Output::Warning("CommandYNOPBridge: Unsupported target_type {}", target_type);
                    return true;
            }
        }
    }

    if (operation == 1) { //set
        std::string value_data;
        
        switch (target_type) {
            case 0: // Switch
                value_data = std::to_string(Main_Data::game_switches->Get(target_var_id));
                break;
            case 1: // Variable
                value_data = std::to_string(Main_Data::game_variables->Get(target_var_id));
                break;
            case 2: // String
                value_data = ToString(Main_Data::game_strings->Get(target_var_id));
                break;
            default:
                Output::Warning("CommandYNOPBridge: Unsupported target_type {}", target_type);
                return true;
        }

        json << "{"
             << "\"request\":\"" << request_path << "\","
             << "\"type\":" << operation << ","
             << "\"data\":\"" << value_data << "\""
             << "}";
        
        std::string response = ProcessBridgeRequest(json.str()); // Process SET request
        
        // Handle response status if needed (stored in target_var_id)
        if (!response.empty() && target_var_id > 0) {
            Main_Data::game_strings->Set(target_var_id, response);
        }
    }

    return true;
}

5. Storage Guidelines

Server-Side Storage

  • Use flat file storage for JSON data
    • One file per map/player/configuration
    • Directory structure matches request paths
    • Example: cu/playermaps/PlayerName/mapname.json
  • File Operations
    • Read entire file for GET operations
    • Write atomic updates for SET operations
    • Use file locking for concurrent access
  • Basic Validation
    • Check for Logged Players
    • Check JSON syntax
    • Verify required fields
    • Validate data types

Client-Side Handling

  • Variable Types
    • Switches (0): Boolean values
    • Variables (1): Numeric values
    • Strings (2): Text and JSON data

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions