init()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
dl 0
loc 19
rs 9.7
c 0
b 0
f 0
1
package de.pewpewproject.lasertag.client.screen;
2
3
import de.pewpewproject.lasertag.client.screen.widget.*;
4
import de.pewpewproject.lasertag.common.types.Tuple;
5
import de.pewpewproject.lasertag.lasertaggame.settings.SettingDescription;
6
import de.pewpewproject.lasertag.networking.NetworkingConstants;
7
import io.netty.buffer.Unpooled;
8
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
9
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
10
import net.minecraft.client.MinecraftClient;
11
import net.minecraft.client.gui.Drawable;
12
import net.minecraft.client.gui.screen.Screen;
13
import net.minecraft.client.gui.widget.ButtonWidget;
14
import net.minecraft.client.gui.widget.TextFieldWidget;
15
import net.minecraft.entity.player.PlayerEntity;
16
import net.minecraft.network.PacketByteBuf;
17
import net.minecraft.text.Text;
18
19
import java.util.ArrayList;
20
import java.util.Arrays;
21
import java.util.Comparator;
22
import java.util.List;
23
24
import static de.pewpewproject.lasertag.lasertaggame.settings.SettingDataType.BOOL;
25
import static de.pewpewproject.lasertag.lasertaggame.settings.SettingDataType.LONG;
26
27
/**
28
 * The settings screen of the lasertag game manager
29
 *
30
 * @author Étienne Muser
31
 */
32
public class LasertagGameManagerSettingsScreen extends GameManagerScreen {
33
34
    private ListWidget<Tuple<SettingDescription, Object>, SettingDescription> list;
35
36
    public LasertagGameManagerSettingsScreen(Screen parent, PlayerEntity player) {
37
        super(parent, "gui.game_manager.settings_screen_title", player);
38
    }
39
40
    /**
41
     * Reload the lists data source
42
     */
43
    public void resetList() {
44
        this.list.refreshDataSource();
45
    }
46
47
    @Override
48
    public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
49
        // Forward the mouse scrolled event to the list
50
        return this.list.mouseScrolled(mouseX, mouseY, amount);
51
    }
52
53
    @Override
54
    public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
55
        // Forward the mouse dragged event to the list
56
        return this.list.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
57
    }
58
59
    @Override
60
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
61
        // Forward the mouse clicked event to the list
62
        return this.list.mouseClicked(mouseX, mouseY, button) || super.mouseClicked(mouseX, mouseY, button);
63
    }
64
65
    @Override
66
    public void tick() {
67
        // Forward the tick to the list - the list contains text field widgets
68
        this.list.tick();
69
    }
70
71
    @Override
72
    protected void init() {
73
        super.init();
74
        this.addAdditionalButtons();
75
76
        var columns = new ArrayList<ListColumn<Tuple<SettingDescription, Object>, SettingDescription>>(3);
77
78
        columns.add(new ListColumn<>(this::getNameCellTempate, Tuple::x, 9));
79
        columns.add(new ListColumn<>(this::getValueCellTemplate, Tuple::x, 7));
80
        columns.add(new ListColumn<>(this::getResetCellTemplate, Tuple::x, 2));
81
82
        var columnsDefinition = new ListColumnsDefinition<>(columns);
83
84
        var availableHeight = this.height - (2 * verticalPadding + this.textRenderer.fontHeight + 2 * buttonPadding + buttonHeight);
85
86
        this.list = this.addDrawableChild(ListWidget.fromAvailableHeight(horizontalPadding, verticalPadding + textRenderer.fontHeight + buttonPadding,
87
                this.width - 2 * horizontalPadding, availableHeight,
88
                this::getSettingDescriptions,
89
                columnsDefinition, this, this.textRenderer));
90
    }
91
92
    /**
93
     * Get the template for the name column of the list
94
     *
95
     * @param desc The cell description
96
     * @return The cell template
97
     */
98
    private Drawable getNameCellTempate(ListCell<Tuple<SettingDescription, Object>> desc) {
99
100
        var startY = desc.y() + (desc.height() / 2) - (this.textRenderer.fontHeight / 2);
101
        return new LabelWidget(desc.x() + 5, startY, this.textRenderer, Text.translatable("gui.game_manager.settings." + desc.value().x().getName()));
102
    }
103
104
    /**
105
     * Get the template for the value column of the list
106
     *
107
     * @param desc The cell description
108
     * @return The cell template
109
     */
110
    private Drawable getValueCellTemplate(ListCell<Tuple<SettingDescription, Object>> desc) {
111
112
        var dataType = desc.value().x().getDataType();
113
        if (dataType.equals(BOOL)) {
114
            return this.getBooleanSettingInput(desc.x() + 1, desc.y() + 1, desc.width() - 1, desc.height() - 2, desc.value().x().toString(), (Boolean) desc.value().y());
115
        } else if (dataType.equals(LONG)) {
116
            return this.getLongSettingInput(desc.x() + 2, desc.y() + 2, desc.width() - 4, desc.height() - 4, desc.value().x().toString(), (long) desc.value().y());
117
        } else if (dataType.isEnum()) {
118
            return this.getEnumSettingInput(desc.x() + 1, desc.y() + 1, desc.width() - 1, desc.height() - 2, desc.value().x().toString(), (Enum<?>)desc.value().y());
119
        }
120
121
        // Default empty drawable
122
        return (matrices, mouseX, mouseY, delta) -> {};
123
    }
124
125
    /**
126
     * Get the template for the reset button column of the list
127
     *
128
     * @param desc The cell description
129
     * @return The cell template
130
     */
131
    private Drawable getResetCellTemplate(ListCell<Tuple<SettingDescription, Object>> desc) {
132
133
        // If player has not enough rights to edit settings
134
        if (!this.player.hasPermissionLevel(4)) {
135
            // Return empty drawable
136
            return (matrices, mouseX, mouseY, delta) -> {};
137
        }
138
139
        var buttonWidget = new ButtonWidget(desc.x() + 1, desc.y() + 1, desc.width() - 2, desc.height() - 2, Text.translatable("gui.reset"), button -> {
140
            // Create packet buffer
141
            var buf = new PacketByteBuf(Unpooled.buffer());
142
143
            buf.writeString(desc.value().x().getName());
144
145
            ClientPlayNetworking.send(NetworkingConstants.CLIENT_TRIGGER_SETTING_RESET, buf);
146
        });
147
        buttonWidget.active = this.player.hasPermissionLevel(4);
148
149
        return buttonWidget;
150
    }
151
152
    /**
153
     * The data source for the list
154
     *
155
     * @return The setting descriptions and values
156
     */
157
    private List<Tuple<SettingDescription, Object>> getSettingDescriptions() {
158
159
        // Get the game managers
160
        var gameManager = MinecraftClient.getInstance().world.getClientLasertagManager();
161
        var gameModeManager = gameManager.getGameModeManager();
162
        var settingsManager = gameManager.getSettingsManager();
163
164
        return gameModeManager.getGameMode().getRelevantSettings().stream()
165
                .sorted(Comparator.comparing(SettingDescription::getName))
166
                .map(s -> {
167
168
                    Object value;
169
                    if (s.getDataType().isEnum()) {
170
                        value = settingsManager.getEnum(s);
171
                    } else {
172
                        value = settingsManager.get(s);
173
                    }
174
175
                    return new Tuple<>(s, value);
176
                }).toList();
177
    }
178
179
    /**
180
     * Get the template for a boolean setting value
181
     *
182
     * @param x The start x-value of the cell
183
     * @param y The start y-value of the cell
184
     * @param width The width of the cell
185
     * @param height The height of the cell
186
     * @param settingEnumName The enum name of the setting description
187
     * @param initialValue The initial value of the setting
188
     * @return The cell template
189
     */
190
    private Drawable getBooleanSettingInput(int x, int y, int width, int height, String settingEnumName, boolean initialValue) {
191
        if (player.hasPermissionLevel(4)) {
192
            var buttonWidet = new YesNoButtonWidget(x, y, width, height, initialValue, (newValue) -> {
193
                // Create packet buffer
194
                var buf = new PacketByteBuf(Unpooled.buffer());
195
196
                buf.writeString(settingEnumName);
197
                buf.writeBoolean(newValue);
198
199
                ClientPlayNetworking.send(NetworkingConstants.CLIENT_TRIGGER_SETTING_CHANGE, buf);
200
            });
201
202
            buttonWidet.active = this.player.hasPermissionLevel(4);
203
204
            return buttonWidet;
205
        } else {
206
            var startY = y + (height / 2) - (this.textRenderer.fontHeight / 2);
207
            return new LabelWidget(x + 5, startY, this.textRenderer, Text.translatable(initialValue ? "gui.yes" : "gui.no"));
208
        }
209
    }
210
211
    /**
212
     * Get the template for a long setting value
213
     *
214
     * @param x The start x-value of the cell
215
     * @param y The start y-value of the cell
216
     * @param width The width of the cell
217
     * @param height The height of the cell
218
     * @param settingEnumName The enum name of the setting description
219
     * @param initialValue The initial value of the setting
220
     * @return The cell template
221
     */
222
    private Drawable getLongSettingInput(int x, int y, int width, int height, String settingEnumName, long initialValue) {
223
        if (player.hasPermissionLevel(4)) {
224
            var textFieldWidget = new TextFieldWidget(this.textRenderer, x, y, width, height, Text.empty());
225
            textFieldWidget.setText(Long.toString(initialValue));
226
227
            textFieldWidget.setChangedListener(newValue -> {
228
229
                // Try to parse new value to long
230
                try {
231
                    var newLongValue = Long.parseLong(newValue);
232
233
                    if (newLongValue == initialValue) {
234
                        return;
235
                    }
236
237
                    // Get the setting description
238
                    var settingDescription = SettingDescription.valueOf(settingEnumName);
239
240
                    var minValue = settingDescription.getMinValue();
241
                    if (minValue != null && newLongValue < (long) minValue) {
242
                        newLongValue = (long) minValue;
243
                    }
244
245
                    var maxValue = settingDescription.getMaxValue();
246
                    if (maxValue != null && newLongValue > (long) maxValue) {
247
                        newLongValue = (long) maxValue;
248
                    }
249
250
                    // Create packet buffer
251
                    var buf = new PacketByteBuf(Unpooled.buffer());
252
253
                    buf.writeString(settingEnumName);
254
                    buf.writeLong(newLongValue);
255
256
                    ClientPlayNetworking.send(NetworkingConstants.CLIENT_TRIGGER_SETTING_CHANGE, buf);
257
                } catch (NumberFormatException ignored) {
258
                    // Do nothing
259
                }
260
            });
261
262
            return textFieldWidget;
263
        } else {
264
            var startY = y + (height / 2) - (this.textRenderer.fontHeight / 2);
265
            return new LabelWidget(x + 5, startY, this.textRenderer, Text.literal(Long.toString(initialValue)));
266
        }
267
    }
268
269
    private Drawable getEnumSettingInput(int x, int y, int width, int height, String settingEnumName, Enum<?> initialValue) {
270
        if (player.hasPermissionLevel(4)) {
271
272
            // Get the setting description
273
            var settingDescription = SettingDescription.valueOf(settingEnumName);
274
275
            // Get the enum values
276
            var enumValues = settingDescription.getDataType().getValueType().getEnumConstants();
277
278
            return new CyclingValueButtonWidget<>(x, y, width, height, initialValue,
279
                    value -> Text.translatable(settingEnumName + "." + ((Enum<?>)value).name()),
280
                    Arrays.stream(enumValues).toList(),
281
                    value -> {
282
                        // Get the enum value as a string
283
                        var enumValueString = ((Enum<?>)value).name();
284
285
                        // Create packet buffer
286
                        var buf = new PacketByteBuf(Unpooled.buffer());
287
288
                        buf.writeString(settingEnumName);
289
                        buf.writeString(enumValueString);
290
291
                        ClientPlayNetworking.send(NetworkingConstants.CLIENT_TRIGGER_SETTING_CHANGE, buf);
292
                    });
293
        } else {
294
            var startY = y + (height / 2) - (this.textRenderer.fontHeight / 2);
295
            return new LabelWidget(x + 5, startY, this.textRenderer, Text.translatable(settingEnumName + "." + initialValue.name()));
296
        }
297
    }
298
299
    /**
300
     * Add the settings presets and reset all settings buttons
301
     */
302
    private void addAdditionalButtons() {
303
304
        if (!this.player.hasPermissionLevel(4)) {
305
            return;
306
        }
307
308
        this.addDrawableChild(new ButtonWidget(horizontalPadding, this.height - verticalPadding - buttonHeight, buttonWidth / 2, buttonHeight, Text.translatable("gui.game_manager.settings.presets"), button -> {
309
            this.client.setScreen(new LasertagGameManagerSettingsPresetsScreen(this, this.player));
310
        }));
311
312
        this.addDrawableChild(new ButtonWidget(horizontalPadding + (buttonWidth / 2) + 4, this.height - verticalPadding - buttonHeight, buttonWidth / 2, buttonHeight, Text.translatable("gui.game_manager.settings.reset_settings"), button -> {
313
            ClientPlayNetworking.send(NetworkingConstants.CLIENT_TRIGGER_SETTINGS_RESET, PacketByteBufs.empty());
314
        }));
315
    }
316
}
317