Skip to content

Commit

Permalink
Updated tutorials related to instances (#144)
Browse files Browse the repository at this point in the history
Changes to Pipeline events
Added support for Group Public, Group+, and Group instances to instance generator widget
  • Loading branch information
VinyarionHyarmendacil authored May 4, 2024
1 parent 4ea2baf commit 65790f9
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 40 deletions.
13 changes: 12 additions & 1 deletion content/tutorials/instances.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ category: general
difficulty: medium
---

Instances are parallell "rooms" or "lobbies" of a world.
Instances are parallel "rooms" or "lobbies" of a world.
Each instance can only hold a limited number of users, but there is no limit on how many instances can exist of a world.
Instances are uniquely identified by the combined World ID and Instance ID.

*Note: as of 2024-05-02, VRChat indicated in [a Developer Update](https://ask.vrchat.com/t/developer-update-2-may-2024/24284#changes-to-instance-apis-and-auto-creation-13) an eventual intent to replace the current system with a UUID-ish system similar to User IDs*

## Instance Generator

{{< instance_generator >}}
Expand Down Expand Up @@ -37,3 +39,12 @@ USA, West | San José | us
USA, East | Washington D.C. | use
Europe | Amsterdam | eu
Japan | Tokyo | jp

### Special Values

The VRChat API has several sentinel values for location strings:

- `""` Pseudo-null value
- `"offline"` Implies a user currently is not either running the VRChat client or connected to the Pipeline (e.g., browser tab open)
- `"traveling"` Indicates a user's client is travelling between instances (e.g., downloading world, synchronizing world state)
- `"private"` Indicates a user's location is not visible to the currently logged-in user. (e.g., Ask Me/Do Not Disturb status, Invite/Invite+/Group instance)
83 changes: 52 additions & 31 deletions content/tutorials/websocket.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,36 @@ It is possible to be connected from multiple locations at the same time. All cli
> }
> ```
## Note on Enumerations
Several JSON string values present in both Websocket API messages and HTTP API responses appear to be contained in predictably consistent sets.
Throughout both APIs, the empty string `""` is returned in places (including the immediately) where it would seem otherwise reasonable to have a `null` or undefined value.
In this part of the documentation, the following `":identifier"`s will be used to describe possible enumeration-ish values:
- `":locationString"`
- `""` Pseudo-null value
- `"offline"` Implies a user currently is not either running the VRChat client or connected to the Pipeline (e.g., browser tab open)
- `"traveling"` Indicates a user's client is travelling between instances (e.g., downloading world, synchronizing world state)
- `"private"` Indicates a user's location is not visible to the currently logged-in user. (e.g., Ask Me/Do Not Disturb status, Invite/Invite+/Group instance)
- *other values* An actual location (see https://vrchatapi.github.io/tutorials/instances/)
- `":platformString"`
- `""` Pseudo-null value
- `"standalonewindows"`
- `"android"`
- `"web"` User is on a https://vrchat.com/home page
- *other values* Some other platform or third-party application (e.g., `"ios"` could be the value for a future build on some Apple devices)
- `":contentRefreshContentTypeEnum"`
- `"gallery"`
- `"icon"`
- `"emoji"`
- `"avatar"`
- `"world"`
- *other values* Some other user-uploaded content
- `":contentRefreshActionTypeEnum"`
- `"created"`
- `"deleted"`
- *other values* Not expected
## Events
### Notification Events
Expand Down Expand Up @@ -209,13 +239,13 @@ A "`friend-online`" event is sent when one of the user's friends has gone online
"type": "friend-online",
"content": {
"userId": ":userId",
"platform": ":platformString",
"location": ":locationString",
"canRequestInvite": <boolean>,
"user": {
// <User Object>, See return data of User API:
// https://vrchatapi.github.io/docs/api/#get-/users/-userId-
},
"location": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"instance": ":instanceId", // This is locationString without the World ID part.
"canRequestInvite": <boolean>
}
}
}
```
Expand All @@ -228,6 +258,7 @@ A "`friend-active`" event is sent when one of the user's friends is active on th
"type": "friend-active",
"content": {
"userid": ":userId",
"platform": ":platformString", // Appears only to be "web" from these events
"user": {
// <User Object>, See return data of User API:
// https://vrchatapi.github.io/docs/api/#get-/users/-userId-
Expand All @@ -243,7 +274,8 @@ A "`friend-offline`" event is sent when one of the user's friends has gone offli
{
"type": "friend-offline",
"content": {
"userId": ":userId"
"userId": ":userId",
"platform": ":platformString", // Appears only to be empty "" from these events
}
}
```
Expand All @@ -266,22 +298,21 @@ A "`friend-update`" event is sent when something about one of the user's friends


#### friend-location
A "`friend-location`" event is sent when one of the user's friends has changed instances. Note that the "`world`" field will be an empty object when the friend is on orange/red, or is in a private world.
A "`friend-location`" event is sent when one of the user's friends has changed instances. Note that the `worldId` field will be `"private"` when the friend is on orange/red, or is in a private world.

```json
{
"type": "friend-location",
"content": {
"userId": ":userId",
"location": ":locationString",
"travelingToLocation": ":locationString", // normally empty "", but when the above "location" is "traveling", this contains the imminent destination
"worldId": ":worldId",
"canRequestInvite": <boolean>,
"user": {
// <User Object>, See return data of User API:
// https://vrchatapi.github.io/docs/api/#get-/users/-userId-
},
"location": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"travelingToLocation": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"instance": ":instanceId", // This is locationString without the World ID part.
"worldId": ":worldId", // wlrd_...
"canRequestInvite": <boolean>
}
}
}
```
Expand Down Expand Up @@ -335,9 +366,9 @@ A "`user-location`" event is sent when the user has changed instances.
// <User Object>, See return data of User API:
// https://vrchatapi.github.io/docs/api/#get-/users/-userId-
},
"location": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"location": ":locationString",
"instance": ":instanceId", // This is locationString without the World ID part.
"worldId": ":worldId", // wlrd_...
"worldId": ":worldId",
"world": {
// <World Object>, See return data of World API:
// https://vrchatapi.github.io/docs/api/#get-/worlds/-worldId-
Expand All @@ -354,8 +385,8 @@ A "`content-refresh`" event is sent when the user adds or removes profile images
{
"type": "content-refresh",
"content": {
"contentType": ":contentRefreshContentTypeEnum", // One of: "gallery", "icon", "emoji", "avatar", "world", ???
"actionType": ":contentRefreshActionTypeEnum" // One of: "created", "deleted", ???
"contentType": ":contentRefreshContentTypeEnum",
"actionType": ":contentRefreshActionTypeEnum"
}
}
```
Expand All @@ -368,7 +399,7 @@ A "`instance-queue-joined`" event is sent when the user queues to join an instan
{
"type": "instance-queue-joined",
"content": {
"instanceLocation": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"instanceLocation": ":locationString",
"position": <number> // Integer position in queue
}
}
Expand All @@ -382,7 +413,7 @@ A "`instance-queue-ready`" event is sent when the user is at the front of the qu
{
"type": "instance-queue-ready",
"content": {
"instanceLocation": ":locationString", // Refer to https://vrchatapi.github.io/tutorials/instances/
"instanceLocation": ":locationString",
"expiry": ":dateTimeString" // Time at which priority will be lost
}
}
Expand Down Expand Up @@ -419,25 +450,15 @@ A "`group-left`" event is sent when the user has either left a group, or has bee


#### group-member-updated
A "`group-member-updated`" event is sent when something regarding the user's group membership changes. Note that the `member` object is **not** a full GroupMember object, even though it has similarities. It's missing `user`, `createdAt`, `bannedAt`, and `managerNotes`. It also has the extra `lastPostReadAt` field.
A "`group-member-updated`" event is sent when something regarding the user's group membership changes. Note that the optional values in the `member` are as if "fetching a specific user", per the schema description.

```json
{
"type": "group-member-updated",
"content": {
"member": {
"id": ":groupMemberId", // gmem_00000000-0000-0000-000000000000
"groupId": ":groupId",
"userId": ":userId",
"isRepresenting": <boolean>,
"roleIds": [
":groupRoleId" // grol_00000000-0000-0000-000000000000
],
"joinedAt": ":dateTimeString", // yyyy-mm-ddThh:mm:ss.sssZ
"membershipStatus": ":groupMembershipEnum", // One of: "member", ???
"visibility": ":groupVisibilityEnum", // One of: "visible", ???
"isSubscribedToAnnouncements": <boolean>,
"lastPostReadAt": ":dateTimeString" // NOTE: WILL BE NULL if the user hasn't read any group posts
// <GroupLimitedMember Object>, See return data of Groups API:
// https://vrchatapi.github.io/docs/api/#get-/groups/-groupId-/members/-userId-
}
}
}
Expand Down
62 changes: 54 additions & 8 deletions layouts/shortcodes/instance_generator.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
<option value="friends">Friends</option>
<option value="invite+">Invite+</option>
<option value="invite">Invite</option>
<option value="grouppublic">Group Public</option>
<option value="group+">Group+</option>
<option value="group">Group</option>
</select>
</div>
</div>
Expand All @@ -66,7 +69,7 @@
</div>
<div class="col mt-0 mt-lg-3 mb-3 mb-lg-0">
<span class="form-text">
Must be a valid User ID.
Must be a valid User ID or Group ID.
</span>
</div>
</div>
Expand Down Expand Up @@ -143,6 +146,7 @@
nonceElement.value = uuidv4();
}

let ownerIdMatchesGroupID = (ownerId.match(/^(grp_[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12})$/) || [])[1] == undefined;
switch (instanceType) {
case "public":
ownerIdElement.disabled = true;
Expand All @@ -154,6 +158,20 @@
case "invite":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
if (!ownerIdMatchesGroupID) {
output.innerHTML = "<span class='text-red'>Invalid User ID.</span>";
return;
}
break;
case "grouppublic":
case "group+":
case "group":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
if (ownerIdMatchesGroupID) {
output.innerHTML = "<span class='text-red'>Invalid Group ID.</span>";
return;
}
break;
}

Expand All @@ -163,7 +181,8 @@
}

let res_type = "";
let res_hidden = "";
let res_owner = "";
let res_gaccess = "";
let res_nonce = "";
let res_canRequestInvite = false;

Expand All @@ -177,38 +196,65 @@
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "hidden";
res_hidden = ownerId;
res_owner = ownerId;
res_nonce = nonce;
break;
case "friends":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "friends";
res_hidden = ownerId;
res_owner = ownerId;
res_nonce = nonce;
break;
case "invite+":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "private";
res_canRequestInvite = true;
res_hidden = ownerId;
res_owner = ownerId;
res_nonce = nonce;
break;
case "invite":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "private";
res_hidden = ownerId;
res_owner = ownerId;
res_nonce = nonce;
break;
case "grouppublic":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "group";
res_owner = ownerId;
res_gaccess = "public";
res_nonce = nonce;
break;
case "group+":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "group";
res_owner = ownerId;
res_gaccess = "plus";
res_nonce = nonce;
break;
case "group":
ownerIdElement.disabled = false;
nonceElement.disabled = true;
res_type = "group";
res_owner = ownerId;
res_gaccess = "members";
res_nonce = nonce;
break;
}

let result = "";
result += "worldId=<span class='text-danger'>" + worldId + "</span>";
result += "&instanceId=<span class='text-orange'>" + instanceId + "</span>";
if (res_hidden != "") {
result += "<span class='text-green'>~" + res_type + "(<span class='text-blue'>" + res_hidden + "</span>)</span>";
if (res_owner != "") {
result += "<span class='text-green'>~" + res_type + "(<span class='text-blue'>" + res_owner + "</span>)</span>";
}
if (res_gaccess != "") {
result += "<span class='text-green'>~groupAccessType(<span class='text-blue'>" + res_gaccess + "</span>)</span>";
}
if (res_canRequestInvite) {
result += "<span class='text-green'>~canRequestInvite</span>";
Expand Down

0 comments on commit 65790f9

Please sign in to comment.