DenchiSoft / VTubeStudio

VTube Studio API Development Page
MIT License
826 stars 77 forks source link

BUG : InjectParameterDataRequest validate invalid value data #70

Open azekiia opened 9 months ago

azekiia commented 9 months ago

Explanation

This bug echoes observations we have made about the VTS-Sharp framework: https://github.com/FomTarro/VTS-Sharp/issues/36

A custom parameter for which I injected a value was never updated, but I received a positive response from the API.

On further investigation, it appears that the API endpoint does not check the type of the given value for the keys :

To test this, let's consider a parameter InputTestParameter defined as :

{
                "parameterName": "InputTestParameter",
                "explanation": "This is my new parameter.",
                "min": 0,
                "max": 1,
                "defaultValue": 0.5
}

Exchanged message

Value outside the bounds

Sent

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701634822409,
  "requestID": "52297ca7-3332-4585-aa31-79e4f8a9525e",
  "messageType": "InjectParameterDataRequest",
  "data": {
    "faceFound": false,
    "mode": "set",
    "parameterValues": [
      {
        "id": "InputTestParameter",
        "value": 10
      }
    ]
  }
}

Received

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701634822421,
  "messageType": "InjectParameterDataResponse",
  "requestID": "52297ca7-3332-4585-aa31-79e4f8a9525e",
  "data": {}
}

Value is null

Sent

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635150890,
  "requestID": "f599ccdf-0bdf-4069-9708-06d0106755c3",
  "messageType": "InjectParameterDataRequest",
  "data": {
    "faceFound": false,
    "mode": "set",
    "parameterValues": [
      {
        "id": "InputTestParameter",
        "value": null
      }
    ]
  }
}

Received

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635150899,
  "messageType": "InjectParameterDataResponse",
  "requestID": "f599ccdf-0bdf-4069-9708-06d0106755c3",
  "data": {}
}

Value is string

Sent

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635368284,
  "requestID": "40a8f809-f427-49ab-a288-66fc8e3407fc",
  "messageType": "InjectParameterDataRequest",
  "data": {
    "faceFound": false,
    "mode": "set",
    "parameterValues": [
      {
        "id": "InputTestParameter",
        "value": "arbitrary string"
      }
    ]
  }
}

Received

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635368294,
  "messageType": "InjectParameterDataResponse",
  "requestID": "40a8f809-f427-49ab-a288-66fc8e3407fc",
  "data": {}
}

Weight is a string (or null)

Sent

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635771971,
  "requestID": "a70944b1-f23f-4cf3-9d79-4d716579bcc5",
  "messageType": "InjectParameterDataRequest",
  "data": {
    "faceFound": false,
    "mode": "set",
    "parameterValues": [
      {
        "id": "InputTestParameter",
        "value": 0.9,
        "weight": "my string"
      }
    ]
  }
}

Received

{
  "apiName": "VTubeStudioPublicAPI",
  "apiVersion": "1.0",
  "timestamp": 1701635771982,
  "messageType": "InjectParameterDataResponse",
  "requestID": "a70944b1-f23f-4cf3-9d79-4d716579bcc5",
  "data": {}
}

Suggestion

The current behavior may be misleading when using the API, as the parameter is not injected. It would be interesting to explicit the reason if the type or the values of these fields are incorrect.

azekiia commented 9 months ago

On a side note,

DenchiSoft commented 8 months ago

Thanks for reporting. This behavior is a bit strange but it's the expected behavior from this serializer. I am using JsonUtility here, probably should look into switching to Newtonsoft (already using that one for the event payloads).

The Unity serializer will just use default values for any fields it cannot deserialize without any error indication. Which means that any value for a float field passed in as string will have the float default value 0.

If you actually pass in NaN (as float, not as string, for example using "value": float('nan') in python), it will get correctly deserialized as NaN and you will receive the appropriate error response:

{
    "apiName": "VTubeStudioPublicAPI",
    "apiVersion": "1.0",
    "timestamp": 1704038461572,
    "messageType": "APIError",
    "requestID": "17bb655841114c35b290e7f65cc27cc6",
    "data": {
        "errorID": 451,
        "message": "Value for parameter FaceAngleX not provided or to big/small."
    }
}

Not sure there is a good solution for this without switching the serializer.