3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-07-31 09:38:06 +02:00

Split Forms into an Api and an implementation

Dieser Commit ist enthalten in:
Tim203 2020-11-26 23:00:43 +01:00
Ursprung 8b811b43fb
Commit e583abffdf
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 064EE9F5BF7C3EE8
43 geänderte Dateien mit 1965 neuen und 892 gelöschten Zeilen

Datei anzeigen

@ -31,7 +31,6 @@ import lombok.Getter;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum PlatformType { public enum PlatformType {
ANDROID("Android"), ANDROID("Android"),
BUNGEECORD("BungeeCord"), BUNGEECORD("BungeeCord"),
FABRIC("Fabric"), FABRIC("Fabric"),

Datei anzeigen

@ -25,153 +25,62 @@
package org.geysermc.common.form; package org.geysermc.common.form;
import com.google.gson.annotations.JsonAdapter; import org.geysermc.common.form.component.Component;
import lombok.Getter; import org.geysermc.common.form.component.DropdownComponent;
import org.geysermc.common.form.component.*; import org.geysermc.common.form.component.StepSliderComponent;
import org.geysermc.common.form.impl.CustomFormImpl;
import org.geysermc.common.form.response.CustomFormResponse; import org.geysermc.common.form.response.CustomFormResponse;
import org.geysermc.common.form.util.FormAdaptor;
import org.geysermc.common.form.util.FormImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@Getter public interface CustomForm extends Form<CustomFormResponse> {
@JsonAdapter(FormAdaptor.class) static CustomForm.Builder builder() {
public final class CustomForm extends Form { return new CustomFormImpl.Builder();
private final String title;
private final FormImage icon;
private final List<Component> content;
private CustomForm(String title, FormImage icon, List<Component> content) {
super(Form.Type.CUSTOM_FORM);
this.title = title;
this.icon = icon;
this.content = Collections.unmodifiableList(content);
} }
public static Builder builder() { static CustomForm of(String title, FormImage icon, List<Component> content) {
return new Builder(); return CustomFormImpl.of(title, icon, content);
} }
public static CustomForm of(String title, FormImage icon, List<Component> content) { interface Builder extends FormBuilder<Builder, CustomForm> {
return new CustomForm(title, icon, content); Builder icon(FormImage.Type type, String data);
}
public CustomFormResponse parseResponse(String data) { Builder iconPath(String path);
if (isClosed(data)) {
return CustomFormResponse.closed();
}
return CustomFormResponse.of(this, data);
}
public static final class Builder extends Form.Builder<Builder, CustomForm> { Builder iconUrl(String url);
private final List<Component> components = new ArrayList<>();
private FormImage icon;
public Builder icon(FormImage.Type type, String data) { Builder component(Component component);
icon = FormImage.of(type, data);
return this;
}
public Builder iconPath(String path) { Builder dropdown(DropdownComponent.Builder dropdownBuilder);
return icon(FormImage.Type.PATH, path);
}
public Builder iconUrl(String url) { Builder dropdown(String text, int defaultOption, String... options);
return icon(FormImage.Type.URL, url);
}
public Builder component(Component component) { Builder dropdown(String text, String... options);
components.add(component);
return this;
}
public Builder dropdown(DropdownComponent.Builder dropdownBuilder) { Builder input(String text, String placeholder, String defaultText);
return component(dropdownBuilder.translateAndBuild(this::translate));
}
public Builder dropdown(String text, int defaultOption, String... options) { Builder input(String text, String placeholder);
List<String> optionsList = new ArrayList<>();
for (String option : options) {
optionsList.add(translate(option));
}
return component(DropdownComponent.of(translate(text), optionsList, defaultOption));
}
public Builder dropdown(String text, String... options) { Builder input(String text);
return dropdown(text, -1, options);
}
public Builder input(String text, String placeholder, String defaultText) { Builder label(String text);
return component(InputComponent.of(
translate(text), translate(placeholder), translate(defaultText)
));
}
public Builder input(String text, String placeholder) { Builder slider(String text, float min, float max, int step, float defaultValue);
return component(InputComponent.of(translate(text), translate(placeholder)));
}
public Builder input(String text) { Builder slider(String text, float min, float max, int step);
return component(InputComponent.of(translate(text)));
}
public Builder label(String text) { Builder slider(String text, float min, float max, float defaultValue);
return component(LabelComponent.of(translate(text)));
}
public Builder slider(String text, float min, float max, int step, float defaultValue) { Builder slider(String text, float min, float max);
return component(SliderComponent.of(text, min, max, step, defaultValue));
}
public Builder slider(String text, float min, float max, int step) { Builder stepSlider(StepSliderComponent.Builder stepSliderBuilder);
return slider(text, min, max, step, -1);
}
public Builder slider(String text, float min, float max, float defaultValue) { Builder stepSlider(String text, int defaultStep, String... steps);
return slider(text, min, max, -1, defaultValue);
}
public Builder slider(String text, float min, float max) { Builder stepSlider(String text, String... steps);
return slider(text, min, max, -1, -1);
}
public Builder stepSlider(StepSliderComponent.Builder stepSliderBuilder) { Builder toggle(String text, boolean defaultValue);
return component(stepSliderBuilder.translateAndBuild(this::translate));
}
public Builder stepSlider(String text, int defaultStep, String... steps) { Builder toggle(String text);
List<String> stepsList = new ArrayList<>();
for (String option : steps) {
stepsList.add(translate(option));
}
return component(StepSliderComponent.of(translate(text), stepsList, defaultStep));
}
public Builder stepSlider(String text, String... steps) {
return stepSlider(text, -1, steps);
}
public Builder toggle(String text, boolean defaultValue) {
return component(ToggleComponent.of(translate(text), defaultValue));
}
public Builder toggle(String text) {
return component(ToggleComponent.of(translate(text)));
}
@Override
public CustomForm build() {
CustomForm form = of(title, icon, components);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
} }
} }

Datei anzeigen

@ -25,123 +25,59 @@
package org.geysermc.common.form; package org.geysermc.common.form;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.geysermc.common.form.response.FormResponse; import org.geysermc.common.form.response.FormResponse;
import org.geysermc.common.form.util.FormAdaptor;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
@Getter /**
public abstract class Form { * Base class of all Forms. While it can be used it doesn't contain every data you could get when
protected static final Gson GSON = * using the specific class of the form type.
new GsonBuilder() *
.registerTypeAdapter(ModalForm.class, new FormAdaptor()) * @param <T> class provided by the specific form type. It understands the response data and makes
.create(); * the data easily accessible
*/
public interface Form<T extends FormResponse> {
/**
* Returns the form type of this specific instance. The valid form types can be found {@link
* FormType in the FormType class}
*/
FormType getType();
private final Type type; /**
* Returns the data that will be sent by Geyser to the Bedrock client
*/
String getJsonData();
@Getter(AccessLevel.NONE) /**
protected String hardcodedJsonData = null; * Returns the handler that will be invoked once the form got a response from the Bedrock
* client
*/
Consumer<String> getResponseHandler();
@Setter protected Consumer<String> responseHandler; /**
* Sets the handler that will be invoked once the form got a response from the Bedrock client.
* This handler contains the raw data sent by the Bedrock client. See {@link
* #parseResponse(String)} if you want to turn the given data into something that's easier to
* handle.
*
* @param responseHandler the response handler
*/
void setResponseHandler(Consumer<String> responseHandler);
public Form(Type type) { /**
this.type = type; * Parses the method into something provided by the form implementation, which will make the
} * data given by the Bedrock client easier to handle.
*
* @param response the raw data given by the Bedrock client
* @return the data in an easy-to-handle class
*/
T parseResponse(String response);
public static <T extends Form> T fromJson(String json, Class<T> formClass) { /**
return GSON.fromJson(json, formClass); * Checks if the given data by the Bedrock client is saying that the client closed the form.
} *
* @param response the raw data given by the Bedrock client
public String getJsonData() { * @return true if the raw data implies that the Bedrock client closed the form
if (hardcodedJsonData != null) { */
return hardcodedJsonData; boolean isClosed(String response);
}
return GSON.toJson(this);
}
public abstract FormResponse parseResponse(String response);
@SuppressWarnings("unchecked")
public <T extends FormResponse> T parseResponseAs(String response) {
return (T) parseResponse(response);
}
public boolean isClosed(String response) {
return response == null || response.isEmpty() || response.equalsIgnoreCase("null");
}
@Getter
@RequiredArgsConstructor
public enum Type {
@SerializedName("form")
SIMPLE_FORM(SimpleForm.class),
@SerializedName("modal")
MODAL_FORM(ModalForm.class),
@SerializedName("custom_form")
CUSTOM_FORM(CustomForm.class);
private static final Type[] VALUES = values();
private final Class<? extends Form> typeClass;
public static Type getByOrdinal(int ordinal) {
return ordinal < VALUES.length ? VALUES[ordinal] : null;
}
}
public static abstract class Builder<T extends Builder<T, F>, F extends Form> {
protected String title = "";
protected BiFunction<String, String, String> translationHandler = null;
protected BiConsumer<F, String> biResponseHandler;
protected Consumer<String> responseHandler;
protected String locale;
public T title(String title) {
this.title = translate(title);
return self();
}
public T translator(BiFunction<String, String, String> translator, String locale) {
this.translationHandler = translator;
this.locale = locale;
return title(title);
}
public T translator(BiFunction<String, String, String> translator) {
return translator(translator, locale);
}
public T responseHandler(BiConsumer<F, String> responseHandler) {
biResponseHandler = responseHandler;
return self();
}
public T responseHandler(Consumer<String> responseHandler) {
this.responseHandler = responseHandler;
return self();
}
public abstract F build();
protected String translate(String text) {
if (translationHandler != null && text != null && !text.isEmpty()) {
return translationHandler.apply(text, locale);
}
return text;
}
@SuppressWarnings("unchecked")
protected T self() {
return (T) this;
}
}
} }

Datei anzeigen

@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
public interface FormBuilder<T extends FormBuilder<T, F>, F extends Form<?>> {
T title(String title);
T translator(BiFunction<String, String, String> translator, String locale);
T translator(BiFunction<String, String, String> translator);
T responseHandler(BiConsumer<F, String> responseHandler);
T responseHandler(Consumer<String> responseHandler);
F build();
}

Datei anzeigen

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form;
import com.google.gson.annotations.SerializedName;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.impl.util.FormImageImpl;
public interface FormImage {
static FormImage of(Type type, String data) {
return FormImageImpl.of(type, data);
}
static FormImage of(String type, String data) {
return FormImageImpl.of(type, data);
}
Type getType();
String getData();
@RequiredArgsConstructor
enum Type {
@SerializedName("path") PATH,
@SerializedName("url") URL;
private static final Type[] VALUES = values();
public static Type getByName(String name) {
String upper = name.toUpperCase();
for (Type value : VALUES) {
if (value.name().equals(upper)) {
return value;
}
}
return null;
}
}
}

Datei anzeigen

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.impl.CustomFormImpl;
import org.geysermc.common.form.impl.ModalFormImpl;
import org.geysermc.common.form.impl.SimpleFormImpl;
@Getter
@RequiredArgsConstructor
public enum FormType {
@SerializedName("form")
SIMPLE_FORM(SimpleFormImpl.class),
@SerializedName("modal")
MODAL_FORM(ModalFormImpl.class),
@SerializedName("custom_form")
CUSTOM_FORM(CustomFormImpl.class);
private static final FormType[] VALUES = values();
private final Class<? extends Form> typeClass;
public static FormType getByOrdinal(int ordinal) {
return ordinal < VALUES.length ? VALUES[ordinal] : null;
}
}

Datei anzeigen

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.geysermc.common.form.impl.FormImpl;
import org.geysermc.common.form.impl.util.FormAdaptor;
public final class Forms {
private static final Gson GSON =
new GsonBuilder()
.registerTypeAdapter(FormImpl.class, new FormAdaptor())
.create();
public static Gson getGson() {
return GSON;
}
public static <T extends Form<?>> T fromJson(String json, Class<T> formClass) {
return GSON.fromJson(json, formClass);
}
}

Datei anzeigen

@ -25,79 +25,23 @@
package org.geysermc.common.form; package org.geysermc.common.form;
import com.google.gson.annotations.JsonAdapter; import org.geysermc.common.form.impl.ModalFormImpl;
import lombok.Getter;
import org.geysermc.common.form.response.ModalFormResponse; import org.geysermc.common.form.response.ModalFormResponse;
import org.geysermc.common.form.util.FormAdaptor;
@Getter public interface ModalForm extends Form<ModalFormResponse> {
@JsonAdapter(FormAdaptor.class) static Builder builder() {
public class ModalForm extends Form { return new ModalFormImpl.Builder();
private final String title;
private final String content;
private final String button1;
private final String button2;
private ModalForm(String title, String content, String button1, String button2) {
super(Type.MODAL_FORM);
this.title = title;
this.content = content;
this.button1 = button1;
this.button2 = button2;
} }
public static Builder builder() { static ModalForm of(String title, String content, String button1, String button2) {
return new Builder(); return ModalFormImpl.of(title, content, button1, button2);
} }
public static ModalForm of(String title, String content, String button1, String button2) { interface Builder extends FormBuilder<Builder, ModalForm> {
return new ModalForm(title, content, button1, button2); Builder content(String content);
}
public ModalFormResponse parseResponse(String data) { Builder button1(String button1);
if (isClosed(data)) {
return ModalFormResponse.closed();
}
if ("true".equals(data)) { Builder button2(String button2);
return ModalFormResponse.of(0, button1);
} else if ("false".equals(data)) {
return ModalFormResponse.of(1, button2);
}
return ModalFormResponse.invalid();
}
public static final class Builder extends Form.Builder<Builder, ModalForm> {
private String content = "";
private String button1 = "";
private String button2 = "";
public Builder content(String content) {
this.content = translate(content);
return this;
}
public Builder button1(String button1) {
this.button1 = translate(button1);
return this;
}
public Builder button2(String button2) {
this.button2 = translate(button2);
return this;
}
@Override
public ModalForm build() {
ModalForm form = of(title, content, button1, button2);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
} }
} }

Datei anzeigen

@ -25,93 +25,37 @@
package org.geysermc.common.form; package org.geysermc.common.form;
import com.google.gson.annotations.JsonAdapter;
import lombok.Getter;
import org.geysermc.common.form.component.ButtonComponent; import org.geysermc.common.form.component.ButtonComponent;
import org.geysermc.common.form.impl.SimpleFormImpl;
import org.geysermc.common.form.response.SimpleFormResponse; import org.geysermc.common.form.response.SimpleFormResponse;
import org.geysermc.common.form.util.FormAdaptor;
import org.geysermc.common.form.util.FormImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@Getter /**
@JsonAdapter(FormAdaptor.class) *
public final class SimpleForm extends Form { */
private final String title; public interface SimpleForm extends Form<SimpleFormResponse> {
private final String content; static Builder builder() {
private final List<ButtonComponent> buttons; return new SimpleFormImpl.Builder();
private SimpleForm(String title, String content, List<ButtonComponent> buttons) {
super(Type.SIMPLE_FORM);
this.title = title;
this.content = content;
this.buttons = Collections.unmodifiableList(buttons);
} }
public static Builder builder() { static SimpleForm of(String title, String content, List<ButtonComponent> buttons) {
return new Builder(); return SimpleFormImpl.of(title, content, buttons);
} }
public static SimpleForm of(String title, String content, List<ButtonComponent> buttons) { String getTitle();
return new SimpleForm(title, content, buttons);
}
public SimpleFormResponse parseResponse(String data) { String getContent();
if (isClosed(data)) {
return SimpleFormResponse.closed();
}
int buttonId; List<ButtonComponent> getButtons();
try {
buttonId = Integer.parseInt(data);
} catch (Exception exception) {
return SimpleFormResponse.invalid();
}
if (buttonId >= buttons.size()) { interface Builder extends FormBuilder<Builder, SimpleForm> {
return SimpleFormResponse.invalid(); Builder content(String content);
}
return SimpleFormResponse.of(buttonId, buttons.get(buttonId)); Builder button(String text, FormImage.Type type, String data);
}
public static final class Builder extends Form.Builder<Builder, SimpleForm> { Builder button(String text, FormImage image);
private final List<ButtonComponent> buttons = new ArrayList<>();
private String content = "";
public Builder content(String content) { Builder button(String text);
this.content = translate(content);
return this;
}
public Builder button(String text, FormImage.Type type, String data) {
buttons.add(ButtonComponent.of(translate(text), type, data));
return this;
}
public Builder button(String text, FormImage image) {
buttons.add(ButtonComponent.of(translate(text), image));
return this;
}
public Builder button(String text) {
buttons.add(ButtonComponent.of(translate(text)));
return this;
}
@Override
public SimpleForm build() {
SimpleForm form = of(title, content, buttons);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
} }
} }

Datei anzeigen

@ -25,26 +25,23 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import lombok.AccessLevel; import org.geysermc.common.form.FormImage;
import lombok.Getter; import org.geysermc.common.form.impl.component.ButtonComponentImpl;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.util.FormImage;
@Getter public interface ButtonComponent {
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) static ButtonComponent of(String text, FormImage image) {
public final class ButtonComponent { return ButtonComponentImpl.of(text, image);
private final String text;
private final FormImage image;
public static ButtonComponent of(String text, FormImage image) {
return new ButtonComponent(text, image);
} }
public static ButtonComponent of(String text, FormImage.Type type, String data) { static ButtonComponent of(String text, FormImage.Type type, String data) {
return of(text, FormImage.of(type, data)); return ButtonComponentImpl.of(text, type, data);
} }
public static ButtonComponent of(String text) { static ButtonComponent of(String text) {
return of(text, null); return of(text, null);
} }
String getText();
FormImage getImage();
} }

Datei anzeigen

@ -25,53 +25,8 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; public interface Component {
import lombok.Getter; ComponentType getType();
import lombok.RequiredArgsConstructor;
import java.util.Objects; String getText();
@Getter
public abstract class Component {
private final Type type;
private final String text;
Component(Type type, String text) {
Objects.requireNonNull(type, "Type cannot be null");
Objects.requireNonNull(text, "Text cannot be null");
this.type = type;
this.text = text;
}
@Getter
@RequiredArgsConstructor
public enum Type {
@SerializedName("dropdown")
DROPDOWN(DropdownComponent.class),
@SerializedName("input")
INPUT(InputComponent.class),
@SerializedName("label")
LABEL(LabelComponent.class),
@SerializedName("slider")
SLIDER(SliderComponent.class),
@SerializedName("step_slider")
STEP_SLIDER(StepSliderComponent.class),
@SerializedName("toggle")
TOGGLE(ToggleComponent.class);
private static final Type[] VALUES = values();
private final String name = name().toLowerCase();
private final Class<? extends Component> componentClass;
public static Type getByName(String name) {
for (Type type : VALUES) {
if (type.name.equals(name)) {
return type;
}
}
return null;
}
}
} }

Datei anzeigen

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum ComponentType {
@SerializedName("dropdown")
DROPDOWN(DropdownComponent.class),
@SerializedName("input")
INPUT(InputComponent.class),
@SerializedName("label")
LABEL(LabelComponent.class),
@SerializedName("slider")
SLIDER(SliderComponent.class),
@SerializedName("step_slider")
STEP_SLIDER(StepSliderComponent.class),
@SerializedName("toggle")
TOGGLE(ToggleComponent.class);
private static final ComponentType[] VALUES = values();
private final String name = name().toLowerCase();
private final Class<? extends Component> componentClass;
public static ComponentType getByName(String name) {
for (ComponentType type : VALUES) {
if (type.name.equals(name)) {
return type;
}
}
return null;
}
}

Datei anzeigen

@ -25,78 +25,39 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; import org.geysermc.common.form.impl.component.DropdownComponentImpl;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
@Getter public interface DropdownComponent extends Component {
public class DropdownComponent extends Component { static DropdownComponent of(String text, List<String> options, int defaultOption) {
private final List<String> options; return DropdownComponentImpl.of(text, options, defaultOption);
@SerializedName("default")
private final int defaultOption;
private DropdownComponent(String text, List<String> options, int defaultOption) {
super(Type.DROPDOWN, text);
this.options = Collections.unmodifiableList(options);
this.defaultOption = defaultOption;
} }
public static DropdownComponent of(String text, List<String> options, int defaultOption) { static Builder builder() {
if (defaultOption == -1 || defaultOption >= options.size()) { return new DropdownComponentImpl.Builder();
defaultOption = 0;
}
return new DropdownComponent(text, options, defaultOption);
} }
public static Builder builder() { static Builder builder(String text) {
return new Builder();
}
public static Builder builder(String text) {
return builder().text(text); return builder().text(text);
} }
public static class Builder { List<String> getOptions();
private final List<String> options = new ArrayList<>();
private String text;
private int defaultOption = 0;
public Builder text(String text) { int getDefaultOption();
this.text = text;
return this;
}
public Builder option(String option, boolean isDefault) { interface Builder {
options.add(option); Builder text(String text);
if (isDefault) {
defaultOption = options.size() - 1;
}
return this;
}
public Builder option(String option) { Builder option(String option, boolean isDefault);
return option(option, false);
}
public Builder defaultOption(int defaultOption) { Builder option(String option);
this.defaultOption = defaultOption;
return this;
}
public DropdownComponent build() { Builder defaultOption(int defaultOption);
return of(text, options, defaultOption);
}
public DropdownComponent translateAndBuild(Function<String, String> translator) { DropdownComponent build();
for (int i = 0; i < options.size(); i++) {
options.set(i, translator.apply(options.get(i)));
}
return of(translator.apply(text), options, defaultOption); DropdownComponent translateAndBuild(Function<String, String> translator);
}
} }
} }

Datei anzeigen

@ -25,30 +25,22 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; import org.geysermc.common.form.impl.component.InputComponentImpl;
import lombok.Getter;
@Getter public interface InputComponent extends Component {
public class InputComponent extends Component { static InputComponent of(String text, String placeholder, String defaultText) {
private final String placeholder; return InputComponentImpl.of(text, placeholder, defaultText);
@SerializedName("default")
private final String defaultText;
private InputComponent(String text, String placeholder, String defaultText) {
super(Type.INPUT, text);
this.placeholder = placeholder;
this.defaultText = defaultText;
} }
public static InputComponent of(String text, String placeholder, String defaultText) { static InputComponent of(String text, String placeholder) {
return new InputComponent(text, placeholder, defaultText); return InputComponentImpl.of(text, placeholder, "");
} }
public static InputComponent of(String text, String placeholder) { static InputComponent of(String text) {
return new InputComponent(text, placeholder, ""); return InputComponentImpl.of(text, "", "");
} }
public static InputComponent of(String text) { String getPlaceholder();
return new InputComponent(text, "", "");
} String getDefaultText();
} }

Datei anzeigen

@ -25,15 +25,10 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import lombok.Getter; import org.geysermc.common.form.impl.component.LabelComponentImpl;
@Getter public interface LabelComponent extends Component {
public class LabelComponent extends Component { static LabelComponent of(String text) {
private LabelComponent(String text) { return LabelComponentImpl.of(text);
super(Type.LABEL, text);
}
public static LabelComponent of(String text) {
return new LabelComponent(text);
} }
} }

Datei anzeigen

@ -25,49 +25,30 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; import org.geysermc.common.form.impl.component.SliderComponentImpl;
import lombok.Getter;
@Getter public interface SliderComponent extends Component {
public final class SliderComponent extends Component { static SliderComponent of(String text, float min, float max, int step, float defaultValue) {
private final float min; return SliderComponentImpl.of(text, min, max, step, defaultValue);
private final float max;
private final int step;
@SerializedName("default")
private final float defaultValue;
private SliderComponent(String text, float min, float max, int step, float defaultValue) {
super(Type.SLIDER, text);
this.min = min;
this.max = max;
this.step = step;
this.defaultValue = defaultValue;
} }
public static SliderComponent of(String text, float min, float max, int step, float defaultValue) { static SliderComponent of(String text, float min, float max, int step) {
min = Math.max(min, 0f); return SliderComponentImpl.of(text, min, max, step);
max = Math.max(max, min);
if (step < 1) {
step = 1;
}
if (defaultValue == -1f) {
defaultValue = (int) Math.floor(min + max / 2D);
}
return new SliderComponent(text, min, max, step, defaultValue);
} }
public static SliderComponent of(String text, float min, float max, int step) { static SliderComponent of(String text, float min, float max, float defaultValue) {
return of(text, min, max, step, -1); return SliderComponentImpl.of(text, min, max, defaultValue);
} }
public static SliderComponent of(String text, float min, float max, float defaultValue) { static SliderComponent of(String text, float min, float max) {
return of(text, min, max, -1, defaultValue); return SliderComponentImpl.of(text, min, max);
} }
public static SliderComponent of(String text, float min, float max) { float getMin();
return of(text, min, max, -1, -1);
} float getMax();
int getStep();
float getDefaultValue();
} }

Datei anzeigen

@ -25,92 +25,47 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; import org.geysermc.common.form.impl.component.StepSliderComponentImpl;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
@Getter public interface StepSliderComponent extends Component {
public final class StepSliderComponent extends Component { static StepSliderComponent of(String text, List<String> steps, int defaultStep) {
private final List<String> steps; return StepSliderComponentImpl.of(text, steps, defaultStep);
@SerializedName("default")
private final int defaultStep;
private StepSliderComponent(String text, List<String> steps, int defaultStep) {
super(Type.STEP_SLIDER, text);
this.steps = Collections.unmodifiableList(steps);
this.defaultStep = defaultStep;
} }
public static StepSliderComponent of(String text, List<String> steps, int defaultStep) { static StepSliderComponent of(String text, int defaultStep, String... steps) {
if (text == null) { return StepSliderComponentImpl.of(text, defaultStep, steps);
text = "";
}
if (defaultStep >= steps.size() || defaultStep == -1) {
defaultStep = 0;
}
return new StepSliderComponent(text, steps, defaultStep);
} }
public static StepSliderComponent of(String text, int defaultStep, String... steps) { static StepSliderComponent of(String text, String... steps) {
return of(text, Arrays.asList(steps), defaultStep); return StepSliderComponentImpl.of(text, steps);
} }
public static StepSliderComponent of(String text, String... steps) { static Builder builder() {
return of(text, 0, steps); return new StepSliderComponentImpl.Builder();
} }
public static Builder builder() { static Builder builder(String text) {
return new Builder();
}
public static Builder builder(String text) {
return builder().text(text); return builder().text(text);
} }
public static final class Builder { List<String> getSteps();
private final List<String> steps = new ArrayList<>();
private String text;
private int defaultStep;
public Builder text(String text) { int getDefaultStep();
this.text = text;
return this;
}
public Builder step(String step, boolean defaultStep) { interface Builder {
steps.add(step); Builder text(String text);
if (defaultStep) {
this.defaultStep = steps.size() - 1;
}
return this;
}
public Builder step(String step) { Builder step(String step, boolean defaultStep);
return step(step, false);
}
public Builder defaultStep(int defaultStep) { Builder step(String step);
this.defaultStep = defaultStep;
return this;
}
public StepSliderComponent build() { Builder defaultStep(int defaultStep);
return of(text, steps, defaultStep);
}
public StepSliderComponent translateAndBuild(Function<String, String> translator) { StepSliderComponent build();
for (int i = 0; i < steps.size(); i++) {
steps.set(i, translator.apply(steps.get(i)));
}
return of(translator.apply(text), steps, defaultStep); StepSliderComponent translateAndBuild(Function<String, String> translator);
}
} }
} }

Datei anzeigen

@ -25,24 +25,16 @@
package org.geysermc.common.form.component; package org.geysermc.common.form.component;
import com.google.gson.annotations.SerializedName; import org.geysermc.common.form.impl.component.ToggleComponentImpl;
import lombok.Getter;
@Getter public interface ToggleComponent extends Component {
public class ToggleComponent extends Component { static ToggleComponent of(String text, boolean defaultValue) {
@SerializedName("default") return ToggleComponentImpl.of(text, defaultValue);
private final boolean defaultValue;
private ToggleComponent(String text, boolean defaultValue) {
super(Type.TOGGLE, text);
this.defaultValue = defaultValue;
} }
public static ToggleComponent of(String text, boolean defaultValue) { static ToggleComponent of(String text) {
return new ToggleComponent(text, defaultValue); return ToggleComponentImpl.of(text);
} }
public static ToggleComponent of(String text) { boolean getDefaultValue();
return of(text, false);
}
} }

Datei anzeigen

@ -0,0 +1,179 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl;
import com.google.gson.annotations.JsonAdapter;
import lombok.Getter;
import org.geysermc.common.form.CustomForm;
import org.geysermc.common.form.FormImage;
import org.geysermc.common.form.FormType;
import org.geysermc.common.form.component.*;
import org.geysermc.common.form.impl.response.CustomFormResponseImpl;
import org.geysermc.common.form.impl.util.FormAdaptor;
import org.geysermc.common.form.impl.util.FormImageImpl;
import org.geysermc.common.form.response.CustomFormResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Getter
@JsonAdapter(FormAdaptor.class)
public final class CustomFormImpl extends FormImpl<CustomFormResponse> implements CustomForm {
private final String title;
private final FormImage icon;
private final List<Component> content;
private CustomFormImpl(String title, FormImage icon, List<Component> content) {
super(FormType.CUSTOM_FORM);
this.title = title;
this.icon = icon;
this.content = Collections.unmodifiableList(content);
}
public static CustomFormImpl of(String title, FormImage icon, List<Component> content) {
return new CustomFormImpl(title, icon, content);
}
public CustomFormResponseImpl parseResponse(String data) {
if (isClosed(data)) {
return CustomFormResponseImpl.closed();
}
return CustomFormResponseImpl.of(this, data);
}
public static final class Builder extends FormImpl.Builder<CustomForm.Builder, CustomForm>
implements CustomForm.Builder {
private final List<Component> components = new ArrayList<>();
private FormImage icon;
public Builder icon(FormImage.Type type, String data) {
icon = FormImageImpl.of(type, data);
return this;
}
public Builder iconPath(String path) {
return icon(FormImage.Type.PATH, path);
}
public Builder iconUrl(String url) {
return icon(FormImage.Type.URL, url);
}
public Builder component(Component component) {
components.add(component);
return this;
}
public Builder dropdown(DropdownComponent.Builder dropdownBuilder) {
return component(dropdownBuilder.translateAndBuild(this::translate));
}
public Builder dropdown(String text, int defaultOption, String... options) {
List<String> optionsList = new ArrayList<>();
for (String option : options) {
optionsList.add(translate(option));
}
return component(DropdownComponent.of(translate(text), optionsList, defaultOption));
}
public Builder dropdown(String text, String... options) {
return dropdown(text, -1, options);
}
public Builder input(String text, String placeholder, String defaultText) {
return component(InputComponent.of(
translate(text), translate(placeholder), translate(defaultText)
));
}
public Builder input(String text, String placeholder) {
return component(InputComponent.of(translate(text), translate(placeholder)));
}
public Builder input(String text) {
return component(InputComponent.of(translate(text)));
}
public Builder label(String text) {
return component(LabelComponent.of(translate(text)));
}
public Builder slider(String text, float min, float max, int step, float defaultValue) {
return component(SliderComponent.of(text, min, max, step, defaultValue));
}
public Builder slider(String text, float min, float max, int step) {
return slider(text, min, max, step, -1);
}
public Builder slider(String text, float min, float max, float defaultValue) {
return slider(text, min, max, -1, defaultValue);
}
public Builder slider(String text, float min, float max) {
return slider(text, min, max, -1, -1);
}
public Builder stepSlider(StepSliderComponent.Builder stepSliderBuilder) {
return component(stepSliderBuilder.translateAndBuild(this::translate));
}
public Builder stepSlider(String text, int defaultStep, String... steps) {
List<String> stepsList = new ArrayList<>();
for (String option : steps) {
stepsList.add(translate(option));
}
return component(StepSliderComponent.of(translate(text), stepsList, defaultStep));
}
public Builder stepSlider(String text, String... steps) {
return stepSlider(text, -1, steps);
}
public Builder toggle(String text, boolean defaultValue) {
return component(ToggleComponent.of(translate(text), defaultValue));
}
public Builder toggle(String text) {
return component(ToggleComponent.of(translate(text)));
}
@Override
public CustomFormImpl build() {
CustomFormImpl form = of(title, icon, components);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
}
}

Datei anzeigen

@ -0,0 +1,121 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl;
import com.google.gson.Gson;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.common.form.Form;
import org.geysermc.common.form.FormBuilder;
import org.geysermc.common.form.FormType;
import org.geysermc.common.form.Forms;
import org.geysermc.common.form.response.FormResponse;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@Getter
public abstract class FormImpl<T extends FormResponse> implements Form<T> {
protected static final Gson GSON = Forms.getGson();
private final FormType type;
protected String hardcodedJsonData = null;
@Setter protected Consumer<String> responseHandler;
public FormImpl(FormType type) {
this.type = type;
}
@Override
public String getJsonData() {
if (hardcodedJsonData != null) {
return hardcodedJsonData;
}
return GSON.toJson(this);
}
@Override
public boolean isClosed(String response) {
return response == null || response.isEmpty() || response.equalsIgnoreCase("null");
}
public static abstract class Builder<T extends FormBuilder<T, F>, F extends Form<?>>
implements FormBuilder<T, F> {
protected String title = "";
protected BiFunction<String, String, String> translationHandler = null;
protected BiConsumer<F, String> biResponseHandler;
protected Consumer<String> responseHandler;
protected String locale;
@Override
public T title(String title) {
this.title = translate(title);
return self();
}
@Override
public T translator(BiFunction<String, String, String> translator, String locale) {
this.translationHandler = translator;
this.locale = locale;
return title(title);
}
@Override
public T translator(BiFunction<String, String, String> translator) {
return translator(translator, locale);
}
@Override
public T responseHandler(BiConsumer<F, String> responseHandler) {
biResponseHandler = responseHandler;
return self();
}
@Override
public T responseHandler(Consumer<String> responseHandler) {
this.responseHandler = responseHandler;
return self();
}
@Override
public abstract F build();
protected String translate(String text) {
if (translationHandler != null && text != null && !text.isEmpty()) {
return translationHandler.apply(text, locale);
}
return text;
}
@SuppressWarnings("unchecked")
protected T self() {
return (T) this;
}
}
}

Datei anzeigen

@ -0,0 +1,105 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl;
import com.google.gson.annotations.JsonAdapter;
import lombok.Getter;
import org.geysermc.common.form.FormType;
import org.geysermc.common.form.ModalForm;
import org.geysermc.common.form.impl.response.ModalFormResponseImpl;
import org.geysermc.common.form.impl.util.FormAdaptor;
import org.geysermc.common.form.response.ModalFormResponse;
@Getter
@JsonAdapter(FormAdaptor.class)
public final class ModalFormImpl extends FormImpl<ModalFormResponse> implements ModalForm {
private final String title;
private final String content;
private final String button1;
private final String button2;
private ModalFormImpl(String title, String content, String button1, String button2) {
super(FormType.MODAL_FORM);
this.title = title;
this.content = content;
this.button1 = button1;
this.button2 = button2;
}
public static ModalFormImpl of(String title, String content, String button1, String button2) {
return new ModalFormImpl(title, content, button1, button2);
}
public ModalFormResponse parseResponse(String data) {
if (isClosed(data)) {
return ModalFormResponseImpl.closed();
}
data = data.trim();
if ("true".equals(data)) {
return ModalFormResponseImpl.of(0, button1);
} else if ("false".equals(data)) {
return ModalFormResponseImpl.of(1, button2);
}
return ModalFormResponseImpl.invalid();
}
public static final class Builder extends FormImpl.Builder<ModalForm.Builder, ModalForm>
implements ModalForm.Builder {
private String content = "";
private String button1 = "";
private String button2 = "";
public Builder content(String content) {
this.content = translate(content);
return this;
}
public Builder button1(String button1) {
this.button1 = translate(button1);
return this;
}
public Builder button2(String button2) {
this.button2 = translate(button2);
return this;
}
@Override
public ModalForm build() {
ModalFormImpl form = of(title, content, button1, button2);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
}
}

Datei anzeigen

@ -0,0 +1,120 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl;
import com.google.gson.annotations.JsonAdapter;
import lombok.Getter;
import org.geysermc.common.form.FormImage;
import org.geysermc.common.form.FormType;
import org.geysermc.common.form.SimpleForm;
import org.geysermc.common.form.component.ButtonComponent;
import org.geysermc.common.form.impl.component.ButtonComponentImpl;
import org.geysermc.common.form.impl.response.SimpleFormResponseImpl;
import org.geysermc.common.form.impl.util.FormAdaptor;
import org.geysermc.common.form.response.SimpleFormResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Getter
@JsonAdapter(FormAdaptor.class)
public final class SimpleFormImpl extends FormImpl<SimpleFormResponse> implements SimpleForm {
private final String title;
private final String content;
private final List<ButtonComponent> buttons;
private SimpleFormImpl(String title, String content, List<ButtonComponent> buttons) {
super(FormType.SIMPLE_FORM);
this.title = title;
this.content = content;
this.buttons = Collections.unmodifiableList(buttons);
}
public static SimpleFormImpl of(String title, String content, List<ButtonComponent> buttons) {
return new SimpleFormImpl(title, content, buttons);
}
public SimpleFormResponse parseResponse(String data) {
if (isClosed(data)) {
return SimpleFormResponseImpl.closed();
}
data = data.trim();
int buttonId;
try {
buttonId = Integer.parseInt(data);
} catch (Exception exception) {
return SimpleFormResponseImpl.invalid();
}
if (buttonId >= buttons.size()) {
return SimpleFormResponseImpl.invalid();
}
return SimpleFormResponseImpl.of(buttonId, buttons.get(buttonId));
}
public static final class Builder extends FormImpl.Builder<SimpleForm.Builder, SimpleForm>
implements SimpleForm.Builder {
private final List<ButtonComponent> buttons = new ArrayList<>();
private String content = "";
public Builder content(String content) {
this.content = translate(content);
return this;
}
public Builder button(String text, FormImage.Type type, String data) {
buttons.add(ButtonComponentImpl.of(translate(text), type, data));
return this;
}
public Builder button(String text, FormImage image) {
buttons.add(ButtonComponentImpl.of(translate(text), image));
return this;
}
public Builder button(String text) {
buttons.add(ButtonComponentImpl.of(translate(text)));
return this;
}
@Override
public SimpleForm build() {
SimpleFormImpl form = of(title, content, buttons);
if (biResponseHandler != null) {
form.setResponseHandler(response -> biResponseHandler.accept(form, response));
return form;
}
form.setResponseHandler(responseHandler);
return form;
}
}
}

Datei anzeigen

@ -0,0 +1,52 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.FormImage;
import org.geysermc.common.form.component.ButtonComponent;
import org.geysermc.common.form.impl.util.FormImageImpl;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ButtonComponentImpl implements ButtonComponent {
private final String text;
private final FormImageImpl image;
public static ButtonComponentImpl of(String text, FormImage image) {
return new ButtonComponentImpl(text, (FormImageImpl) image);
}
public static ButtonComponentImpl of(String text, FormImage.Type type, String data) {
return of(text, FormImageImpl.of(type, data));
}
public static ButtonComponentImpl of(String text) {
return of(text, null);
}
}

Datei anzeigen

@ -0,0 +1,45 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import java.util.Objects;
@Getter
public abstract class Component {
private final ComponentType type;
private final String text;
Component(ComponentType type, String text) {
Objects.requireNonNull(type, "Type cannot be null");
Objects.requireNonNull(text, "Text cannot be null");
this.type = type;
this.text = text;
}
}

Datei anzeigen

@ -0,0 +1,102 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.DropdownComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@Getter
public final class DropdownComponentImpl extends Component implements DropdownComponent {
private final List<String> options;
@SerializedName("default")
private final int defaultOption;
private DropdownComponentImpl(String text, List<String> options, int defaultOption) {
super(ComponentType.DROPDOWN, text);
this.options = Collections.unmodifiableList(options);
this.defaultOption = defaultOption;
}
public static DropdownComponentImpl of(String text, List<String> options, int defaultOption) {
if (defaultOption == -1 || defaultOption >= options.size()) {
defaultOption = 0;
}
return new DropdownComponentImpl(text, options, defaultOption);
}
public static class Builder implements DropdownComponent.Builder {
private final List<String> options = new ArrayList<>();
private String text;
private int defaultOption = 0;
@Override
public Builder text(String text) {
this.text = text;
return this;
}
@Override
public Builder option(String option, boolean isDefault) {
options.add(option);
if (isDefault) {
defaultOption = options.size() - 1;
}
return this;
}
@Override
public Builder option(String option) {
return option(option, false);
}
@Override
public Builder defaultOption(int defaultOption) {
this.defaultOption = defaultOption;
return this;
}
@Override
public DropdownComponentImpl build() {
return of(text, options, defaultOption);
}
@Override
public DropdownComponentImpl translateAndBuild(Function<String, String> translator) {
for (int i = 0; i < options.size(); i++) {
options.set(i, translator.apply(options.get(i)));
}
return of(translator.apply(text), options, defaultOption);
}
}
}

Datei anzeigen

@ -0,0 +1,56 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.InputComponent;
@Getter
public final class InputComponentImpl extends Component implements InputComponent {
private final String placeholder;
@SerializedName("default")
private final String defaultText;
private InputComponentImpl(String text, String placeholder, String defaultText) {
super(ComponentType.INPUT, text);
this.placeholder = placeholder;
this.defaultText = defaultText;
}
public static InputComponentImpl of(String text, String placeholder, String defaultText) {
return new InputComponentImpl(text, placeholder, defaultText);
}
public static InputComponentImpl of(String text, String placeholder) {
return new InputComponentImpl(text, placeholder, "");
}
public static InputComponentImpl of(String text) {
return new InputComponentImpl(text, "", "");
}
}

Datei anzeigen

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.LabelComponent;
@Getter
public final class LabelComponentImpl extends Component implements LabelComponent {
private LabelComponentImpl(String text) {
super(ComponentType.LABEL, text);
}
public static LabelComponentImpl of(String text) {
return new LabelComponentImpl(text);
}
}

Datei anzeigen

@ -0,0 +1,76 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.SliderComponent;
@Getter
public final class SliderComponentImpl extends Component implements SliderComponent {
private final float min;
private final float max;
private final int step;
@SerializedName("default")
private final float defaultValue;
private SliderComponentImpl(String text, float min, float max, int step, float defaultValue) {
super(ComponentType.SLIDER, text);
this.min = min;
this.max = max;
this.step = step;
this.defaultValue = defaultValue;
}
public static SliderComponentImpl of(String text, float min, float max, int step,
float defaultValue) {
min = Math.max(min, 0f);
max = Math.max(max, min);
if (step < 1) {
step = 1;
}
if (defaultValue == -1f) {
defaultValue = (int) Math.floor(min + max / 2D);
}
return new SliderComponentImpl(text, min, max, step, defaultValue);
}
public static SliderComponentImpl of(String text, float min, float max, int step) {
return of(text, min, max, step, -1);
}
public static SliderComponentImpl of(String text, float min, float max, float defaultValue) {
return of(text, min, max, -1, defaultValue);
}
public static SliderComponentImpl of(String text, float min, float max) {
return of(text, min, max, -1, -1);
}
}

Datei anzeigen

@ -0,0 +1,118 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import com.google.gson.annotations.SerializedName;
import lombok.Getter;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.StepSliderComponent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@Getter
public final class StepSliderComponentImpl extends Component implements StepSliderComponent {
private final List<String> steps;
@SerializedName("default")
private final int defaultStep;
private StepSliderComponentImpl(String text, List<String> steps, int defaultStep) {
super(ComponentType.STEP_SLIDER, text);
this.steps = Collections.unmodifiableList(steps);
this.defaultStep = defaultStep;
}
public static StepSliderComponentImpl of(String text, List<String> steps, int defaultStep) {
if (text == null) {
text = "";
}
if (defaultStep >= steps.size() || defaultStep == -1) {
defaultStep = 0;
}
return new StepSliderComponentImpl(text, steps, defaultStep);
}
public static StepSliderComponentImpl of(String text, int defaultStep, String... steps) {
return of(text, Arrays.asList(steps), defaultStep);
}
public static StepSliderComponentImpl of(String text, String... steps) {
return of(text, 0, steps);
}
public static Builder builder() {
return new Builder();
}
public static Builder builder(String text) {
return builder().text(text);
}
public static final class Builder implements StepSliderComponent.Builder {
private final List<String> steps = new ArrayList<>();
private String text;
private int defaultStep;
public Builder text(String text) {
this.text = text;
return this;
}
public Builder step(String step, boolean defaultStep) {
steps.add(step);
if (defaultStep) {
this.defaultStep = steps.size() - 1;
}
return this;
}
public Builder step(String step) {
return step(step, false);
}
public Builder defaultStep(int defaultStep) {
this.defaultStep = defaultStep;
return this;
}
public StepSliderComponentImpl build() {
return of(text, steps, defaultStep);
}
public StepSliderComponentImpl translateAndBuild(Function<String, String> translator) {
for (int i = 0; i < steps.size(); i++) {
steps.set(i, translator.apply(steps.get(i)));
}
return of(translator.apply(text), steps, defaultStep);
}
}
}

Datei anzeigen

@ -0,0 +1,52 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.component;
import com.google.gson.annotations.SerializedName;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.component.ToggleComponent;
public final class ToggleComponentImpl extends Component implements ToggleComponent {
@SerializedName("default")
private final boolean defaultValue;
private ToggleComponentImpl(String text, boolean defaultValue) {
super(ComponentType.TOGGLE, text);
this.defaultValue = defaultValue;
}
public static ToggleComponentImpl of(String text, boolean defaultValue) {
return new ToggleComponentImpl(text, defaultValue);
}
public static ToggleComponentImpl of(String text) {
return of(text, false);
}
public boolean getDefaultValue() {
return defaultValue;
}
}

Datei anzeigen

@ -0,0 +1,207 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.response;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonPrimitive;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.geysermc.common.form.component.Component;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.impl.CustomFormImpl;
import org.geysermc.common.form.response.CustomFormResponse;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
public final class CustomFormResponseImpl implements CustomFormResponse {
private static final Gson GSON = new Gson();
private static final CustomFormResponseImpl CLOSED =
new CustomFormResponseImpl(true, false, null, null);
private static final CustomFormResponseImpl INVALID =
new CustomFormResponseImpl(false, true, null, null);
private final boolean closed;
private final boolean invalid;
private final JsonArray responses;
private final List<ComponentType> componentTypes;
private int index = -1;
public static CustomFormResponseImpl closed() {
return CLOSED;
}
public static CustomFormResponseImpl invalid() {
return INVALID;
}
public static CustomFormResponseImpl of(CustomFormImpl form, String responseData) {
JsonArray responses = GSON.fromJson(responseData, JsonArray.class);
List<ComponentType> types = new ArrayList<>();
for (Component component : form.getContent()) {
types.add(component.getType());
}
return of(types, responses);
}
public static CustomFormResponseImpl of(List<ComponentType> componentTypes,
JsonArray responses) {
if (componentTypes.size() != responses.size()) {
return invalid();
}
return new CustomFormResponseImpl(false, false, responses,
Collections.unmodifiableList(componentTypes));
}
@Override
@SuppressWarnings("unchecked")
public <T> T next(boolean includeLabels) {
if (!hasNext()) {
return null;
}
while (++index < responses.size()) {
ComponentType type = componentTypes.get(index);
if (type == ComponentType.LABEL && !includeLabels) {
continue;
}
return (T) getDataFromType(type, index);
}
return null; // we don't have anything to check anymore
}
@Override
public <T> T next() {
return next(false);
}
@Override
public void skip(int amount) {
index += amount;
}
@Override
public void skip() {
skip(1);
}
@Override
public void index(int index) {
this.index = index;
}
@Override
public boolean hasNext() {
return responses.size() > index + 1;
}
@Override
public JsonPrimitive get(int index) {
try {
return responses.get(index).getAsJsonPrimitive();
} catch (IllegalStateException exception) {
wrongType(index, "a primitive");
return null;
}
}
@Override
public int getDropdown(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "dropdown");
}
return primitive.getAsInt();
}
@Override
public String getInput(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isString()) {
wrongType(index, "input");
}
return primitive.getAsString();
}
@Override
public float getSlider(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "slider");
}
return primitive.getAsFloat();
}
@Override
public int getStepSlide(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "step slider");
}
return primitive.getAsInt();
}
@Override
public boolean getToggle(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isBoolean()) {
wrongType(index, "toggle");
}
return primitive.getAsBoolean();
}
private Object getDataFromType(ComponentType type, int index) {
switch (type) {
case DROPDOWN:
return getDropdown(index);
case INPUT:
return getInput(index);
case SLIDER:
return getSlider(index);
case STEP_SLIDER:
return getStepSlide(index);
case TOGGLE:
return getToggle(index);
default:
return null; // label e.g. is always null
}
}
private void wrongType(int index, String expected) {
throw new IllegalStateException(String.format(
"Expected %s on %s, got %s",
expected, index, responses.get(index).toString()));
}
}

Datei anzeigen

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.response;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.response.FormResponse;
import org.geysermc.common.form.response.ModalFormResponse;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ModalFormResponseImpl implements ModalFormResponse {
private static final ModalFormResponseImpl CLOSED =
new ModalFormResponseImpl(true, false, -1, null);
private static final ModalFormResponseImpl INVALID =
new ModalFormResponseImpl(false, true, -1, null);
private final boolean closed;
private final boolean invalid;
private final int clickedButtonId;
private final String clickedButtonText;
public static ModalFormResponseImpl closed() {
return CLOSED;
}
public static ModalFormResponseImpl invalid() {
return INVALID;
}
public static ModalFormResponseImpl of(int clickedButtonId, String clickedButtonText) {
return new ModalFormResponseImpl(false, false, clickedButtonId, clickedButtonText);
}
public boolean getResult() {
return clickedButtonId == 0;
}
}

Datei anzeigen

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.common.form.impl.response;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.component.ButtonComponent;
import org.geysermc.common.form.response.SimpleFormResponse;
@Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class SimpleFormResponseImpl implements SimpleFormResponse {
private static final SimpleFormResponseImpl CLOSED =
new SimpleFormResponseImpl(true, false, -1, null);
private static final SimpleFormResponseImpl INVALID =
new SimpleFormResponseImpl(false, true, -1, null);
private final boolean closed;
private final boolean invalid;
private final int clickedButtonId;
private final ButtonComponent clickedButton;
public static SimpleFormResponseImpl closed() {
return CLOSED;
}
public static SimpleFormResponseImpl invalid() {
return INVALID;
}
public static SimpleFormResponseImpl of(int clickedButtonId, ButtonComponent clickedButton) {
return new SimpleFormResponseImpl(false, false, clickedButtonId, clickedButton);
}
public String getClickedButtonText() {
return clickedButton.getText();
}
}

Datei anzeigen

@ -23,28 +23,31 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.common.form.util; package org.geysermc.common.form.impl.util;
import com.google.gson.*; import com.google.gson.*;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import org.geysermc.common.form.CustomForm; import org.geysermc.common.form.FormImage;
import org.geysermc.common.form.Form;
import org.geysermc.common.form.ModalForm;
import org.geysermc.common.form.SimpleForm;
import org.geysermc.common.form.component.ButtonComponent; import org.geysermc.common.form.component.ButtonComponent;
import org.geysermc.common.form.component.Component; import org.geysermc.common.form.component.Component;
import org.geysermc.common.form.component.ComponentType;
import org.geysermc.common.form.impl.CustomFormImpl;
import org.geysermc.common.form.impl.FormImpl;
import org.geysermc.common.form.impl.ModalFormImpl;
import org.geysermc.common.form.impl.SimpleFormImpl;
import org.geysermc.common.form.impl.component.ButtonComponentImpl;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class FormAdaptor implements JsonDeserializer<Form>, JsonSerializer<Form> { public final class FormAdaptor implements JsonDeserializer<FormImpl<?>>, JsonSerializer<FormImpl<?>> {
private static final Type LIST_BUTTON_TYPE = private static final Type LIST_BUTTON_TYPE =
new TypeToken<List<ButtonComponent>>() {}.getType(); new TypeToken<List<ButtonComponentImpl>>() {}.getType();
@Override @Override
public Form deserialize(JsonElement jsonElement, Type typeOfT, public FormImpl<?> deserialize(JsonElement jsonElement, Type typeOfT,
JsonDeserializationContext context) JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
if (!jsonElement.isJsonObject()) { if (!jsonElement.isJsonObject()) {
@ -52,50 +55,50 @@ public class FormAdaptor implements JsonDeserializer<Form>, JsonSerializer<Form>
} }
JsonObject json = jsonElement.getAsJsonObject(); JsonObject json = jsonElement.getAsJsonObject();
if (typeOfT == SimpleForm.class) { if (typeOfT == SimpleFormImpl.class) {
String title = json.get("title").getAsString(); String title = json.get("title").getAsString();
String content = json.get("content").getAsString(); String content = json.get("content").getAsString();
List<ButtonComponent> buttons = context List<ButtonComponent> buttons = context
.deserialize(json.get("buttons"), LIST_BUTTON_TYPE); .deserialize(json.get("buttons"), LIST_BUTTON_TYPE);
return SimpleForm.of(title, content, buttons); return SimpleFormImpl.of(title, content, buttons);
} }
if (typeOfT == ModalForm.class) { if (typeOfT == ModalFormImpl.class) {
String title = json.get("title").getAsString(); String title = json.get("title").getAsString();
String content = json.get("content").getAsString(); String content = json.get("content").getAsString();
String button1 = json.get("button1").getAsString(); String button1 = json.get("button1").getAsString();
String button2 = json.get("button2").getAsString(); String button2 = json.get("button2").getAsString();
return ModalForm.of(title, content, button1, button2); return ModalFormImpl.of(title, content, button1, button2);
} }
if (typeOfT == CustomForm.class) { if (typeOfT == CustomFormImpl.class) {
String title = json.get("title").getAsString(); String title = json.get("title").getAsString();
FormImage icon = context.deserialize(json.get("icon"), FormImage.class); FormImage icon = context.deserialize(json.get("icon"), FormImageImpl.class);
List<Component> content = new ArrayList<>(); List<Component> content = new ArrayList<>();
JsonArray contentArray = json.getAsJsonArray("content"); JsonArray contentArray = json.getAsJsonArray("content");
for (JsonElement contentElement : contentArray) { for (JsonElement contentElement : contentArray) {
String typeName = contentElement.getAsJsonObject().get("type").getAsString(); String typeName = contentElement.getAsJsonObject().get("type").getAsString();
Component.Type type = Component.Type.getByName(typeName); ComponentType type = ComponentType.getByName(typeName);
if (type == null) { if (type == null) {
throw new JsonParseException("Failed to find Component type " + typeName); throw new JsonParseException("Failed to find Component type " + typeName);
} }
content.add(context.deserialize(contentElement, type.getComponentClass())); content.add(context.deserialize(contentElement, type.getComponentClass()));
} }
return CustomForm.of(title, icon, content); return CustomFormImpl.of(title, icon, content);
} }
return null; return null;
} }
@Override @Override
public JsonElement serialize(Form src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(FormImpl src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject(); JsonObject result = new JsonObject();
result.add("type", context.serialize(src.getType())); result.add("type", context.serialize(src.getType()));
if (typeOfSrc == SimpleForm.class) { if (typeOfSrc == SimpleFormImpl.class) {
SimpleForm form = (SimpleForm) src; SimpleFormImpl form = (SimpleFormImpl) src;
result.addProperty("title", form.getTitle()); result.addProperty("title", form.getTitle());
result.addProperty("content", form.getContent()); result.addProperty("content", form.getContent());
@ -103,8 +106,8 @@ public class FormAdaptor implements JsonDeserializer<Form>, JsonSerializer<Form>
return result; return result;
} }
if (typeOfSrc == ModalForm.class) { if (typeOfSrc == ModalFormImpl.class) {
ModalForm form = (ModalForm) src; ModalFormImpl form = (ModalFormImpl) src;
result.addProperty("title", form.getTitle()); result.addProperty("title", form.getTitle());
result.addProperty("content", form.getContent()); result.addProperty("content", form.getContent());
@ -113,8 +116,8 @@ public class FormAdaptor implements JsonDeserializer<Form>, JsonSerializer<Form>
return result; return result;
} }
if (typeOfSrc == CustomForm.class) { if (typeOfSrc == CustomFormImpl.class) {
CustomForm form = (CustomForm) src; CustomFormImpl form = (CustomFormImpl) src;
result.addProperty("title", form.getTitle()); result.addProperty("title", form.getTitle());
result.add("icon", context.serialize(form.getIcon())); result.add("icon", context.serialize(form.getIcon()));

Datei anzeigen

@ -23,36 +23,24 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.common.form.util; package org.geysermc.common.form.impl.util;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.FormImage;
@Getter @Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class FormImage { public final class FormImageImpl implements FormImage {
private final String type; private final Type type;
private final String data; private final String data;
public static FormImage of(String type, String data) { public static FormImageImpl of(Type type, String data) {
return new FormImage(type, data); return new FormImageImpl(type, data);
} }
public static FormImage of(Type type, String data) { public static FormImageImpl of(String type, String data) {
return of(type.getName(), data); return of(Type.getByName(type), data);
}
@RequiredArgsConstructor
public enum Type {
PATH("path"),
URL("url");
@Getter private final String name;
@Override
public String toString() {
return name;
}
} }
} }

Datei anzeigen

@ -25,169 +25,38 @@
package org.geysermc.common.form.response; package org.geysermc.common.form.response;
import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import lombok.AccessLevel; import org.geysermc.common.form.component.ComponentType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.geysermc.common.form.CustomForm;
import org.geysermc.common.form.component.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@Getter public interface CustomFormResponse extends FormResponse {
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) JsonArray getResponses();
@ToString
public class CustomFormResponse implements FormResponse {
private static final Gson GSON = new Gson();
private static final CustomFormResponse CLOSED =
new CustomFormResponse(true, false, null, null);
private static final CustomFormResponse INVALID =
new CustomFormResponse(false, true, null, null);
private final boolean closed;
private final boolean invalid;
private final JsonArray responses; List<ComponentType> getComponentTypes();
private final List<Component.Type> componentTypes;
private int index = -1; <T> T next(boolean includeLabels);
public static CustomFormResponse closed() { <T> T next();
return CLOSED;
}
public static CustomFormResponse invalid() { void skip(int amount);
return INVALID;
}
public static CustomFormResponse of(CustomForm form, String responseData) { void skip();
JsonArray responses = GSON.fromJson(responseData, JsonArray.class);
List<Component.Type> types = new ArrayList<>();
for (Component component : form.getContent()) {
types.add(component.getType());
}
return of(types, responses);
}
public static CustomFormResponse of(List<Component.Type> componentTypes, void index(int index);
JsonArray responses) {
if (componentTypes.size() != responses.size()) {
return invalid();
}
return new CustomFormResponse(false, false, responses, boolean hasNext();
Collections.unmodifiableList(componentTypes));
}
@SuppressWarnings("unchecked") JsonPrimitive get(int index);
public <T> T next(boolean includeLabels) {
if (!hasNext()) {
return null;
}
while (++index < responses.size()) { int getDropdown(int index);
Component.Type type = componentTypes.get(index);
if (type == Component.Type.LABEL && !includeLabels) {
continue;
}
return (T) getDataFromType(type, index);
}
return null; // we don't have anything to check anymore
}
public <T> T next() { String getInput(int index);
return next(false);
}
public void skip(int amount) { float getSlider(int index);
index += amount;
}
public void skip() { int getStepSlide(int index);
skip(1);
}
public void index(int index) { boolean getToggle(int index);
this.index = index;
}
public boolean hasNext() {
return responses.size() > index + 1;
}
public JsonPrimitive get(int index) {
try {
return responses.get(index).getAsJsonPrimitive();
} catch (IllegalStateException exception) {
wrongType(index, "a primitive");
return null;
}
}
public int getDropdown(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "dropdown");
}
return primitive.getAsInt();
}
public String getInput(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isString()) {
wrongType(index, "input");
}
return primitive.getAsString();
}
public float getSlider(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "slider");
}
return primitive.getAsFloat();
}
public int getStepSlide(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isNumber()) {
wrongType(index, "step slider");
}
return primitive.getAsInt();
}
public boolean getToggle(int index) {
JsonPrimitive primitive = get(index);
if (!primitive.isBoolean()) {
wrongType(index, "toggle");
}
return primitive.getAsBoolean();
}
private Object getDataFromType(Component.Type type, int index) {
switch (type) {
case DROPDOWN:
return getDropdown(index);
case INPUT:
return getInput(index);
case SLIDER:
return getSlider(index);
case STEP_SLIDER:
return getStepSlide(index);
case TOGGLE:
return getToggle(index);
default:
return null; // label e.g. is always null
}
}
private void wrongType(int index, String expected) {
throw new IllegalStateException(String.format(
"Expected %s on %s, got %s",
expected, index, responses.get(index).toString()));
}
} }

Datei anzeigen

@ -25,36 +25,10 @@
package org.geysermc.common.form.response; package org.geysermc.common.form.response;
import lombok.AccessLevel; public interface ModalFormResponse extends FormResponse {
import lombok.Getter; int getClickedButtonId();
import lombok.RequiredArgsConstructor;
@Getter String getClickedButtonText();
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public final class ModalFormResponse implements FormResponse {
private static final ModalFormResponse CLOSED =
new ModalFormResponse(true, false, -1, null);
private static final ModalFormResponse INVALID =
new ModalFormResponse(false, true, -1, null);
private final boolean closed;
private final boolean invalid;
private final int clickedButtonId; boolean getResult();
private final String clickedButtonText;
public static ModalFormResponse closed() {
return CLOSED;
}
public static ModalFormResponse invalid() {
return INVALID;
}
public static ModalFormResponse of(int clickedButtonId, String clickedButtonText) {
return new ModalFormResponse(false, false, clickedButtonId, clickedButtonText);
}
public boolean getResult() {
return clickedButtonId == 0;
}
} }

Datei anzeigen

@ -25,31 +25,10 @@
package org.geysermc.common.form.response; package org.geysermc.common.form.response;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.component.ButtonComponent; import org.geysermc.common.form.component.ButtonComponent;
@Getter public interface SimpleFormResponse extends FormResponse {
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) int getClickedButtonId();
public final class SimpleFormResponse implements FormResponse {
private static final SimpleFormResponse CLOSED = new SimpleFormResponse(true, false, -1, null);
private static final SimpleFormResponse INVALID = new SimpleFormResponse(false, true, -1, null);
private final boolean closed;
private final boolean invalid;
private final int clickedButtonId; ButtonComponent getClickedButton();
private final ButtonComponent clickedButton;
public static SimpleFormResponse closed() {
return CLOSED;
}
public static SimpleFormResponse invalid() {
return INVALID;
}
public static SimpleFormResponse of(int clickedButtonId, ButtonComponent clickedButton) {
return new SimpleFormResponse(false, false, clickedButtonId, clickedButton);
}
} }

Datei anzeigen

@ -58,13 +58,13 @@ import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.Setter; import lombok.Setter;
import org.geysermc.common.form.Form; import org.geysermc.common.form.Form;
import org.geysermc.common.form.FormBuilder;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.common.AuthType; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.Entity;
import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.entity.PlayerEntity;
import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.inventory.PlayerInventory;
import org.geysermc.connector.network.translators.chat.MessageTranslator;
import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.remote.RemoteServer;
import org.geysermc.connector.network.session.auth.AuthData; import org.geysermc.connector.network.session.auth.AuthData;
import org.geysermc.connector.network.session.auth.BedrockClientData; import org.geysermc.connector.network.session.auth.BedrockClientData;
@ -72,6 +72,7 @@ import org.geysermc.connector.network.session.cache.*;
import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.BiomeTranslator;
import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.network.translators.chat.MessageTranslator;
import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator; import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator;
import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.utils.*; import org.geysermc.connector.utils.*;
@ -606,11 +607,11 @@ public class GeyserSession implements CommandSender {
return this.upstream.getAddress(); return this.upstream.getAddress();
} }
public void sendForm(Form form) { public void sendForm(Form<?> form) {
formCache.showForm(form); formCache.showForm(form);
} }
public void sendForm(Form.Builder<?, ?> formBuilder) { public void sendForm(FormBuilder<?, ?> formBuilder) {
formCache.showForm(formBuilder.build()); formCache.showForm(formBuilder.build());
} }

Datei anzeigen

@ -27,40 +27,50 @@ package org.geysermc.connector.network.session.cache;
import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket; import com.nukkitx.protocol.bedrock.packet.ModalFormRequestPacket;
import com.nukkitx.protocol.bedrock.packet.ModalFormResponsePacket; import com.nukkitx.protocol.bedrock.packet.ModalFormResponsePacket;
import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.common.form.Form; import org.geysermc.common.form.Form;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
@RequiredArgsConstructor @RequiredArgsConstructor
public class FormCache { public class FormCache {
private final AtomicInteger formId = new AtomicInteger(0); private final AtomicInteger formId = new AtomicInteger(0);
private final Int2ObjectMap<Form> forms = new Int2ObjectOpenHashMap<>(); private final Int2ObjectMap<Form<?>> forms = new Int2ObjectOpenHashMap<>();
private final GeyserSession session; private final GeyserSession session;
public int addForm(Form form) { public int addForm(Form<?> form) {
int windowId = formId.getAndIncrement(); int windowId = formId.getAndIncrement();
forms.put(windowId, form); forms.put(windowId, form);
return windowId; return windowId;
} }
public int showForm(Form form) { public int showForm(Form<?> form) {
int windowId = addForm(form); int windowId = addForm(form);
ModalFormRequestPacket formRequestPacket = new ModalFormRequestPacket(); ModalFormRequestPacket formRequestPacket = new ModalFormRequestPacket();
formRequestPacket.setFormId(windowId); formRequestPacket.setFormId(windowId);
formRequestPacket.setFormData(form.getJsonData()); formRequestPacket.setFormData(form.getJsonData());
session.sendUpstreamPacket(formRequestPacket); session.sendUpstreamPacket(formRequestPacket);
// Hack to fix the url image loading bug
NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket();
latencyPacket.setFromServer(true);
latencyPacket.setTimestamp(-System.currentTimeMillis());
session.getConnector().getGeneralThreadPool().schedule(() ->
session.sendUpstreamPacket(latencyPacket),
500, TimeUnit.MILLISECONDS);
return windowId; return windowId;
} }
public void handleResponse(ModalFormResponsePacket response) { public void handleResponse(ModalFormResponsePacket response) {
Form form = forms.get(response.getFormId()); Form<?> form = forms.get(response.getFormId());
if (form == null) { if (form == null) {
return; return;
} }

Datei anzeigen

@ -27,9 +27,16 @@ package org.geysermc.connector.network.translators.bedrock;
import com.github.steveice10.mc.protocol.packet.ingame.client.ClientKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientKeepAlivePacket;
import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket;
import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.connector.entity.attribute.Attribute;
import org.geysermc.connector.entity.attribute.AttributeType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.Translator;
import org.geysermc.connector.utils.AttributeUtils;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/** /**
* Used to send the keep alive packet back to the server * Used to send the keep alive packet back to the server
@ -39,8 +46,26 @@ public class BedrockNetworkStackLatencyTranslator extends PacketTranslator<Netwo
@Override @Override
public void translate(NetworkStackLatencyPacket packet, GeyserSession session) { public void translate(NetworkStackLatencyPacket packet, GeyserSession session) {
// The client sends a timestamp back but it's rounded and therefore unreliable when we need the exact number if (packet.getTimestamp() > 0) {
ClientKeepAlivePacket keepAlivePacket = new ClientKeepAlivePacket(session.getLastKeepAliveTimestamp()); // The client sends a timestamp back but it's rounded and therefore unreliable when we need the exact number
session.sendDownstreamPacket(keepAlivePacket); ClientKeepAlivePacket keepAlivePacket = new ClientKeepAlivePacket(session.getLastKeepAliveTimestamp());
session.sendDownstreamPacket(keepAlivePacket);
return;
}
// Hack to fix the url image loading bug
UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
attributesPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId());
Attribute attribute = session.getPlayerEntity().getAttributes().get(AttributeType.EXPERIENCE_LEVEL);
if (attribute != null) {
attributesPacket.setAttributes(Collections.singletonList(AttributeUtils.getBedrockAttribute(attribute)));
} else {
attributesPacket.setAttributes(Collections.singletonList(AttributeUtils.getBedrockAttribute(AttributeType.EXPERIENCE_LEVEL.getAttribute(0))));
}
session.getConnector().getGeneralThreadPool().schedule(
() -> session.sendUpstreamPacket(attributesPacket),
500, TimeUnit.MILLISECONDS);
} }
} }

Datei anzeigen

@ -29,6 +29,8 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessag
import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import org.geysermc.common.form.Form; import org.geysermc.common.form.Form;
import org.geysermc.common.form.FormType;
import org.geysermc.common.form.Forms;
import org.geysermc.connector.common.AuthType; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.PacketTranslator;
@ -53,7 +55,7 @@ public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMe
// receive: first byte is form type, second and third are the id, remaining is the form data // receive: first byte is form type, second and third are the id, remaining is the form data
// respond: first and second byte id, remaining is form response data // respond: first and second byte id, remaining is form response data
Form.Type type = Form.Type.getByOrdinal(data[0]); FormType type = FormType.getByOrdinal(data[0]);
if (type == null) { if (type == null) {
throw new NullPointerException( throw new NullPointerException(
"Got type " + data[0] + " which isn't a valid form type!"); "Got type " + data[0] + " which isn't a valid form type!");
@ -61,7 +63,7 @@ public class JavaPluginMessageTranslator extends PacketTranslator<ServerPluginMe
String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8); String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8);
Form form = Form.fromJson(dataString, type.getTypeClass()); Form<?> form = Forms.fromJson(dataString, type.getTypeClass());
form.setResponseHandler(response -> { form.setResponseHandler(response -> {
byte[] raw = response.getBytes(StandardCharsets.UTF_8); byte[] raw = response.getBytes(StandardCharsets.UTF_8);
byte[] finalData = new byte[raw.length + 2]; byte[] finalData = new byte[raw.length + 2];

Datei anzeigen

@ -89,7 +89,7 @@ public class SettingsUtils {
} }
builder.responseHandler((form, responseData) -> { builder.responseHandler((form, responseData) -> {
CustomFormResponse response = form.parseResponseAs(responseData); CustomFormResponse response = form.parseResponse(responseData);
if (response.isClosed() || response.isInvalid()) { if (response.isClosed() || response.isInvalid()) {
return; return;
} }