Repository navigation
Feature Request - Communication System + YNOP Data Get/Set system #55
Copy link
Copy link
Open
Description
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
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Desdaemon commentedon Mar 7, 2025
@jetrotal Sorry for the delay since I have been away from contributing to ynoengine. I have a few suggestions:
RpcPacketthat is roughly modelled after JSONRPC which will look something like this:The client would send this packet to the server and create a callback to asynchronously handle the server's response.
ProcessBridgeRequestwill be able to return a string, but instead will accept a callback:If this distinction is important, we can split
ProcessBridgeRequestinto another variant that does return a binding and force the caller to hold onto it in some manner, perhaps on the Scene itself.Would you be willing to submit a PR for this? I apologize for not being able to spend more time on this, but I should be able to work on the server part regardless. Most validation can be done on the server instead, and any protocol between client and server can be defined in an adhoc manner without recompiling the engine (except to change client's behavior).
Add YNO extensions and YnoAsyncRpc command
Add YNO extensions and YnoAsyncRpc command
Add YNO extensions and YnoAsyncRpc command
DeanLemans commentedon Sep 30, 2025
any news on this?