Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
160 commits
Select commit Hold shift + click to select a range
1aa4346
commit so I can PR this
screret Jul 1, 2025
92906af
Merge branch '1.20.1' into mui2-refactor
Spicierspace153 Jul 28, 2025
d235841
base package for mui (#3603)
YoungOnionMC Aug 2, 2025
087aa05
Client/screen package (#3664)
YoungOnionMC Aug 7, 2025
d53ae11
Api/widget (#3667)
YoungOnionMC Aug 13, 2025
151245e
api/widgets (#3682)
YoungOnionMC Aug 13, 2025
f251853
syncing (#3718)
YoungOnionMC Aug 17, 2025
f62c758
themes (#3867)
YoungOnionMC Sep 6, 2025
ab31e62
drawables + spotless (#3842)
YoungOnionMC Sep 6, 2025
a1df1d9
api/util (#3871)
YoungOnionMC Sep 6, 2025
1a04d05
json utils (#3875)
YoungOnionMC Sep 8, 2025
292cca4
screen overlays (#3876)
YoungOnionMC Sep 12, 2025
5301047
api/facotry + spotless (#4022) - [Admin]
YoungOnionMC Oct 6, 2025
4f035fa
missing utils (#4023) - [Admin]
YoungOnionMC Oct 6, 2025
2c7c2af
Common + factories (#4024) - [Admin]
YoungOnionMC Oct 6, 2025
18acafa
mui mixins (#4025) - [Admin]
YoungOnionMC Oct 6, 2025
7ed6aeb
xei integration (#4026) - [Admin]
YoungOnionMC Oct 6, 2025
2eef805
fake level (#4027) - [Admin]
YoungOnionMC Oct 6, 2025
8b7117a
Retry misc files, game launches now (#4031)
YoungOnionMC Oct 6, 2025
b6ad2ab
update mui2 refactor up to #4019 (#4033)
YoungOnionMC Oct 6, 2025
eeb2809
[MUI2] Fix image & adaptable sizing in GTGuiTextures (#4039)
purebluez Oct 7, 2025
7c7dbb7
Fix Tooltip Rendering inside mui UIs (#4038)
Spicierspace153 Oct 7, 2025
997803b
[MUI2] Merge MUI2's GuiTextures with GT's GTGuiTextures (#4041)
purebluez Oct 8, 2025
03b250c
Test Tile, Fixing Sync networking (#4043)
YoungOnionMC Oct 8, 2025
e8954e9
Item Count, Tooltip Layering, Debug Keybind (#4040)
YoungOnionMC Oct 8, 2025
9c3e99f
Fix Mouse Offsets in various contexts (#4044)
YoungOnionMC Oct 8, 2025
f472454
Making UI in builders (#4046)
jurrejelle Oct 8, 2025
e07dca8
Fix mui dark background layer (#4049)
brachy84 Oct 9, 2025
1158022
Part 1 of MUI updating (#4052)
YoungOnionMC Oct 9, 2025
6109f06
Entity Drawables (#4054)
YoungOnionMC Oct 9, 2025
2246011
Part 2 of Mui Updating (#4053)
YoungOnionMC Oct 10, 2025
ac8bb79
[MUI2] Animation refactor (#4055)
jurrejelle Oct 10, 2025
abc97dd
Add the missing CharTyped event listener to ClientScreenHandler (#4045)
screret Oct 10, 2025
95cb0b8
[MUI2] PlayerInventoryUIFactory + Curios compat (#4056)
brachy84 Oct 11, 2025
f3169a0
update mui p4 (#4059)
YoungOnionMC Oct 11, 2025
abddbae
[MUI2] dynamic sync (#4060)
jurrejelle Oct 11, 2025
487949a
[MUI2] Fix Textfield (#4061)
brachy84 Oct 11, 2025
b48f997
Machine Controller Cover Gui (#4048)
YoungOnionMC Oct 11, 2025
e919ec5
More MUI updaing p5 (#4062)
YoungOnionMC Oct 12, 2025
6ed2f80
Resizeable Panels (#4063)
YoungOnionMC Oct 12, 2025
ffb0018
[MUI] updating pt 6 (#4064)
jurrejelle Oct 12, 2025
fee1fca
update mui p7 (#4068)
YoungOnionMC Oct 13, 2025
3577211
Port CleanroomMC/ModularUI#135 (#4077)
Spicierspace153 Oct 18, 2025
ce70a1e
Port CleanroomMC/ModularUI#140 (#4067)
screret Oct 18, 2025
3f91da7
[MUI2] Small commits (#4083)
brachy84 Oct 18, 2025
bc78acf
Make schema rendering code sane (#4084)
screret Oct 18, 2025
741729a
Theme refactoring and improvements (#4087)
YoungOnionMC Oct 19, 2025
9a5e999
[MUI2] Fix slot desync on world load (#4088)
brachy84 Oct 19, 2025
ae22f62
scroll bars and fixes idk (#4091)
YoungOnionMC Oct 20, 2025
8e9b34c
the rest of the owl (#4092)
YoungOnionMC Oct 20, 2025
ca2be0e
[MUI] Fix depth problems (#4095)
brachy84 Oct 20, 2025
e7964e4
merge 1.20 into mui2 refactor (#4100)
YoungOnionMC Oct 21, 2025
5d42461
cache multi preview renders (#4096)
screret Oct 21, 2025
227c649
Fix Machine Controller Cover's UI (#4105)
purebluez Oct 22, 2025
d6587e8
[MUI] Fix several mui issues (#4112)
brachy84 Oct 24, 2025
a32e70b
[MUI2] Port Storage Cover (#4153)
purebluez Nov 6, 2025
d4907f1
[MUI] add UI builder option to multis (#4162)
jurrejelle Nov 9, 2025
0b939ca
Background Inverse Texture (#4165)
Ghostipedia Nov 10, 2025
e1d464b
Background Inverse Texture but I give it the right size this time! (#…
Ghostipedia Nov 10, 2025
422ec6e
Make Base Backgrounds/Tabs Sharpened to Match 1.12 Stylizing (#4167)
Ghostipedia Nov 10, 2025
0df4742
Update MUI to 727a80b4 (#4173)
YoungOnionMC Nov 13, 2025
82d0d08
Update MUI to current as of 11-13-25 (#4178)
YoungOnionMC Nov 14, 2025
3b81957
[MUI2] Dynamic singleblock UI from recipe type (#4101)
jurrejelle Nov 15, 2025
0fc5dee
Update MUI as of 11-15-2025 (#4185)
YoungOnionMC Nov 15, 2025
10a5fbe
[MUI2] Port Advanced Energy Detector Cover (#4191)
purebluez Nov 17, 2025
ea8bbfe
Multipart foundational + item bus - [MUI2] (#4222)
YoungOnionMC Nov 23, 2025
6cbda2a
Steam Machine and fisher work - [MUI2] (#4221)
YoungOnionMC Nov 23, 2025
52c9295
RecipeTypeUI foundation - [MUI2] (#4220)
YoungOnionMC Nov 23, 2025
6c6100a
[MUI2] Add an addMultiLang method to IRichTextBuilder (#4223)
purebluez Nov 24, 2025
0b7af8f
[MUI2] Parallel hatches (#4218)
jurrejelle Nov 24, 2025
ce055e7
[MUI] Remove floating "Inventory" (#4217)
jurrejelle Nov 24, 2025
767fa1f
[MUI] Block breaker UI (#4216)
jurrejelle Nov 24, 2025
60200f8
[MUI2] Buffer (#4234)
jurrejelle Nov 25, 2025
b5c9eda
[MUI2] Object Holder (#4232)
jurrejelle Nov 29, 2025
9e1058d
[MUI2] Data Hatches (#4251)
jurrejelle Nov 29, 2025
4d1c891
[MUI2] Muffler Hatch (#4253)
jurrejelle Nov 29, 2025
7f97b17
[MUI2] Object holder rework slots (#4256)
jurrejelle Nov 29, 2025
8b1f7ed
Fix new object holder GUI using the wrong slot index for the input it…
screret Dec 1, 2025
468492d
[MUI2] Extract createSquareSlotgroupFromInventory (#4255)
jurrejelle Dec 1, 2025
3e92d4f
[MUI2] Super/Quantum Tank (#4282)
jurrejelle Dec 12, 2025
f47f9ba
[MUI2] Creative computation provider (#4294)
TarLaboratories Dec 13, 2025
01a95bd
[MUI2] Battery Buffer (#4281)
TarLaboratories Dec 13, 2025
5dcb495
Fix MUI not being reopened properly (#4354)
ghzdude Dec 22, 2025
19a1a6b
[MUI2] Miner (#4334)
TarLaboratories Dec 22, 2025
c22fe63
[MUI2] Item Collector (#4332)
TarLaboratories Dec 22, 2025
60bbd20
[MUI2] Turbo Charger (#4331)
TarLaboratories Dec 22, 2025
041b4d3
[MUI2] Maintenance Hatch (#4328)
TarLaboratories Dec 22, 2025
e411451
[MUI2] Center stuff in battery buffer UI (#4315)
TarLaboratories Dec 22, 2025
e64c796
[MUI2] Dual Hatch (#4330)
TarLaboratories Dec 22, 2025
f64fd10
[MUI2] rotor holder (#4252)
jurrejelle Dec 22, 2025
c3ab309
[MUI2] Fluid Hatch (#4344)
TarLaboratories Dec 22, 2025
ebfa8a2
[MUI] - Singleblock RecipeType UIs (#4309)
YoungOnionMC Dec 22, 2025
f274292
[MUI2] Programmed Circuit (#4311)
TarLaboratories Dec 22, 2025
62f81d8
[MUI2] Fix Tiled UITextures not drawing correctly (#4358)
ghzdude Dec 22, 2025
56ab3bd
mui2 merge nightmare (#4360)
YoungOnionMC Dec 23, 2025
786ece6
14759d1a to d4e989e0, skipped 848d9e60 (#4366)
YoungOnionMC Dec 23, 2025
6e0afaa
[MUI2] Fix Theme Deserialization (#4373)
ghzdude Dec 24, 2025
158aeac
Start of theme application for steam machines (#4374)
YoungOnionMC Dec 24, 2025
49af1a7
[MUI2] - Steam Boilers (#4380)
YoungOnionMC Dec 26, 2025
936eea8
[MUI2] Auto Maintenance Hatch (#4391)
zetrock1 Jan 1, 2026
f5a4a75
[MUI2] Pump Machine (#4357)
zetrock1 Jan 5, 2026
df3c771
Merge remote-tracking branch 'origin/1.20.1-v8.0.0' into mui2-refactor
YoungOnionMC Jan 5, 2026
5edc0a0
fix the merge that happened [MUI2] (#4425)
YoungOnionMC Jan 5, 2026
276effa
Update MUI to 3 Jan 2026 (#4434)
YoungOnionMC Jan 7, 2026
0450b41
[MUI2] Fix client classes being loaded on server (#4442)
TarLaboratories Jan 8, 2026
c02965c
Merge 1.20.1 8.0.0 into mui2 refactor (#4448)
jurrejelle Jan 8, 2026
30c189c
CursorHandler fix (#4449)
zetrock1 Jan 9, 2026
6058048
[MUI2] Quantum Chest (#4356)
zetrock1 Jan 15, 2026
c1f52bc
Circuit Set correct value on sync read amount (#4480)
jurrejelle Jan 18, 2026
4240ec5
[MUI2 Docs] Starting MUI2 Sync docs (#4509)
jurrejelle Jan 28, 2026
22e5488
Add synced actions docs (#4514)
jurrejelle Jan 29, 2026
b20ddfb
MUI2 Positioning + Layout docs (#4524)
jurrejelle Feb 3, 2026
4fd1c42
Allow drawing non-living entities with EntityDrawable (and port f61dc…
screret Feb 3, 2026
85c5239
Clean up some hatch uis (#4540)
YoungOnionMC Feb 3, 2026
4a5863d
update mui to pre 3.1 (#4542)
YoungOnionMC Feb 3, 2026
49d9040
3.1 MUI (#4547)
YoungOnionMC Feb 4, 2026
355463c
[MUI2] ME Pattern Buffers and Proxies (#4515)
NegaNote Feb 4, 2026
837a79c
Update MUI to 4/2/2026 (#4553)
YoungOnionMC Feb 4, 2026
e5d58fa
[MUI2] More / better sync docs (#4546)
jurrejelle Feb 5, 2026
741e75e
Merge remote-tracking branch 'origin/1.20.1-v8.0.0' into mui2-refactor
YoungOnionMC Feb 5, 2026
26c5f2f
update 8.0.0 into mui2 refactor :iminsomuchpain:
YoungOnionMC Feb 5, 2026
5310c03
Merge 8.0.0 into mui2 refactor (#4555)
TechLord22 Feb 5, 2026
f887fec
[MUI] - Fix EMI Addon Registrations (#4557)
Ghostipedia Feb 5, 2026
4ba098a
[MUI2] ME PARTS (#4558)
Ghostipedia Feb 6, 2026
6c3ef94
[MUI] Conveyor and Simple Filter (#4128)
Spicierspace153 Feb 6, 2026
4eb2920
[MUI2] Primitive Blast Furnace (#4362)
zetrock1 Feb 6, 2026
45dce74
[MUI2] Coke Oven Machine (#4372)
zetrock1 Feb 6, 2026
9475b80
[MUI] Creative Energy Source (#4164)
Spicierspace153 Feb 8, 2026
5df5c8a
Start of Multiblock UIs and the underlying systems (#4575)
YoungOnionMC Feb 8, 2026
7c166ff
Implement more covers & implement all filters (#4565)
gustovafing Feb 9, 2026
4847019
update mui with 8.0 p2 (#4583)
YoungOnionMC Feb 9, 2026
e9afb89
Steam Parallel multi MUI (#4598)
YoungOnionMC Feb 10, 2026
39abe27
[MUI2] Power Substations (#4605)
jurrejelle Feb 12, 2026
6e27ec4
[MUI2] Multiblock Tank Machine (#4359)
zetrock1 Feb 12, 2026
f652a77
[MUI2] Large Boiler (#4612)
jurrejelle Feb 12, 2026
b686b06
Only display parallel lines if > 1 (#4614)
YoungOnionMC Feb 13, 2026
922099f
Merge branch '1.20.1' into jj/mui2/merge-1.20.1-p1
jurrejelle Feb 16, 2026
a50dc8b
Misc merge fixes
jurrejelle Feb 16, 2026
519f379
it launches
jurrejelle Feb 16, 2026
9da4ab7
spotless
jurrejelle Feb 16, 2026
c985ae7
Merge 1.20.1 into mui2-refactor (#4645)
Ghostipedia Feb 16, 2026
468a687
Remove IDisplayUIMachine (#4647)
jurrejelle Feb 17, 2026
338eaab
[MUI2] Research station UI (#4619)
jurrejelle Feb 17, 2026
2e6af0c
[MUI2] Data bank (#4621)
jurrejelle Feb 17, 2026
b8e345d
[MUI2] Cleanroom (#4631)
jurrejelle Feb 17, 2026
c9977e1
[MUI2] Active Transformer (#4633)
jurrejelle Feb 17, 2026
e165325
port 1.20/1.12 branches up to 18/2/2026 (#4654)
YoungOnionMC Feb 18, 2026
3587ebb
Finish most cover UIs (#4653)
gustovafing Feb 18, 2026
69b6b86
Fix IllegalStateException when opening a machine GUI (#4661)
brachy84 Feb 19, 2026
54b11a8
[MUI2] Tool AoE config (#4390)
TarLaboratories Feb 19, 2026
76118e3
remove remaining singleblock ldlib ui stuff (#4673)
gustovafing Feb 22, 2026
ceefb8f
[MUI2] HPCA (#4675)
TarLaboratories Feb 23, 2026
97f6164
Merge 1.20.1 into mui2-refactor (#4672)
gustovafing Feb 23, 2026
7c312cb
[MUI2] Code Editor (#4388)
TarLaboratories Mar 2, 2026
8395867
[MUI2] Central monitor (#4535)
TarLaboratories Mar 2, 2026
d534954
[MUI2] GUI Module (#4389)
TarLaboratories Mar 2, 2026
9a9b557
switch grid overlays to UITexture (#4719)
gustovafing Mar 7, 2026
72687ff
[MUI2] Central Monitor fixes (#4707)
TarLaboratories Mar 8, 2026
cd87cd3
steam miner machine ui (#4721)
gustovafing Mar 16, 2026
ffb7001
remove usages of ldlib builder util (#4720)
gustovafing Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ dependencies {
// Configuration
jarJar(modApi(forge.configuration.get()))

// Math Parser
jarJar(implementation(libs.evalEx.get()))
additionalRuntimeClasspath(libs.evalEx.get())

// Mixin (& Extras)
annotationProcessor(variantOf(libs.mixin) { classifier("processor") })
compileOnly(annotationProcessor(forge.mixinExtras.common.get()))
Expand Down Expand Up @@ -118,4 +122,6 @@ dependencies {
modExtraLocalRuntime(forge.ponder)
modExtraLocalRuntime(variantOf(forge.create) { classifier("slim") })
modExtraLocalRuntime(forge.flywheel.forge)

modLocalRuntime(forge.curios)
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
268 changes: 268 additions & 0 deletions docs/content/Development/MUI2/Syncing/Sync-Basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# Sync Basics

## Basics of Syncing
To display dynamic values on the client, you have to send the data from the server to the client. When making UIs, it is very important to keep track of if and how your data is being synced to the client. There are a few ways to do so, which will be discussed below.

When opening a UI, a copy of the UI is created both on the server and on the client. It is important to note here that the server's copy will have access to most everything about e.g. the machine, block state, the world etc., but the client's copy will not.

To sync this data back and forth, you need to use `SyncHandler`s. These will send your data from the server to the client when it updates.

Because of this, you cannot just use values you create SyncHandlers for directly in the client. An example:

```java

var tickSyncValue = new IntSyncValue(() -> this.ticks, (newValue) -> this.ticks = newValue);
for(int i=0;i<tickSyncValue.getValue(); i++){
//...
}
```
This would not work, intSyncValue hasn't had time to send data over yet and thus int is still 0 on the client side.

If you try to access values on the client that aren't synced or don't have a `SyncValue` or `SyncHandler`, they will have a default value, but they will not reflect the values or changes happening on the server.



## Method 1: Dynamic Widgets
The first method is using dynamic widgets, which update every frame regardless of what happens.
This method is easiest if you just need to sync some data over and display or edit it in a single widget.
Some examples are:

- `IKey.dynamic(Supplier<Component>)` - Queries the supplier every frame to retrieve the component to display
- `new DynamicDrawable(Supplier<IDrawable>)` - Queries the supplier every frame to retrieve the drawable to display


!!! Note
To convert IKeys or Drawables to Widgets, you need to chain `.asWidget()`

```java
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public int ticks = 0;

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
this.subscribeServerTick(() -> ticks++);
}

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 176, 168);
var tickSyncValue = new IntSyncValue(() -> this.ticks, (newValue) -> this.ticks = newValue);
syncManager.syncValue("tickSyncValue", tickSyncValue);

var column = Flow.column();

column.child(IKey.dynamic(() -> Component.literal("Ticks: " + this.ticks)) // note that this is a Supplier<Component> instead of a Component
.asWidget()
.margin(4));

column.child(
new DynamicDrawable(() -> { // note that this is a Supplier<IDrawable> instead of an IDrawable
if (ticks % 40 < 20) { // flip every second
return GTGuiTextures.BUTTON_FLUID_OUTPUT;
} else {
return GTGuiTextures.BUTTON_ITEM_OUTPUT;
}
})
.asWidget()
.background(GTGuiTextures.BACKGROUND_STEEL)
);

panel.child(column);

return panel;
}
}
```

Here, we create a basic `SyncValue` for an integer. This takes a `Supplier<Integer>` and a `Consumer<Integer>`, more commonly known as a getter and a setter. Generally speaking, `SyncValue`s will take a `Supplier` and `Consumer` of the type of value they are syncing.

If the value returned by the getter changed on the server, the value gets serialized and sent to the client by the `SyncManager`. The `SyncHandler`'s value can always be manually updated, for example to do client-to-server syncing.

Then, the value on the client (being set every time the server sends an update) is retrieved every frame by the lambdas used in the dynamic widgets.

If you want to update the value from the client, you can call `syncValue.setValue()` on the client. This will also update the value on the server side.

## Method 2: DynamicLinkedSyncHandler

This method is great for widgets whose structure and layout can change depending on your synced values.

```java
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public int ticks = 0;

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
this.subscribeServerTick(() -> ticks++);
}

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 176, 168);
var tickSyncValue = new IntSyncValue(() -> this.ticks, (newValue) -> this.ticks = newValue);
syncManager.syncValue("tickSyncValue", tickSyncValue);

DynamicLinkedSyncHandler<IntSyncValue> dynamicLinkedSyncHandler = new DynamicLinkedSyncHandler<>(tickSyncValue)
.widgetProvider((widgetSyncManager, intSyncHandler) -> {
var list = new ListWidget<>()
.widthRel(1)
.coverChildrenHeight()
.crossAxisAlignment(Alignment.CrossAxis.START);
int tickValue = intSyncHandler.getValue(); // It is also possible to just reference this.ticks directly
int amountOfItems = 1 + (tickValue % 200) / 20;
for (int i = 0; i < amountOfItems; i++) {
list.child(IKey.str("Value nr. " + (i + 1)).asWidget()); // No need for IKey.dynamic since we have the value as a variable here, inside the lambda
}
return list;
});

panel.child(new DynamicSyncedWidget<>()
.widthRel(1)
.coverChildrenHeight()
.syncHandler(dynamicLinkedSyncHandler)
.padding(3));

return panel;
}
}
```

This method works in three steps:

The first step is creating a `SyncHandler` and registering it to the `PanelSyncManager`.
The second step is creating a `DynamicLinkedSyncHandler` based on the first `SyncHandler`. This is effectively a wrapper class to provide your widget whenever your initial `SyncHandler` updates.
The third step is creating a `DynamicSyncedWidget` with that `DynamicLinkedSyncHandler` as its `SyncHandler`.

This effectively lets us create a new "version" of the widget whenever our value (in this case the `ticks` int) changes. Furthermore, in this example we have the actual values of the things we want to sync when constructing our widget tree on the client, allowing for much greater customization.


!!! note
For even more complex systems where you need to dynamically register sync handlers within the `DynamicLinkedSyncHandler`'s `.widgetProvider(...)`, this can be done by calling `.getOrCreateSyncHandler(...)` on the `widgetSyncManager` parameter of the lambda.

## Method 3: Types that take SyncHandlers
There are some widgets that have built in support for working directly with SyncHandlers.

```java
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public boolean buttonPressed = false;

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
}

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 176, 168);

var column = Flow.column().paddingTop(3);

column.child(
IKey.dynamic(() -> Component.literal("Pressed: " + this.buttonPressed))
.asWidget());

var buttonSyncValue = new BooleanSyncValue(() -> this.buttonPressed, (newValue) -> this.buttonPressed = newValue);
column.child(new ToggleButton().value(buttonSyncValue));

panel.child(column);

return panel;
}
}
```

Note that in this case, the ToggleButton takes care of registering the SyncValue for us, so we do not register it to the syncManager ourselves. This method is great for simple functions using widgets that support it.

A few examples of this would be:

- `new ToggleButton().value(BooleanSyncValue)` - A ToggleButton that affects the Boolean sync value
- `new TextFieldWidget().value(StringSyncValue)` - A TextField that updates the String sync value
- `new ProgressWidget().value(DoubleSyncValue)` - A ProgressWidget (e.g. bar) that shows progress, can also be constructed with `new ProgressWidget().progress(() -> this.progress)`
- `new SliderWidget().value(DoubleSyncValue)` - A SliderWidget that updates the Double sync value

## Method 4: Manually notifying DynamicSyncHandlers
This method is useful when your custom widget needs complex data coming in, like through multiple sync handlers.

```java
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public int rows = 0;
public int columns = 0;
public int counter = 0;

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
this.subscribeServerTick(() -> {
counter += 1;
if (counter % 20 == 0) {
rows = (rows + 1) % 10;
}
if (counter % 15 == 0) {
columns = (columns + 1) % 10;
}
});
}

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 200, 200);

var rowsSyncValue = new IntSyncValue(() -> this.rows, (newValue) -> this.rows = newValue);
syncManager.syncValue("rows", rowsSyncValue);

var columnsSyncValue = new IntSyncValue(() -> this.columns, (newValue) -> this.columns = newValue);
syncManager.syncValue("columns", columnsSyncValue);

DynamicSyncHandler gridWidgetHandler = new DynamicSyncHandler().widgetProvider((slotsSyncManger, buffer) -> {

Flow grid = Flow.column().width(200);
for (int rowNr = 0; rowNr < this.rows; rowNr++) {
Flow row = Flow.row();
for (int columnNr = 0; columnNr < this.columns; columnNr++) {
row.child(IKey.str(rowNr + ", " + columnNr).asWidget().width(20));
}
grid.child(row);
}
return grid;
});

rowsSyncValue.setChangeListener(() -> {
gridWidgetHandler.notifyUpdate(buffer -> {});
});
columnsSyncValue.setChangeListener(() -> {
gridWidgetHandler.notifyUpdate(buffer -> {});
});

panel.child(new DynamicSyncedWidget<>().syncHandler(gridWidgetHandler));
return panel;
}
}
```

This is very similar to method 2, but instead of a `DynamicLinkedSyncHandler` we use a normal `DynamicSyncHandler` where we have to manually let it know when to update. We do this in the change listener of our two `SyncValue`s by calling notifyUpdate.

Do note there's also a buffer where you can serialize data to, to be consumed in the `.widgetProvider(...)` in the spot where in a `DynamicLinkedSyncHandler` our syncValue would be. It is usually not needed to put anything in this buffer.

## Other sync information

### SyncHandler panel separation

SyncValues are separated across panels. So if you do `mainPanelSyncManager.syncValue("rows", rowsSyncValue);` in one panel, you can't just call `popupSyncManager.getSyncHandlerFromMapKey("rows:0")`.
You can, however, call `syncManager.getModularSyncManager().getPanelSyncManager("panel name here").getSyncHandlerFromMapKey("rows:0");`.

### Value.Dynamic
Sometimes you need to quickly create a Value for something that already exists client side. For this you can use `new [Type]Value.Dynamic(...)`.
For example, if you have a client-only value that's affected by a button, you could do
`panel.child(new ToggleButton().value(new BoolValue.Dynamic(() -> this.toggled, (newValue) -> this.toggled = newValue)));`

Another reason to use a dynamic value is if you want to change the type of a variable, e.g. `.value(new DoubleValue.Dynamic(() -> (double) this.x, val -> this.x = (double) val)` where x is an int.

The third reason is if you want to use a `SyncHandler` in two separate widgets that would both auto-register it.
```
var boolSyncValue = new BooleanSyncValue(() -> this.toggled, (newValue) -> this.toggled = newValue);
panel.child(new ToggleButton().value(boolSyncValue));
panel.child(new ToggleButton().value(BoolValue.wrap(boolSyncValue)).left(32));
```
Without the wrap around the second boolSyncValue call, it would complain of registration of an already registered SyncValue.

48 changes: 48 additions & 0 deletions docs/content/Development/MUI2/Syncing/Synced-Actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Synced Actions

```java
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
}

public int number = 0;

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 176, 168);

var numberSyncValue = new IntSyncValue(() -> this.number, (newValue) -> this.number = newValue);
syncManager.syncValue("number", numberSyncValue);

syncManager.registerServerSyncedAction("randomButtonPressed", (packet) -> {
this.number = getLevel().getRandom().nextInt();
});

Column contents = new Column();
contents.child(IKey.dynamic(() -> Component.literal("Number: " + number))
.asWidget()
.width(100)
.height(16)
.margin(4));

contents.child(new ButtonWidget<>()
.onMousePressed((x, y, button) -> {
if (button == 0) {
syncManager.callSyncedAction("randomButtonPressed");
}
return true;
})
.size(16));
return panel.child(contents);
}
}

```

Synced actions are useful when you need a client-side input (e.g. a button press) to trigger an action on the server.

In this case we create a synced action called `randomButtonPressed`, and when the button is pressed on the client, the `randomButtonPressed` signal is sent to the server and the relevant action is executed.

If you need to pass other data with your action, you can pass a `(packet) -> {...}` as second argument to `callSyncedAction` and serialize your data there, and then deserialize it from the `packet` argument in the synced action definition.
1 change: 1 addition & 0 deletions docs/content/Development/MUI2/Syncing/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Syncing is the concept of synchronising data between client and server. This folder will contain files relevant to setting up syncing on your UIs.
35 changes: 35 additions & 0 deletions docs/content/Development/MUI2/Test-Machine.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Making a MUI2 Test Machine
To make a basic machine to test your UI, simply create the following class:

```java title="MultiMachines.java"
public class MuiTestMachine extends MetaMachine implements IMuiMachine {

public MuiTestMachine(BlockEntityCreationInfo info) {
super(info);
}

@Override
public ModularPanel buildUI(PosGuiData data, PanelSyncManager syncManager, UISettings settings) {
var panel = GTGuis.createPanel(this, 176, 168);
// Do stuff with your panel here, add children, etc.
// For example:
panel.child(IKey.str("Test machine")
.asWidget()
.margin(4));

return panel;
}
}
```

and in your machines definitions class, add the following entry:

```java
public static final MachineDefinition MUI_TEST_MACHINE = REGISTRATE
.machine("mui_test", MuiTestMachine::new)
.model(createOverlayCasingMachineModel(GTCEu.id("block/casings/solid/machine_casing_clean_stainless_steel"),
GTCEu.id("block/machine/part/computer_monitor")))
.register();
```

Make sure to run datagen after making the initial machine to register the lang keys, model, etc. Running datagen afterward for UI changes is not required.
Loading
Loading