Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[No Code] Adding Detailed Documentation for the CUI system #52

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Rust Community Repository
> This Repository is part of the game Rust. It has no relation to the Programming Language.

Client Code for the `CommunityEntity` Class to fulfill Server-side Modder Requests.
Holds the Custom User Interface System (CUI System), which lets developers create interactive UI through a simple JSON Schema.

## Table of Contents
> Click one of the Topics or dive directly into the Component Documentation
- [The Basics](/docs/Basics.md)
- [Components](/docs/components/README.md)
- [RectTransform](/docs/components/RectTransform.md)
- [RawImage](/docs/components/UnityEngine.UI.RawImage.md)
- [Image](/docs/components/UnityEngine.UI.Image.md)
- [Text](/docs/components/UnityEngine.UI.Text.md)
- [Outline](/docs/components/UnityEngine.UI.Outline.md)
- [Button](/docs/components/UnityEngine.UI.Button.md)
- [InputField](/docs/components/UnityEngine.UI.InputField.md)
- [NeedsCursor & NeedsKeyboard](/docs/components/NeedsX.md)
- [Countdown](/docs/components/Countdown.md)
- [Tips, Bugs & Edge cases](/docs/Bugs-Tips.md)
- [Credits & Acknowledgements](#Credits)

## Credits
External Contributors & People who improved the CUI System
- [@bawNg](https://github.com/bawNg) - PRs [#1](https://github.com/Facepunch/Rust.Community/pull/1), [#2](https://github.com/Facepunch/Rust.Community/pull/2), [#5](https://github.com/Facepunch/Rust.Community/pull/5)
- [@balu92](https://github.com/balu92) - PRs [#7](https://github.com/Facepunch/Rust.Community/pull/7), [#9](https://github.com/Facepunch/Rust.Community/pull/9)
- [@Jake-Rich](https://github.com/Jake-Rich) - PRs [#16](https://github.com/Facepunch/Rust.Community/pull/16), [#30](https://github.com/Facepunch/Rust.Community/pull/39)
- [@Mughisi](https://github.com/Mughisi) - PRs [#19](https://github.com/Facepunch/Rust.Community/pull/19), [#22](https://github.com/Facepunch/Rust.Community/pull/22)
- [@shooter46](https://github.com/shooter46) - PR [#28](https://github.com/Facepunch/Rust.Community/pull/28)
- [@Alitop](https://github.com/Alitop) - PR [#32](https://github.com/Facepunch/Rust.Community/pull/32)
- [@TactiTac0z](https://github.com/TactiTac0z) - PR [#40](https://github.com/Facepunch/Rust.Community/pull/40)
- [@Kulltero](https://github.com/Kulltero) - PR [#43](https://github.com/Facepunch/Rust.Community/pull/43)
> And of course, Facepunch, who has put a lot of effort into giving Developers the CUI System & the ability to improve it.

---
### Disclaimer
The README & Documentation is Community maintained. It aims to give Developers a starting Point and educate them on effectively using CUIs for their Projects.
76 changes: 76 additions & 0 deletions docs/Basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# The Basics of CUI
**[Back to the Start](/README.md)** | **[Next Topic](/docs/components/README.md) >**

There are a few basic Concepts that are needed to make your own CUI, below you will learn about what Panels are & how to create and destroy UI Elements

## The Schema

the JSON Schema to send UI to the Player consists of a List of Elements, where each Element creates a new Panel on the Client. Elements have One or more Components that control the Look & Functionality.

```json
[{
"name": "AddUI CreatedPanel",
"parent": "Overlay",
"components": [...],
"fadeOut": 0.0,
"destroyUi": ""
}, ...]
```
> The values in these JSON examples represent the default values that are assigned if no property is specified.
> … represent One or more collapsed Objects

| Key | Type | Notes |
| :-- | :------- | :------------------- |
| `name` | string | The identifier of your panel, needed when destroying UI or adding panels inside this one |
| `parent` | string | Tells the client which Panel or Layer to Parent to. **[Needs to be a valid Panel or Layer name](/docs/Bugs-Tips.md#addui-unknown-parent-for-name--parent)** |
| `components` |List of Components | One or more Components, without these there’s no point in sending a panel |
| `fadeOut` | float | Makes the Panel fade out instead of disappearing immediately. _Currently doesn’t fade out any child panels._ |
| `destroyUi` | string | Destroys the Panel specified in the string before creating your Panel. Useful **[preventing flickering](/docs/Bugs-Tips.md#flickering-when-destroying--re-sending-ui-on-the-same-frame)** when updating UI. |


### About Layers
layers are used when creating your top most Panel. They differ from Panels because they are static GameObjects that cannot be destroyed via a DestroyUI call. Depending on the Layer you parent to, your UI will appear above or below Rust's own UI elements.

#### Available Layer values
- `Overall` the top most layer in front of all of Rust's UI
- `Overlay`
- `Hud.Menu` the layer where rust positions menus like your inventory
- `Hud` the layer where Rust stores most HUD elements like your status bar
- `Under` the lowermost layer, your UI will appear behind all of Rust's UI


### About Naming

It’s recommended to always name your Panels _something_, this is because the CUI System doesn’t support multiple Panels with the same name and may cause **[Ghost panels](/docs/Bugs-Tips.md#orphaned-ui-panels-ui-that-cant-be-destroyed-or-ghost-panels)** which can't be destroyed.

It’s also recommended to prefix the Name of your Panel with something unique to your Mod, which ensures there are no accidental name Conflicts with other Mods


## Sending & destroying UI

There are two RPC Calls you can use to send & destroy UI respectively

Adding UI:
```c#
BasePlayer player = targetPlayer;
string json = "..."; // your UI in JSON form
var community = CommunityEntity.ServerInstance;
SendInfo sendInfo = new SendInfo(player.net.connection);
community.ClientRPCEx<string>(sendInfo, null, "AddUI", json);
```

Destroying UI:
```c#
BasePlayer player = targetPlayer;
string panel = "AddUi CreatedPanel"; // the name of the Panel you wish to destroy
var community = CommunityEntity.ServerInstance;
SendInfo sendInfo = new SendInfo(player.net.connection);
community.ClientRPCEx<string>(sendInfo, null, "DestroyUI", panel);
```
When destroying a Panel, all child panels will also get destroyed.
> Your Modding Framework may have helper Methods to simplify these steps.

----
The next Topic explains Components in detail

**[Back to the Start](/README.md)** | **[Next Topic](/docs/components/README.md) >**
133 changes: 133 additions & 0 deletions docs/Bugs-Tips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Bugs & Tips

**< [Previous Topic](/docs/components/README.md)** | **[Back to the Start](/README.md)**

When working with the CUI System, you will often encounter weird Bugs & Situations. This document lists some ways to prevent them & shows you additional tricks to enhance your UIs.

## Table of Contents
- [Common Error Messages](#common-error-messages)
- [Bugs](#bugs)
- [Tricks](#tricks)


# Common Error Messages
> these errors will appear in your client console when testing the UI, make sure to test for these before releasing your mod

### AddUI: Unknown Parent for *name*: *parent*
this happens when the parent you supplied in your panel Payload doesn't exist. Double-check for spelling mistakes, and formatting issues & ensure your parent appears in your JSON list before the Panel you get this error on.



---

### Error downloading image: *URL* ( *error* )
the Client couldn't download your Image, double-check your URL & look at the error part within the brackets for what could cause it.



---

### A GameObject can only contain one 'Graphic' component.

This error indicates that you're trying to add multiple Unity Components that derive from `UnityEngine.UI.Graphic`. The **[Components](/docs/components/README.md)** topic has a list of allowed Components and lists the categories they are in. any Component of the **Visual** Category is a Component that derives from or adds a `UnityEngine.UI.Graphic` to the Panel. To get around this Limitation, you can put other Visual Components on a child panel instead.

# Bugs


### Orphaned UI Panels, UI that Can't be Destroyed, or Ghost Panels.

**Symptom:** you have 1 or more panels that are stuck on your Screen and can't be removed by Calling **DestroyUI** with their Name.

**Cause:** you have 2 or more panels that shared the same name & were active at the same time. If these are parented directly to a Layer and one is destroyed, the other Panel Can't be destroyed anymore. The only way to remove the UI Panel from your Screen is by reconnecting. Double-check your UI and ensure any Panel directly parented to a Layer has a unique Name. Also, ensure that you don't accidentally send the same UI twice.



---


### Flickering when destroying & re-sending UI on the same frame.

**Symptom:** when updating Part of your UI. the Player gets a noticeable Delay between the old UI being destroyed & the new UI being created.

**Cause:** the presumed cause of this issue is the Server Delaying your AddUI Packet to the next Network Cycle. This happens very unpredictably, but is more likely with larger UI Updates. The solution is to use the `destroyUi` field on your panel Payload, it works the same way a DestroyUI call works, but is combined with your panel Payload to prevent network scheduling from creating the flickering issue.



---

### Very Inconsistent Alpha handling for images

**Symptom:** when using images with somewhat transparent pixels, the images get rendered more Opaque than they are, resulting in heavy artifacts.
**Linked Issue:** **[#42 - Rust has an Opacity Issue](https://github.com/Facepunch/Rust.Community/issues/42)**

**Cause:** no known Cause or Workaround found. Vote on the Linked issue if you encounter this bug or have more info as to why this might happen.



---

### Panels with a blur Material & Transparency cause underlying Panels to be invisible.
**Symptom:** when using a blurry Material on a Color with Transparency, any underlying Image Components with blur get cut out.
**Visual Example:**
![image](https://user-images.githubusercontent.com/33698270/215882128-d1f0798c-d7ed-4986-9675-4fba48632ad7.png)
> an image of the following UI setup
> parent: black with 98% alpha
>
> square 1: child of Parent, gray with 20% alpha
>
> square 2: child of Parent, gray with 100% alpha
>
> square 3: child of Parent, gray with 20% alpha and a text element behind it.


**Cause:** no exact Cause is known, but it seems to be related to the blurry Materials themselves. This bug only occurs when all underlying Images are using a blurry material with transparency. If at least 1 element is opaque, the bug does not occur. This can be a text or image element.



# Tricks

### Use Outlines like an advanced User
Outlines can go way beyond the basic use case of putting them on your square Panels. Applying Outlines to Text can be a great way to make them stand out, for example when you can't control the background behind it.
![image](https://user-images.githubusercontent.com/33698270/215885917-4916ee09-a891-4609-82a4-51bb07881bde.png)

> Can you read this?

![image](https://user-images.githubusercontent.com/33698270/215886796-346be279-2d8e-43c4-a28f-f740bcf50ff5.png)

> Adding a 1px outline with a darker color makes it much clearer.

Another advanced trick is stacking Outlines with lowered Opacity to create a staggered outline or glow/shadow effect. Unlike **Visual** Components, the Outline Component doesn't derive from `UnityEngine.UI.Graphic`, meaning there's no limit on how many Outlines a Panel can have.

![image](https://user-images.githubusercontent.com/33698270/215899049-e0aa0cd7-b607-466e-a0b7-0cfafa62bdae.png)

> right has no outlines. left is simulating a 3D effect using 3 stacked Outlines with low opacity. looks great in certain scenarios.


---


### Positioning your CUI alongside rust UI

for features that augment Rust's existing UI, like when you're working with Furnaces & other storage inventories, it's important to make sure your CUI doesn't interfere with the UI you augment.

Rust UI uses the same Placement system CUI does. It primarily uses offsets for sizing & positioning and anchors to a specific Point depending on the UI. by doing the same, you can ensure that your CUI is positioned properly, regardless of Screen size & Aspect Ratio.

UIs like the inventory, belt bar & storage containers are anchored to the bottom of the screen, but many other UIs don't follow that convention.

A great way to discover what a UI element is anchored to is to use the windowed mode and stretch it to extreme aspect ratios. This clearly reveals anchoring thanks to rust's offset scaling
![image](https://user-images.githubusercontent.com/33698270/216077347-5461623c-8ff4-4890-8633-062519c4e371.png)
> Stretching our window show that the Crafting & Contacts buttons are anchored to the top middle, while the status bars are anchored to the bottom right corner

a RectTransform Example that covers the Belt-bar
```json
{
"type": "RectTransform",
"anchormin": "0.5 0.0",
"anchormax": "0.5 0.0",
"offsetmin": "-200 18",
"offsetmax": "180 78"
}
```
![image](https://user-images.githubusercontent.com/33698270/215901408-c152fecb-8453-4597-8cd6-61038b2b976d.png)

**< [Previous Topic](/docs/components/README.md)** | **[Back to the Start](/README.md)**
40 changes: 40 additions & 0 deletions docs/components/Countdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Components: Countdown
**< [Previous Component](/docs/components/NeedsX.md)** | **[Back to Components](/docs/components/README.md)**

- Identifier: `Countdown`
- Category: **Misc**
- Unity Documentation: **N/A**

The Countdown Component lets you turn an existing Text Component into a Timer, Countdown, or Count-up. The Countdown Component automatically **destroys** the Panel when it’s done counting.
```json
{
"type": "Countdown",
"endtime": 0,
"startTime": 0,
"step": 1,
"command": ""
}
```

Countdown-specific Fields:
| Key | Type | Notes |
| :---------- | :----- | :------------------- |
| `endTime` | int | The Number it should count to |
| `startTime` | int | The Number it should start counting from |
| `step` | int | The Number it should increment by, also acts as the update interval |
| `command` | string | The command that should be executed when the Countdown finishes. |

## Working with Countdowns

for Countdowns to work, you need to add a **[Text](https://stackedit.io/docs/components/UnityEngine.UI.Text.md)** Component to your Panel. Your Text Component’s content should include the string `%TIME_LEFT%`, which the Countdown will replace with the current Number.

Examples:
- `the Event will end in %TIME_LEFT% Seconds` ⇒ the Event Will end in 30 Seconds
- `Power-up Buff - %TIME_LEFT%s` ⇒ Power-up Buff - 30s

### Counting Up vs counting Down
- to count Down, set your `startTime` higher than your `endTime` & set your `step` to at least 1.
- To count Up, set your `startTime` lower than your `endTime`


**< [Previous Component](/docs/components/NeedsX.md)** | **[Back to Components](/docs/components/README.md)**
19 changes: 19 additions & 0 deletions docs/components/NeedsX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Components: NeedsCursor & NeedsKeyboard
**< [Previous Component](/docs/components/UnityEngine.UI.InputField.md)** | **[Back to Components](/docs/components/README.md)** | **[Next Component](/docs/components/Countdown.md) >**

- Identifier: `NeedsCursor` or `NeedsKeyboard`
- Category: **Misc**
- Unity Documentation: **N/A**

The NeedsCursor & NeedsKeyboard Components are Components with no additional Fields. Their only purpose is to tell Rust's input Controller if mouse & keyboard Behavior should only be focused on your UI.
```json
{
"type": "NeedsCursor"
// or
"type": "NeedsKeyboard"
}
```

Unlike the `needsKeyboard` and `hudMenuInput` fields on an InputField Component, these Components Prevent default Behavior until your Panel is Destroyed

**< [Previous Component](/docs/components/UnityEngine.UI.InputField.md)** | **[Back to Components](/docs/components/README.md)** | **[Next Component](/docs/components/Countdown.md) >**
32 changes: 32 additions & 0 deletions docs/components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Components
**< [Previous Topic](/docs/Basics.md)** | **[Back to the Start](/README.md)** | **[Next Topic](/docs/Bugs-Tips.md) >**

The CUI System comes with a Set of Components you can use to build your UI, some are visual, and others add Interactivity.

Components are added to a panel by sending them as a List in the Schema shown in [The Basics](/docs/Basics.md). To identify the Type of Component sent, a `type` Field is added by every Component.
```json
[{
"type": "UnityEngine.UI.Text",
// More Component fields ...
},
...]
```

## Component List
- [RectTransform](/docs/components/RectTransform.md)
- [RawImage](/docs/components/UnityEngine.UI.RawImage.md)
- [Image](/docs/components/UnityEngine.UI.Image.md)
- [Text](/docs/components/UnityEngine.UI.Text.md)
- [Outline](/docs/components/UnityEngine.UI.Outline.md)
- [Button](/docs/components/UnityEngine.UI.Button.md)
- [InputField](/docs/components/UnityEngine.UI.InputField.md)
- [NeedsCursor & NeedsKeyboard](/docs/components/NeedsX.md)
- [Countdown](/docs/components/Countdown.md)

## About Component Categories
Each Component Page has a _Category_ listed, which helps you identify what a Component does. Pay attention to the **Visual** Category, as it means the Component Adds a Unity Component deriving from `UnityEngine.UI.Graphic`. This is important because **each panel can only have 1 Graphic Component**.

---
The next Topic explains common Pitfalls & Things you need to look out for

**< [Previous Topic](/docs/Basics.md)** | **[Back to the Start](/README.md)** | **[Next Topic](/docs/Bugs-Tips.md) >**
Loading