shedaniel 5 年之前
父節點
當前提交
cd4fb7cbb9

+ 2 - 2
build.gradle

@@ -1,7 +1,7 @@
 import java.text.SimpleDateFormat
 
 plugins {
-    id 'fabric-loom' version '0.2.4-SNAPSHOT'
+    id 'fabric-loom' version '0.2.5-SNAPSHOT'
     id 'maven-publish'
     id 'maven'
     id 'signing'
@@ -141,7 +141,7 @@ curseforge {
     if (apiKey != null)
         project {
             id = '319057'
-            releaseType = 'beta'
+            releaseType = 'release'
             addGameVersion '1.15-Snapshot'
             addGameVersion 'Java 8'
             relations {

+ 5 - 5
gradle.properties

@@ -1,6 +1,6 @@
-minecraft_version=19w44a
-yarn_version=19w44a+build.3
-fabric_loader_version=0.6.3+build.168
-fabric_version=0.4.9+build.258-1.15
-mod_version=2.4.1
+minecraft_version=1.15-pre6
+yarn_version=1.15-pre6+build.1
+fabric_loader_version=0.7.2+build.174
+fabric_version=0.4.20+build.273-1.15
+mod_version=2.5
 modmenu_version=1.7.14-unstable.19w42a+build.10

+ 2 - 0
src/main/java/me/shedaniel/clothconfig2/ClothConfigInitializer.java

@@ -10,6 +10,7 @@ import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
 import net.fabricmc.api.ClientModInitializer;
 import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.util.InputUtil;
 import net.minecraft.item.Item;
 import net.minecraft.item.Items;
 import net.minecraft.util.Identifier;
@@ -133,6 +134,7 @@ public class ClothConfigInitializer implements ClientModInitializer {
                         scrolling.addEntry(entryBuilder.startDoubleField("Bounce Multiplier", bounceBackMultiplier).setDefaultValue(0.24).setSaveConsumer(i -> bounceBackMultiplier = i).build());
                         ConfigCategory testing = builder.getOrCreateCategory("Testing");
                         testing.addEntry(entryBuilder.startDropdownMenu("lol apple", DropdownMenuBuilder.TopCellElementBuilder.ofItemObject(Items.APPLE), DropdownMenuBuilder.CellCreatorBuilder.ofItemObject()).setDefaultValue(Items.APPLE).setSelections(Registry.ITEM.stream().sorted(Comparator.comparing(Item::toString)).collect(Collectors.toSet())).setSaveConsumer(item -> System.out.println("save this " + item)).build());
+                        testing.addEntry(entryBuilder.startKeyCodeField("Cool Key", InputUtil.UNKNOWN_KEYCODE).setDefaultValue(InputUtil.UNKNOWN_KEYCODE).build());
                         builder.setSavingRunnable(() -> {
                             saveConfig();
                         });

+ 9 - 0
src/main/java/me/shedaniel/clothconfig2/api/ConfigEntryBuilder.java

@@ -6,6 +6,9 @@ import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.SelectionTopCellEl
 import me.shedaniel.clothconfig2.impl.ConfigEntryBuilderImpl;
 import me.shedaniel.clothconfig2.impl.builders.*;
 import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder.TopCellElementBuilder;
+import net.fabricmc.fabric.mixin.client.keybinding.KeyCodeAccessor;
+import net.minecraft.client.options.KeyBinding;
+import net.minecraft.client.util.InputUtil;
 
 import java.util.List;
 import java.util.function.Function;
@@ -58,6 +61,12 @@ public interface ConfigEntryBuilder {
     
     LongSliderBuilder startLongSlider(String fieldNameKey, long value, long min, long max);
     
+    KeyCodeBuilder startKeyCodeField(String fieldNameKey, InputUtil.KeyCode value);
+    
+    default KeyCodeBuilder fillKeybindingField(String fieldNameKey, KeyBinding value) {
+        return startKeyCodeField(fieldNameKey, ((KeyCodeAccessor) value).getKeyCode()).setDefaultValue(value.getDefaultKeyCode());
+    }
+    
     <T> DropdownMenuBuilder<T> startDropdownMenu(String fieldNameKey, SelectionTopCellElement<T> topCellElement, SelectionCellCreator<T> cellCreator);
     
     default <T> DropdownMenuBuilder<T> startDropdownMenu(String fieldNameKey, SelectionTopCellElement<T> topCellElement) {

+ 29 - 5
src/main/java/me/shedaniel/clothconfig2/gui/ClothConfigScreen.java

@@ -9,6 +9,7 @@ import me.shedaniel.clothconfig2.api.AbstractConfigEntry;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.QueuedTooltip;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.gui.entries.KeyCodeEntry;
 import me.shedaniel.clothconfig2.gui.widget.DynamicElementListWidget;
 import me.shedaniel.math.api.Rectangle;
 import net.minecraft.client.MinecraftClient;
@@ -23,6 +24,7 @@ import net.minecraft.client.render.BufferBuilder;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.VertexFormats;
 import net.minecraft.client.resource.language.I18n;
+import net.minecraft.client.util.InputUtil;
 import net.minecraft.text.LiteralText;
 import net.minecraft.text.TranslatableText;
 import net.minecraft.util.Identifier;
@@ -42,6 +44,7 @@ public abstract class ClothConfigScreen extends Screen {
     
     private static final Identifier CONFIG_TEX = new Identifier("cloth-config2", "textures/gui/cloth_config.png");
     private final List<QueuedTooltip> queuedTooltips = Lists.newArrayList();
+    public KeyCodeEntry focusedBinding;
     public int nextTabIndex;
     public int selectedTabIndex;
     public double tabsScrollVelocity = 0d;
@@ -435,14 +438,14 @@ public abstract class ClothConfigScreen extends Screen {
         RenderSystem.shadeModel(7425);
         RenderSystem.disableTexture();
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBufferBuilder();
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        BufferBuilder buffer = tessellator.getBuffer();
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(tabsBounds.getMinX() + 20, tabsBounds.getMinY() + 4, 0.0D).texture(0, 1f).color(0, 0, 0, lightColor).next();
         buffer.vertex(tabsBounds.getMaxX() - 20, tabsBounds.getMinY() + 4, 0.0D).texture(1f, 1f).color(0, 0, 0, lightColor).next();
         buffer.vertex(tabsBounds.getMaxX() - 20, tabsBounds.getMinY(), 0.0D).texture(1f, 0).color(0, 0, 0, darkColor).next();
         buffer.vertex(tabsBounds.getMinX() + 20, tabsBounds.getMinY(), 0.0D).texture(0, 0).color(0, 0, 0, darkColor).next();
         tessellator.draw();
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(tabsBounds.getMinX() + 20, tabsBounds.getMaxY(), 0.0D).texture(0, 1f).color(0, 0, 0, darkColor).next();
         buffer.vertex(tabsBounds.getMaxX() - 20, tabsBounds.getMaxY(), 0.0D).texture(1f, 1f).color(0, 0, 0, darkColor).next();
         buffer.vertex(tabsBounds.getMaxX() - 20, tabsBounds.getMaxY() - 4, 0.0D).texture(1f, 0).color(0, 0, 0, lightColor).next();
@@ -459,11 +462,11 @@ public abstract class ClothConfigScreen extends Screen {
         if (isTransparentBackground())
             return;
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBufferBuilder();
+        BufferBuilder buffer = tessellator.getBuffer();
         minecraft.getTextureManager().bindTexture(getBackgroundLocation());
         RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
         float f = 32.0F;
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(rect.getMinX(), rect.getMaxY(), 0.0D).texture(rect.getMinX() / 32.0F, rect.getMaxY() / 32.0F).color(red, green, blue, endAlpha).next();
         buffer.vertex(rect.getMaxX(), rect.getMaxY(), 0.0D).texture(rect.getMaxX() / 32.0F, rect.getMaxY() / 32.0F).color(red, green, blue, endAlpha).next();
         buffer.vertex(rect.getMaxX(), rect.getMinY(), 0.0D).texture(rect.getMaxX() / 32.0F, rect.getMinY() / 32.0F).color(red, green, blue, startAlpha).next();
@@ -471,8 +474,29 @@ public abstract class ClothConfigScreen extends Screen {
         tessellator.draw();
     }
     
+    @Override
+    public boolean mouseClicked(double double_1, double double_2, int int_1) {
+        if (this.focusedBinding != null) {
+            focusedBinding.setValue(InputUtil.Type.MOUSE.createFromCode(int_1));
+            this.focusedBinding = null;
+            return true;
+        } else {
+            return super.mouseClicked(double_1, double_2, int_1);
+        }
+    }
+    
     @Override
     public boolean keyPressed(int int_1, int int_2, int int_3) {
+        if (this.focusedBinding != null) {
+            if (int_1 == 256) {
+                focusedBinding.setValue(InputUtil.UNKNOWN_KEYCODE);
+            } else {
+                focusedBinding.setValue(InputUtil.getKeyCode(int_1, int_2));
+            }
+            
+            this.focusedBinding = null;
+            return true;
+        }
         if (int_1 == 256 && this.shouldCloseOnEsc()) {
             if (confirmSave && edited)
                 minecraft.openScreen(new ConfirmScreen(new QuitSaveConsumer(), new TranslatableText("text.cloth-config.quit_config"), new TranslatableText("text.cloth-config.quit_config_sure"), I18n.translate("text.cloth-config.quit_discard"), I18n.translate("gui.cancel")));

+ 2 - 2
src/main/java/me/shedaniel/clothconfig2/gui/entries/BaseListEntry.java

@@ -9,7 +9,7 @@ import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.widget.AbstractButtonWidget;
 import net.minecraft.client.gui.widget.ButtonWidget;
-import net.minecraft.client.render.GuiLighting;
+import net.minecraft.client.render.DiffuseLighting;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.sound.SoundEvents;
@@ -165,7 +165,7 @@ public abstract class BaseListEntry<T, C extends BaseListCell> extends TooltipLi
                 getScreen().queueTooltip(QueuedTooltip.create(new Point(mouseX, mouseY), tooltip.get()));
         }
         MinecraftClient.getInstance().getTextureManager().bindTexture(CONFIG_TEX);
-        GuiLighting.disable();
+        DiffuseLighting.disable();
         RenderSystem.color4f(1, 1, 1, 1);
         BaseListCell focused = !expended || getFocused() == null || !(getFocused() instanceof BaseListCell) ? null : (BaseListCell) getFocused();
         boolean insideCreateNew = isInsideCreateNew(mouseX, mouseY);

+ 3 - 3
src/main/java/me/shedaniel/clothconfig2/gui/entries/DropdownBoxEntry.java

@@ -401,10 +401,10 @@ public class DropdownBoxEntry<T> extends TooltipListEntry<T> {
                 int topc = new Rectangle(scrollbarPositionMinX, minY, scrollbarPositionMaxX - scrollbarPositionMinX, height).contains(PointHelper.fromMouse()) ? 222 : 172;
                 
                 Tessellator tessellator = Tessellator.getInstance();
-                BufferBuilder buffer = tessellator.getBufferBuilder();
+                BufferBuilder buffer = tessellator.getBuffer();
                 
                 // Bottom
-                buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+                buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
                 buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).texture(0, 1).color(bottomc, bottomc, bottomc, 255).next();
                 buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).texture(1, 1).color(bottomc, bottomc, bottomc, 255).next();
                 buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).texture(1, 0).color(bottomc, bottomc, bottomc, 255).next();
@@ -412,7 +412,7 @@ public class DropdownBoxEntry<T> extends TooltipListEntry<T> {
                 tessellator.draw();
                 
                 // Top
-                buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+                buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
                 buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).texture(0, 1).color(topc, topc, topc, 255).next();
                 buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).texture(1, 1).color(topc, topc, topc, 255).next();
                 buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).texture(1, 0).color(topc, topc, topc, 255).next();

+ 130 - 0
src/main/java/me/shedaniel/clothconfig2/gui/entries/KeyCodeEntry.java

@@ -0,0 +1,130 @@
+package me.shedaniel.clothconfig2.gui.entries;
+
+import com.google.common.collect.Lists;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.gui.widget.ButtonWidget;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.client.util.InputUtil;
+import net.minecraft.client.util.Window;
+import net.minecraft.util.Formatting;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class KeyCodeEntry extends TooltipListEntry<InputUtil.KeyCode> {
+    
+    private InputUtil.KeyCode value;
+    private ButtonWidget buttonWidget, resetButton;
+    private Consumer<InputUtil.KeyCode> saveConsumer;
+    private Supplier<InputUtil.KeyCode> defaultValue;
+    private List<Element> widgets;
+    private boolean allowMouse = true, allowKey = true;
+    
+    @Deprecated
+    public KeyCodeEntry(String fieldName, InputUtil.KeyCode value, String resetButtonKey, Supplier<InputUtil.KeyCode> defaultValue, Consumer<InputUtil.KeyCode> saveConsumer, Supplier<Optional<String[]>> tooltipSupplier, boolean requiresRestart) {
+        super(fieldName, tooltipSupplier, requiresRestart);
+        this.defaultValue = defaultValue;
+        this.value = value;
+        this.buttonWidget = new ButtonWidget(0, 0, 150, 20, "", widget -> {
+            getScreen().focusedBinding = this;
+            getScreen().setEdited(true, isRequiresRestart());
+        });
+        this.resetButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.getStringWidth(I18n.translate(resetButtonKey)) + 6, 20, I18n.translate(resetButtonKey), widget -> {
+            KeyCodeEntry.this.value = getDefaultValue().get();
+            getScreen().focusedBinding = null;
+            getScreen().setEdited(true, isRequiresRestart());
+        });
+        this.saveConsumer = saveConsumer;
+        this.widgets = Lists.newArrayList(buttonWidget, resetButton);
+    }
+    
+    public void setAllowKey(boolean allowKey) {
+        this.allowKey = allowKey;
+    }
+    
+    public void setAllowMouse(boolean allowMouse) {
+        this.allowMouse = allowMouse;
+    }
+    
+    public boolean isAllowKey() {
+        return allowKey;
+    }
+    
+    public boolean isAllowMouse() {
+        return allowMouse;
+    }
+    
+    public void setValue(InputUtil.KeyCode value) {
+        this.value = value;
+    }
+    
+    @Override
+    public void save() {
+        if (saveConsumer != null)
+            saveConsumer.accept(getValue());
+    }
+    
+    @Override
+    public InputUtil.KeyCode getValue() {
+        return value;
+    }
+    
+    @Override
+    public Optional<InputUtil.KeyCode> getDefaultValue() {
+        return Optional.ofNullable(defaultValue).map(Supplier::get);
+    }
+    
+    private String getLocalizedName() {
+        String string_1 = this.value.getName();
+        int int_1 = this.value.getKeyCode();
+        String string_2 = null;
+        switch (this.value.getCategory()) {
+            case KEYSYM:
+                string_2 = InputUtil.getKeycodeName(int_1);
+                break;
+            case SCANCODE:
+                string_2 = InputUtil.getScancodeName(int_1);
+                break;
+            case MOUSE:
+                String string_3 = I18n.translate(string_1);
+                string_2 = Objects.equals(string_3, string_1) ? I18n.translate(InputUtil.Type.MOUSE.getName(), int_1 + 1) : string_3;
+        }
+        return string_2 == null ? I18n.translate(string_1) : string_2;
+    }
+    
+    @Override
+    public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
+        super.render(index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
+        Window window = MinecraftClient.getInstance().getWindow();
+        this.resetButton.active = isEditable() && getDefaultValue().isPresent() && !getDefaultValue().get().equals(value);
+        this.resetButton.y = y;
+        this.buttonWidget.active = isEditable();
+        this.buttonWidget.y = y;
+        this.buttonWidget.setMessage(getLocalizedName());
+        if (getScreen().focusedBinding == this)
+            this.buttonWidget.setMessage(Formatting.WHITE + "> " + Formatting.YELLOW + this.buttonWidget.getMessage() + Formatting.WHITE + " <");
+        if (MinecraftClient.getInstance().textRenderer.isRightToLeft()) {
+            MinecraftClient.getInstance().textRenderer.drawWithShadow(I18n.translate(getFieldName()), window.getScaledWidth() - x - MinecraftClient.getInstance().textRenderer.getStringWidth(I18n.translate(getFieldName())), y + 5, 16777215);
+            this.resetButton.x = x;
+            this.buttonWidget.x = x + resetButton.getWidth() + 2;
+            this.buttonWidget.setWidth(150 - resetButton.getWidth() - 2);
+        } else {
+            MinecraftClient.getInstance().textRenderer.drawWithShadow(I18n.translate(getFieldName()), x, y + 5, getPreferredTextColor());
+            this.resetButton.x = x + entryWidth - resetButton.getWidth();
+            this.buttonWidget.x = x + entryWidth - 150;
+            this.buttonWidget.setWidth(150 - resetButton.getWidth() - 2);
+        }
+        resetButton.render(mouseX, mouseY, delta);
+        buttonWidget.render(mouseX, mouseY, delta);
+    }
+    
+    @Override
+    public List<? extends Element> children() {
+        return widgets;
+    }
+    
+}

+ 2 - 2
src/main/java/me/shedaniel/clothconfig2/gui/entries/SubCategoryListEntry.java

@@ -6,7 +6,7 @@ import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.math.api.Rectangle;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
-import net.minecraft.client.render.GuiLighting;
+import net.minecraft.client.render.DiffuseLighting;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.sound.SoundEvents;
@@ -70,7 +70,7 @@ public class SubCategoryListEntry extends TooltipListEntry<List<AbstractConfigLi
         widget.rectangle.width = entryWidth + 19;
         widget.rectangle.height = 24;
         MinecraftClient.getInstance().getTextureManager().bindTexture(CONFIG_TEX);
-        GuiLighting.disable();
+        DiffuseLighting.disable();
         RenderSystem.color4f(1, 1, 1, 1);
         blit(x - 15, y + 4, 24, (widget.rectangle.contains(mouseX, mouseY) ? 18 : 0) + (expended ? 9 : 0), 9, 9);
         MinecraftClient.getInstance().textRenderer.drawWithShadow(I18n.translate(categoryName), x, y + 5, widget.rectangle.contains(mouseX, mouseY) ? 0xffe6fe16 : -1);

+ 12 - 12
src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicEntryListWidget.java

@@ -12,7 +12,7 @@ import net.minecraft.client.gui.Drawable;
 import net.minecraft.client.gui.DrawableHelper;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.render.BufferBuilder;
-import net.minecraft.client.render.GuiLighting;
+import net.minecraft.client.render.DiffuseLighting;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.VertexFormats;
 import net.minecraft.util.Identifier;
@@ -170,7 +170,7 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
         this.client.getTextureManager().bindTexture(backgroundLocation);
         RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
         float float_2 = 32.0F;
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(this.left, this.bottom, 0.0D).texture(this.left / 32.0F, ((this.bottom + (int) this.getScroll()) / 32.0F)).color(32, 32, 32, 255).next();
         buffer.vertex(this.right, this.bottom, 0.0D).texture(this.right / 32.0F, ((this.bottom + (int) this.getScroll()) / 32.0F)).color(32, 32, 32, 255).next();
         buffer.vertex(this.right, this.top, 0.0D).texture(this.right / 32.0F, ((this.top + (int) this.getScroll()) / 32.0F)).color(32, 32, 32, 255).next();
@@ -185,7 +185,7 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
         RenderSystem.disableLighting();
         RenderSystem.disableFog();
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBufferBuilder();
+        BufferBuilder buffer = tessellator.getBuffer();
         renderBackBackground(buffer, tessellator);
         int rowLeft = this.getRowLeft();
         int startY = this.top + 4 - (int) this.getScroll();
@@ -202,13 +202,13 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
         RenderSystem.disableAlphaTest();
         RenderSystem.shadeModel(7425);
         RenderSystem.disableTexture();
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(this.left, this.top + 4, 0.0D).texture(0, 1).color(0, 0, 0, 0).next();
         buffer.vertex(this.right, this.top + 4, 0.0D).texture(1, 1).color(0, 0, 0, 0).next();
         buffer.vertex(this.right, this.top, 0.0D).texture(1, 0).color(0, 0, 0, 255).next();
         buffer.vertex(this.left, this.top, 0.0D).texture(0, 0).color(0, 0, 0, 255).next();
         tessellator.draw();
-        buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+        buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         buffer.vertex(this.left, this.bottom, 0.0D).texture(0, 1).color(0, 0, 0, 255).next();
         buffer.vertex(this.right, this.bottom, 0.0D).texture(1, 1).color(0, 0, 0, 255).next();
         buffer.vertex(this.right, this.bottom - 4, 0.0D).texture(1, 0).color(0, 0, 0, 0).next();
@@ -233,19 +233,19 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
                 int_10 = this.top;
             }
             
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, this.bottom, 0.0D).texture(0, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.bottom, 0.0D).texture(1, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.top, 0.0D).texture(1, 0).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMinX, this.top, 0.0D).texture(0, 0).color(0, 0, 0, 255).next();
             tessellator.draw();
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, int_10 + int_9, 0.0D).texture(0, 1).color(128, 128, 128, 255).next();
             buffer.vertex(scrollbarPositionMaxX, int_10 + int_9, 0.0D).texture(1, 1).color(128, 128, 128, 255).next();
             buffer.vertex(scrollbarPositionMaxX, int_10, 0.0D).texture(1, 0).color(128, 128, 128, 255).next();
             buffer.vertex(scrollbarPositionMinX, int_10, 0.0D).texture(0, 0).color(128, 128, 128, 255).next();
             tessellator.draw();
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, (int_10 + int_9 - 1), 0.0D).texture(0, 1).color(192, 192, 192, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), (int_10 + int_9 - 1), 0.0D).texture(1, 1).color(192, 192, 192, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), int_10, 0.0D).texture(1, 0).color(192, 192, 192, 255).next();
@@ -393,7 +393,7 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
     protected void renderList(int startX, int startY, int int_3, int int_4, float float_1) {
         int itemCount = this.getItemCount();
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBufferBuilder();
+        BufferBuilder buffer = tessellator.getBuffer();
         
         for(int renderIndex = 0; renderIndex < itemCount; ++renderIndex) {
             E item = this.getItem(renderIndex);
@@ -427,7 +427,7 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
             
             int y = this.getRowTop(renderIndex);
             int x = this.getRowLeft();
-            GuiLighting.disable();
+            DiffuseLighting.disable();
             item.render(renderIndex, y, x, itemWidth, itemHeight, int_3, int_4, this.isMouseOver((double) int_3, (double) int_4) && Objects.equals(this.getItemAtPosition((double) int_3, (double) int_4), item), float_1);
         }
         
@@ -450,11 +450,11 @@ public abstract class DynamicEntryListWidget<E extends DynamicEntryListWidget.En
     
     protected void renderHoleBackground(int int_1, int int_2, int int_3, int int_4) {
         Tessellator tessellator_1 = Tessellator.getInstance();
-        BufferBuilder bufferBuilder_1 = tessellator_1.getBufferBuilder();
+        BufferBuilder bufferBuilder_1 = tessellator_1.getBuffer();
         this.client.getTextureManager().bindTexture(backgroundLocation);
         RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
         float float_1 = 32.0F;
-        bufferBuilder_1.begin(7, VertexFormats.POSITION_UV_COLOR);
+        bufferBuilder_1.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
         bufferBuilder_1.vertex((double) this.left, (double) int_2, 0.0D).texture(0, ((float) int_2 / 32.0F)).color(64, 64, 64, int_4).next();
         bufferBuilder_1.vertex((double) (this.left + this.width), (double) int_2, 0.0D).texture(((float) this.width / 32.0F), ((float) int_2 / 32.0F)).color(64, 64, 64, int_4).next();
         bufferBuilder_1.vertex((double) (this.left + this.width), (double) int_1, 0.0D).texture(((float) this.width / 32.0F), ((float) int_1 / 32.0F)).color(64, 64, 64, int_3).next();

+ 3 - 6
src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicNewSmoothScrollingEntryListWidget.java

@@ -1,7 +1,6 @@
 package me.shedaniel.clothconfig2.gui.widget;
 
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
-import me.shedaniel.clothconfig2.api.RunSixtyTimesEverySec;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import net.minecraft.client.MinecraftClient;
@@ -11,8 +10,6 @@ import net.minecraft.client.render.VertexFormats;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.math.MathHelper;
 
-import static me.shedaniel.clothconfig2.ClothConfigInitializer.getBounceBackMultiplier;
-
 public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends DynamicEntryListWidget.Entry<E>> extends DynamicEntryListWidget<E> {
     
     protected double target;
@@ -142,7 +139,7 @@ public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends Dynamic
             int topc = new Rectangle(scrollbarPositionMinX, minY, scrollbarPositionMaxX - scrollbarPositionMinX, height).contains(PointHelper.fromMouse()) ? 222 : 172;
             
             // Black Bar
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, this.bottom, 0.0D).texture(0, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.bottom, 0.0D).texture(1, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.top, 0.0D).texture(1, 0).color(0, 0, 0, 255).next();
@@ -150,7 +147,7 @@ public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends Dynamic
             tessellator.draw();
             
             // Bottom
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).texture(0, 1).color(bottomc, bottomc, bottomc, 255).next();
             buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).texture(1, 1).color(bottomc, bottomc, bottomc, 255).next();
             buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).texture(1, 0).color(bottomc, bottomc, bottomc, 255).next();
@@ -158,7 +155,7 @@ public abstract class DynamicNewSmoothScrollingEntryListWidget<E extends Dynamic
             tessellator.draw();
             
             // Top
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).texture(0, 1).color(topc, topc, topc, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).texture(1, 1).color(topc, topc, topc, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).texture(1, 0).color(topc, topc, topc, 255).next();

+ 3 - 3
src/main/java/me/shedaniel/clothconfig2/gui/widget/DynamicSmoothScrollingEntryListWidget.java

@@ -134,7 +134,7 @@ public abstract class DynamicSmoothScrollingEntryListWidget<E extends DynamicEnt
             int minY = Math.min(Math.max((int) this.getScroll() * (this.bottom - this.top - height) / maxScroll + this.top, this.top), this.bottom - height);
             
             // Black Bar
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, this.bottom, 0.0D).texture(0, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.bottom, 0.0D).texture(1, 1).color(0, 0, 0, 255).next();
             buffer.vertex(scrollbarPositionMaxX, this.top, 0.0D).texture(1, 0).color(0, 0, 0, 255).next();
@@ -142,7 +142,7 @@ public abstract class DynamicSmoothScrollingEntryListWidget<E extends DynamicEnt
             tessellator.draw();
             
             // Top
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).texture(0, 1).color(128, 128, 128, 255).next();
             buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).texture(1, 1).color(128, 128, 128, 255).next();
             buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).texture(1, 0).color(128, 128, 128, 255).next();
@@ -150,7 +150,7 @@ public abstract class DynamicSmoothScrollingEntryListWidget<E extends DynamicEnt
             tessellator.draw();
             
             // Bottom
-            buffer.begin(7, VertexFormats.POSITION_UV_COLOR);
+            buffer.begin(7, VertexFormats.POSITION_TEXTURE_COLOR);
             buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).texture(0, 1).color(192, 192, 192, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).texture(1, 1).color(192, 192, 192, 255).next();
             buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).texture(1, 0).color(192, 192, 192, 255).next();

+ 6 - 1
src/main/java/me/shedaniel/clothconfig2/impl/ConfigEntryBuilderImpl.java

@@ -2,10 +2,10 @@ package me.shedaniel.clothconfig2.impl;
 
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
-import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry;
 import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.SelectionCellCreator;
 import me.shedaniel.clothconfig2.gui.entries.DropdownBoxEntry.SelectionTopCellElement;
 import me.shedaniel.clothconfig2.impl.builders.*;
+import net.minecraft.client.util.InputUtil;
 
 import java.util.List;
 import java.util.UUID;
@@ -138,6 +138,11 @@ public class ConfigEntryBuilderImpl implements ConfigEntryBuilder {
         return new LongSliderBuilder(resetButtonKey, fieldNameKey, value, min, max);
     }
     
+    @Override
+    public KeyCodeBuilder startKeyCodeField(String fieldNameKey, InputUtil.KeyCode value) {
+        return new KeyCodeBuilder(resetButtonKey, fieldNameKey, value);
+    }
+    
     @Override
     public <T> DropdownMenuBuilder<T> startDropdownMenu(String fieldNameKey, SelectionTopCellElement<T> topCellElement, SelectionCellCreator<T> cellCreator) {
         return new DropdownMenuBuilder(resetButtonKey, fieldNameKey, topCellElement, cellCreator);

+ 78 - 0
src/main/java/me/shedaniel/clothconfig2/impl/builders/KeyCodeBuilder.java

@@ -0,0 +1,78 @@
+package me.shedaniel.clothconfig2.impl.builders;
+
+import me.shedaniel.clothconfig2.gui.entries.KeyCodeEntry;
+import net.minecraft.client.util.InputUtil;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class KeyCodeBuilder extends FieldBuilder<InputUtil.KeyCode, KeyCodeEntry> {
+    
+    @Nullable private Consumer<InputUtil.KeyCode> saveConsumer = null;
+    @Nonnull private Function<InputUtil.KeyCode, Optional<String[]>> tooltipSupplier = bool -> Optional.empty();
+    private InputUtil.KeyCode value;
+    
+    public KeyCodeBuilder(String resetButtonKey, String fieldNameKey, InputUtil.KeyCode value) {
+        super(resetButtonKey, fieldNameKey);
+        this.value = value;
+    }
+    
+    public KeyCodeBuilder setErrorSupplier(@Nullable Function<InputUtil.KeyCode, Optional<String>> errorSupplier) {
+        this.errorSupplier = errorSupplier;
+        return this;
+    }
+    
+    public KeyCodeBuilder requireRestart() {
+        requireRestart(true);
+        return this;
+    }
+    
+    public KeyCodeBuilder setSaveConsumer(Consumer<InputUtil.KeyCode> saveConsumer) {
+        this.saveConsumer = saveConsumer;
+        return this;
+    }
+    
+    public KeyCodeBuilder setDefaultValue(Supplier<InputUtil.KeyCode> defaultValue) {
+        this.defaultValue = defaultValue;
+        return this;
+    }
+    
+    public KeyCodeBuilder setDefaultValue(InputUtil.KeyCode defaultValue) {
+        this.defaultValue = () -> defaultValue;
+        return this;
+    }
+    
+    public KeyCodeBuilder setTooltipSupplier(@Nonnull Function<InputUtil.KeyCode, Optional<String[]>> tooltipSupplier) {
+        this.tooltipSupplier = tooltipSupplier;
+        return this;
+    }
+    
+    public KeyCodeBuilder setTooltipSupplier(@Nonnull Supplier<Optional<String[]>> tooltipSupplier) {
+        this.tooltipSupplier = bool -> tooltipSupplier.get();
+        return this;
+    }
+    
+    public KeyCodeBuilder setTooltip(Optional<String[]> tooltip) {
+        this.tooltipSupplier = bool -> tooltip;
+        return this;
+    }
+    
+    public KeyCodeBuilder setTooltip(@Nullable String... tooltip) {
+        this.tooltipSupplier = bool -> Optional.ofNullable(tooltip);
+        return this;
+    }
+    
+    @Override
+    public KeyCodeEntry build() {
+        KeyCodeEntry entry = new KeyCodeEntry(getFieldNameKey(), value, getResetButtonKey(), defaultValue, saveConsumer, null, isRequireRestart());
+        entry.setTooltipSupplier(() -> tooltipSupplier.apply(entry.getValue()));
+        if (errorSupplier != null)
+            entry.setErrorSupplier(() -> errorSupplier.apply(entry.getValue()));
+        return entry;
+    }
+    
+}