diff --git a/README.md b/README.md
index 617e98f..9aac987 100644
--- a/README.md
+++ b/README.md
@@ -9,4 +9,17 @@ Internal copy of our public docs.
1. `cd path/to/docs`
1. `poetry install --no-root`
1. `poetry shell`
-1. `mkdocs serve`
\ No newline at end of file
+1. `mkdocs serve`
+
+## Contributing
+- master is our production branch, means anything in master goes into the production site
+- develop is our main development branch, merge your changes to here
+
+For any changes, make a feature branch.
+This means a branch named like `feature/add-cvravatar-feature-docs` with a reaonable short name of the changes you are doing there.
+When you are done with your changes, merge them into develop.
+
+### Releases
+Making a release should be done by either a Development Head or DevOps Engineer.
+
+For deploying to production merge develop into master, and grab the latest build artifact from teamcity after it has been built.
diff --git a/_variables/cck.json b/_variables/cck.json
index ff0b0cb..f0d7bf1 100644
--- a/_variables/cck.json
+++ b/_variables/cck.json
@@ -1,7 +1,7 @@
{
"cck": {
- "version": "v3.9 RELEASE",
- "downloadUrl": "https://files.abidata.io/static_web/ChilloutVR%20CCK%20v3.9%20RELEASE.unitypackage"
+ "version": "v3.10 RELEASE",
+ "downloadUrl": "https://files.abidata.io/static_web/ChilloutVR%20CCK%20v3.10%20RELEASE.unitypackage"
},
"unity": {
"install": {
diff --git a/docs/cck/lua/api/avatar-api.md b/docs/cck/lua/api/avatar-api.md
index 6917ee8..8ffdf86 100644
--- a/docs/cck/lua/api/avatar-api.md
+++ b/docs/cck/lua/api/avatar-api.md
@@ -4,9 +4,10 @@ Accessible via the `AvatarAPI` [Global](globals.md). This API provides access to
## Static Functions
-| Name | Description |
-|--------------------------------------------------------|-----------------------------------------------------|
-| `LocalAvatar : Avatar` (Returns [Avatar](#avatar)) | Access the Local Player's Avatar instance reference |
+| Name | Description |
+|----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
+| `LocalAvatar : Avatar` (Returns [Avatar](#avatar)) | Access the Local Player's Avatar instance reference |
+| `CurrentAvatar : Avatar` (Returns [Avatar](#avatar)) | Access the Script's Avatar instance reference (the avatar the script is running on). *This is only available on avatar scripts* |
## Avatar
@@ -47,4 +48,24 @@ The `Avatar` instances can be accessed via:
| `GetParameterAsBool(string parameterName) : bool` | Retrieves a boolean parameter from the animator. Returns nil if the parameter does not exist. |
| `GetParameterAsInt(string parameterName) : int` | Retrieves an integer parameter from the animator. Returns nil if the parameter does not exist. |
| `GetParameterAsFloat(string parameterName) : float` | Retrieves a float parameter from the animator. Returns nil if the parameter does not exist. |
-| `SetParameter(string parameterName, bool/float/int parameterValue) : void` | Sets an animator parameter to a set value. Internally will cast to the type actually used by the Animator. |
\ No newline at end of file
+| `SetParameter(string parameterName, bool/float/int parameterValue) : void` | Sets an animator parameter to a set value. Internally will cast to the type actually used by the Animator. |
+
+### Avatar Picture
+
+Requesting the picture is a bit more complicated as it needs to be acquired in the first place. So it's not a function
+that will give the results right away. Instead, it uses a callback lua function, which is basically a normal lua
+function that gets called whenever the request is finished.
+
+For a complete example, check: [Player Profile and Avatar Picture Example](../examples/player-profile-picture.md)
+
+#### Methods
+
+| Name | Description |
+|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
+| `RequestImage(callback OnAvatarImage, bool castToTexture) : void` - `#arg1` lua function for the [callback](#callbacks) - `#arg2` *[Optional]* Whether to cast the Texture2D to Texture or not. | Sends a request to fetch the Player Avatar's picture as a Texture2D or as a Texture. |
+
+#### Callbacks
+
+| Name | Description |
+|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------|
+| `OnAvatarImage(Texture2D/Texture texture, string avatarID) : void` - `#arg1` The Texture/Texture2D reference for the avatar's image - `#arg2` *[Optional]* The Avatar's ID the image belongs to | Gets called when `RequestImage` finished and is sending the results |
diff --git a/docs/cck/lua/api/lua-behaviour.md b/docs/cck/lua/api/lua-behaviour.md
index 283e19c..98830bf 100644
--- a/docs/cck/lua/api/lua-behaviour.md
+++ b/docs/cck/lua/api/lua-behaviour.md
@@ -7,7 +7,7 @@ This entity inherits from MonoBehaviour, as such inherits some of its members.
### Properties
| Name | Description |
-| ---------------------------- | -------------------------------------------------- |
+|------------------------------|----------------------------------------------------|
| `Hash` : string | SHA512 hash of script text as Base64 string |
| `TypeLabel` : string | Returns the script type label |
| `ScriptName` : string | Name of the script asset |
@@ -15,13 +15,13 @@ This entity inherits from MonoBehaviour, as such inherits some of its members.
### Methods
-| Method | Description |
-| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
-| `Crash(string)` : void | Crashes the script preventing stopping it's execution (the behaviour still exists) |
-| `Destroy(string)` : void | Destroys the script, while actually getting rid of the behavior |
-| `CallReceiverFunction(string name, anything[] args) : void` | Call a function on the LuaBehaviour with the name `RECEIVER_` with the given list table as an argument. |
-| `GetGlobalBoolean(string name) : boolean\|nil` | Get the given global boolean variable, or nil if it doesn't exist. |
-| `GetGlobalNumber(string name) : number\|nil` | Get the given global number variable, or nil if it doesn't exist. |
-| `GetGlobalString(string name) : string\|nil` | Get the given global string variable, or nil if it doesn't exist. |
-| `GetGlobalTable(string name) : Table\|nil` | Get the given global table variable, or nil if it doesn't exist. |
-| `GetGlobals() : Table` | Get a table of all the globals in the script. |
+| Method | Description |
+|---------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `Crash(string)` : void | Crashes the script preventing stopping it's execution (the behaviour still exists) |
+| `Destroy(string)` : void | Destroys the script, while actually getting rid of the behavior |
+| `CallGlobalFunction(string name, arg1, arg2, ...) : value\|nil` | Call a global function on the LuaBehaviour with the name provided. You can send as many arguments as you want (or even none). This can used to call global functions on other scripts Note: If you don't want other scripts from calling your script's functions, make them Local |
+| `GetGlobalBoolean(string name) : boolean\|nil` | Get the given global boolean variable, or nil if it doesn't exist. |
+| `GetGlobalNumber(string name) : number\|nil` | Get the given global number variable, or nil if it doesn't exist. |
+| `GetGlobalString(string name) : string\|nil` | Get the given global string variable, or nil if it doesn't exist. |
+| `GetGlobalTable(string name) : Table\|nil` | Get the given global table variable, or nil if it doesn't exist. |
+| `GetGlobals() : Table` | Get a table of all the globals in the script. |
diff --git a/docs/cck/lua/api/player-api.md b/docs/cck/lua/api/player-api.md
index 14343f2..06b996a 100644
--- a/docs/cck/lua/api/player-api.md
+++ b/docs/cck/lua/api/player-api.md
@@ -117,16 +117,41 @@ The viseme index values are mapped as follows:
| `GetGravity() : Vector3` | Current gravity vector affecting the player. |
| `GetGravityDirection() : Vector3` | Direction of the gravity affecting the player. |
+### Profile Picture
+
+Requesting the picture is a bit more complicated as it needs to be acquired in the first place. So it's not a function
+that will give the results right away. Instead, it uses a callback lua function, which is basically a normal lua
+function that gets called whenever the request is finished.
+
+For a complete example, check: [Player Profile and Avatar Picture Example](../examples/player-profile-picture.md)
+
+#### Methods
+
+| Name | Description |
+|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------|
+| `RequestProfileImage(callback OnProfileImage, bool castToTexture) : void` - `#arg1` lua function for the [callback](#callbacks) - `#arg2` *[Optional]* Whether to cast the Texture2D to Texture or not. | Sends a request to fetch the Player's profile picture as a Texture2D or as a Texture. |
+
+#### Callbacks
+
+| Name | Description |
+|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|
+| `OnProfileImage(Texture2D/Texture texture, string userID) : void` - `#arg1` The Texture/Texture2D reference for the player image - `#arg2` *[Optional]* The Player's UserID the image belongs to | Gets called when `RequestProfileImage` finished and is sending the results |
+
## Remote Player
Functions and properties specific to remote players.
### Properties
-| Name | Description |
-|-------------------------------|---------------------------------------------------------|
-| `NameplatePosition : Vector3` | Position of the remote player's nameplate in the world. |
-| `IsNameplateActive : bool` | Indicates whether the nameplate is active or not. |
+| Name | Description |
+|------------------------------------|---------------------------------------------------------|
+| `IsNameplateActive : bool` | Indicates whether the nameplate is active or not. |
+
+### Methods
+
+| Name | Description |
+|------------------------------------|-----------------------------------------------------------------|
+| `GetNameplatePosition() : Vector3` | Get the Position of the remote player's nameplate in the world. |
## Local Player
diff --git a/docs/cck/lua/changelog/r176ex4-r176ex5.md b/docs/cck/lua/changelog/r176ex4-r176ex5.md
index 7d0bdbb..2ba5546 100644
--- a/docs/cck/lua/changelog/r176ex4-r176ex5.md
+++ b/docs/cck/lua/changelog/r176ex4-r176ex5.md
@@ -22,3 +22,8 @@
### [PlayerAPI](../api/player-api.md)
- Added `IsUsingVR` to [Local Player Properties](../api/player-api.md#properties_2)
+- Added `RequestProfileImage` to [Player Profile Picture](../api/player-api.md#profile-picture)
+
+### [AvatarAPI](../api/avatar-api.md)
+- Added `CurrentAvatar` to [Avatar API Static Functions](../api/avatar-api.md#static-functions)
+- Added `RequestImage` to [Avatar Picture](../api/avatar-api.md#avatar-picture)
diff --git a/docs/cck/lua/examples/.pages b/docs/cck/lua/examples/.pages
index a4561fd..3109493 100644
--- a/docs/cck/lua/examples/.pages
+++ b/docs/cck/lua/examples/.pages
@@ -3,6 +3,7 @@ nav:
- index.md
- funny-cube.md
- instances-disable-go-in-home.md
+ - player-profile-picture.md
- player-thumbs-up-launch.md
- player-teleport-away-from-water.md
- viewpoint-raycast.md
\ No newline at end of file
diff --git a/docs/cck/lua/examples/images/player-profile-cck.png b/docs/cck/lua/examples/images/player-profile-cck.png
new file mode 100644
index 0000000..4d9a289
Binary files /dev/null and b/docs/cck/lua/examples/images/player-profile-cck.png differ
diff --git a/docs/cck/lua/examples/index.md b/docs/cck/lua/examples/index.md
index a480efa..07041a2 100644
--- a/docs/cck/lua/examples/index.md
+++ b/docs/cck/lua/examples/index.md
@@ -7,3 +7,4 @@ Here are some example scripts that can be used as an example to learn about Lua.
* [Teleport from Water](player-teleport-away-from-water.md) - Teleport when fully immersed in water.
* [Thumbs Up Player Launcher](player-thumbs-up-launch.md) - Launch upward when doing 2x thumbs up gesture.
* [Viewpoint Raycast](viewpoint-raycast.md) - Perform a raycast from the player's viewpoint.
+* [Player Profile / Avatar Picture](player-profile-picture.md) - Get Player Profile and Avatar pictures.
diff --git a/docs/cck/lua/examples/player-profile-picture.md b/docs/cck/lua/examples/player-profile-picture.md
new file mode 100644
index 0000000..efbe8b3
--- /dev/null
+++ b/docs/cck/lua/examples/player-profile-picture.md
@@ -0,0 +1,72 @@
+# Player Profile Picture
+
+This is an example how we can request and use the player's profile and avatar's picture.
+
+All you need to do, is create 2 planes. One for the player's picture and the other for the player avatar's picture, and
+add their MeshRenderers as bound object.
+
+Note: You need to add the components directly, if you add the gameObjects you need to call the GetComponent on the
+gameObject to get the mesh renderer reference. Notice on the image, it shows the icon of a MeshRenderer component and
+not the gameObject.
+
+![player-profile-cck.png](images/player-profile-cck.png)
+
+```lua
+UnityEngine = require "UnityEngine"
+
+function Start()
+
+ -- Get the references to the mesh rendereres
+ local playerMeshRenderer = BoundObjects.playerMeshRenderer
+ local avatarMeshRenderer = BoundObjects.avatarMeshRenderer
+
+ -- We're going to use the local player
+ local player = PlayerAPI.LocalPlayer
+
+ -- Request the profile picture image for the player
+ print("Requesting the player's profile image for player " .. player.UserID)
+ player.RequestProfileImage(function(texture)
+ -- Call the GetProfileImage while wrapping the function in a local create function
+ -- so we can send some additional context (the player's reference, and the mesh renderer)
+ OnPlayerProfileImage(texture, player, playerMeshRenderer)
+ end, true)
+
+ -- If the player has the avatar loaded, request the current avatar image for the player
+ if player.Avatar.IsLoaded then
+ print("Requesting the avatar's profile image for avatar " .. player.Avatar.AvatarID)
+ -- Call the GetProfileImage while wrapping the function in a local create function
+ -- so we can send some additional context (the player's avatar reference, and the mesh renderer)
+ player.Avatar.RequestImage(function(texture)
+ OnAvatarImage(texture, player.Avatar, avatarMeshRenderer)
+ end, true)
+ end
+end
+
+function OnPlayerProfileImage(texture, player, playerMeshRenderer)
+ print("Received the Player Profile Image for user " .. player.UserID .. "! " .. tostring(texture))
+ if texture == nil then
+ print("Unfortunately it was nil :(")
+ return
+ end
+ -- Get the current material on the meshrenderer and set the texture
+ -- The material SetTexture requires a Texture instance, and not Texture2D
+ -- which is why we called GetProfileImage with the second arg true, so the
+ -- texture is returned as a Texture instead of Texture2D
+ local materialInstance = playerMeshRenderer.material
+ materialInstance.SetTexture("_MainTex", texture)
+end
+
+function OnAvatarImage(texture, avatar, avatarMeshRenderer)
+ print("Received the Avatar Profile Image for avatar " .. avatar.AvatarID .. "! " .. tostring(texture))
+ if texture == nil then
+ print("Unfortunately it was nil :(")
+ return
+ end
+ -- Get the current material on the meshrenderer and set the texture
+ -- The material SetTexture requires a Texture instance, and not Texture2D
+ -- which is why we called GetProfileImage with the second arg true, so the
+ -- texture is returned as a Texture instead of Texture2D
+ local materialInstance = avatarMeshRenderer.material
+ materialInstance.SetTexture("_MainTex", texture)
+end
+```
diff --git a/docs/cck/lua/recipes/.pages b/docs/cck/lua/recipes/.pages
index 84917a1..1e9ab14 100644
--- a/docs/cck/lua/recipes/.pages
+++ b/docs/cck/lua/recipes/.pages
@@ -2,4 +2,5 @@ title: Recipes
nav:
- index.md
- getting-users.md
- - listen-game-events.md
\ No newline at end of file
+ - listen-game-events.md
+ - getting-components.md
\ No newline at end of file
diff --git a/docs/cck/lua/recipes/getting-components.md b/docs/cck/lua/recipes/getting-components.md
new file mode 100644
index 0000000..88fac2f
--- /dev/null
+++ b/docs/cck/lua/recipes/getting-components.md
@@ -0,0 +1,77 @@
+# Getting Components
+
+This script demonstrates how to use various methods to access components.
+
+It showcases the different approaches for retrieving components attached to a GameObject or its children/parents.
+
+Some methods have an optional parameter to dictate whether to include disabled Components or not. If not provided, it
+will **ignore disabled** Components by default. The components are:
+
+- GetComponentInChildren
+- GetComponentInParent
+- GetComponentsInChildren
+- GetComponentsInParent
+
+**Note:** These methods can be expensive performance wise, use with caution.
+
+```lua
+UnityEngine = require "UnityEngine"
+
+function Start()
+
+ -- Define the source as the current GameObject
+ -- You can also use 'transform' as the source since both GameObjects and Components share the same methods
+ local source = gameObject;
+ -- local source = transform;
+
+ -- Example 1: GetComponent
+ -- Attempts to retrieve the Transform component attached to the current GameObject
+ local transformComponent = source.GetComponent("UnityEngine.Transform")
+ print("component.GetComponent(\"UnityEngine.Transform\"): ", transformComponent, ", IsNull: ", transformComponent == nil)
+
+ -- Example 2: GetComponentInChildren
+ -- Attempts to retrieve the Transform component from the current GameObject or any of its children
+ transformComponent = source.GetComponentInChildren("UnityEngine.Transform")
+ print("component.GetComponentInChildren(\"UnityEngine.Transform\"): ", transformComponent, ", IsNull: ", transformComponent == nil)
+
+ -- Example 3: GetComponentInChildren (include inactive children)
+ -- Attempts to retrieve the Transform component from the current GameObject or any of its children, including inactive ones
+ transformComponent = source.GetComponentInChildren("UnityEngine.Transform", true)
+ print("component.GetComponentInChildren(\"UnityEngine.Transform\", true): ", transformComponent, ", IsNull: ", transformComponent == nil)
+
+ -- Example 4: GetComponentInParent
+ -- Attempts to retrieve the Transform component from the current GameObject or any of its parents
+ transformComponent = source.GetComponentInParent("UnityEngine.Transform")
+ print("component.GetComponentInParent(\"UnityEngine.Transform\"): ", transformComponent, ", IsNull: ", transformComponent == nil)
+
+ -- Example 5: GetComponents
+ -- Retrieves all Transform components attached to the current GameObject
+ local transformComponents = source.GetComponents("UnityEngine.Transform")
+ print("source.GetComponents(\"UnityEngine.Transform\"): ", transformComponents, ", IsNull: ", transformComponents == nil, ", Count: ", #transformComponents)
+ for index, idxTransform in ipairs(transformComponents) do
+ print(string.format(" - Entry %d: Transform: %s, IsNull: %s", index, tostring(idxTransform), tostring(idxTransform == nil)))
+ end
+
+ -- Example 6: GetComponentsInChildren
+ -- Retrieves all Transform components from the current GameObject and its children
+ transformComponents = source.GetComponentsInChildren("UnityEngine.Transform")
+ print("source.GetComponentsInChildren(\"UnityEngine.Transform\"): ", transformComponents, ", IsNull: ", transformComponents == nil, ", Count: ", #transformComponents)
+ for index, idxTransform in ipairs(transformComponents) do
+ print(string.format(" - Entry %d: Transform: %s, IsNull: %s", index, tostring(idxTransform), tostring(idxTransform == nil)))
+ end
+
+ -- Example 7: GetComponentsInParent
+ -- Retrieves all Transform components from the current GameObject and its parents
+ transformComponents = source.GetComponentsInParent("UnityEngine.Transform")
+ print("source.GetComponentsInParent(\"UnityEngine.Transform\"): ", transformComponents, ", IsNull: ", transformComponents == nil, ", Count: ", #transformComponents)
+ for index, idxTransform in ipairs(transformComponents) do
+ print(string.format(" - Entry %d: Transform: %s, IsNull: %s", index, tostring(idxTransform), tostring(idxTransform == nil)))
+ end
+
+ -- Example 8: TryGetComponent
+ -- Safely attempts to retrieve the Transform component and checks if it was successful
+ local hasTransform
+ hasTransform, transformComponent = source.TryGetComponent("UnityEngine.Transform")
+ print("source.TryGetComponent(\"UnityEngine.Transform\"): ", transformComponent, ", IsNull: ", transformComponent == nil, ", hasComponent: ", hasTransform)
+end
+```
\ No newline at end of file
diff --git a/docs/cck/lua/recipes/getting-users.md b/docs/cck/lua/recipes/getting-users.md
index 42dc012..86099c5 100644
--- a/docs/cck/lua/recipes/getting-users.md
+++ b/docs/cck/lua/recipes/getting-users.md
@@ -3,29 +3,25 @@
## Getting Player Count
```lua
-- Pull get the number of users in an instance
-CVR = require "CVR"
-... = CVR.PlayersAPI.PlayerCount
+... = PlayerAPI.PlayerCount
-- You can also use:
-... = #CVR.PlayersAPI.AllPlayers
+... = #PlayerAPI.AllPlayers
```
## Getting All Players
```lua
-- Pull in all the users in an instance, including you.
-CVR = require "CVR"
-... = CVR.PlayersAPI.AllPlayers
+... = PlayerAPI.AllPlayers
```
## Getting All Remote Players
```lua
-- Pull in all the users in an instance, excluding you.
-CVR = require "CVR"
-... = CVR.PlayersAPI.RemotePlayers
+... = PlayerAPI.RemotePlayers
```
## Local Player
```lua
-- Get just you.
-CVR = require "CVR"
-... = CVR.PlayersAPI.LocalPlayer
+... = PlayerAPI.LocalPlayer
```
\ No newline at end of file
diff --git a/docs/cck/lua/recipes/index.md b/docs/cck/lua/recipes/index.md
index b253bda..2d2d032 100644
--- a/docs/cck/lua/recipes/index.md
+++ b/docs/cck/lua/recipes/index.md
@@ -2,6 +2,7 @@
* [Getting Users in an Instance](./getting-users.md)
* [Listening to Game Events](./listen-game-events.md)
+* [Getting Components](./getting-components.md)
\ No newline at end of file
diff --git a/docs/cck/lua/security.md b/docs/cck/lua/security.md
index 28b6c22..cb33fdb 100644
--- a/docs/cck/lua/security.md
+++ b/docs/cck/lua/security.md
@@ -87,6 +87,30 @@ if blake2b.hash({string.byte(boundObject["Text"].text,1,-1)}, 64) == KEYCODE_BLA
end
```
+## Rule 1. Scope
+
+Other scripts can call/access your script's global functions/variables. If you have some code that you want to keep to
+your own script, you should use the `local` keyword. For example:
+
+```lua
+-- This function can be run by external scripts, which can cause a player to cheat and give himself money
+-- if they are able to get a reference to your script
+function IncrementMoneys(amount)
+ print("Incrementing money to this player!")
+ ...
+end
+```
+
+```lua
+-- This function can NOT be run by external scripts, because external scripts can only run Global functions.
+local function SaferIncrementMoneys(amount)
+ print("Incrementing money to this player (a bit more safely)!")
+ ...
+end
+```
+
+So the rule of the thumb is give your code the least scope possible they need to work.
+
## More to come
Other rules of thumb coming soon!
\ No newline at end of file
diff --git a/docs/cck/setup.md b/docs/cck/setup.md
index f545a8f..a431779 100644
--- a/docs/cck/setup.md
+++ b/docs/cck/setup.md
@@ -41,4 +41,4 @@ a ticket for publishing. We will get back to you shortly.
**Any questions left?**
See our [FAQ](../faq/), check out our [Discord](https://discord.gg/abi), take a look at our
-[Forums](https://forums.abinteractive.net/) or mention us on Twitter [@AlphaBlendNET](https://twitter.com/AlphaBlendNET).
+[Feedback Platform](https://feedback.abinteractive.net/) or mention us on Twitter [@AlphaBlendNET](https://twitter.com/AlphaBlendNET).
diff --git a/docs/chilloutvr/quick-start.md b/docs/chilloutvr/quick-start.md
index 1c4fb1a..7388f12 100644
--- a/docs/chilloutvr/quick-start.md
+++ b/docs/chilloutvr/quick-start.md
@@ -1,7 +1,7 @@
# Quick Start
It is nice to see you here! We appreciate your efforts of looking into our games and services. ChilloutVR is a user-content-driven multi-universe sandbox that can be played in VR and Desktop.
-For any questions, see our [FAQ](../faq/), check out our [Discord](https://discord.gg/abi), take a look at our [Forums](https://forums.abinteractive.net/) or mention us on Twitter [@AlphaBlendNET](https://twitter.com/AlphaBlendNET).
+For any questions, see our [FAQ](../faq/), check out our [Discord](https://discord.gg/abi), take a look at our [Feedback Platform](https://feedback.abinteractive.net/) or mention us on Twitter [@AlphaBlendNET](https://twitter.com/AlphaBlendNET).
## Download via Steam
ChilloutVR is free to play on steam.
diff --git a/overrides/home.html b/overrides/home.html
index b50d001..5aec678 100644
--- a/overrides/home.html
+++ b/overrides/home.html
@@ -241,13 +241,13 @@
The community hub is our key account management platform equipped with all major features for content management, friends and content browsing, groups and events management and more.