2021-04-10 20:00:32 +02:00
package com.simibubi.create.foundation.config.ui ;
2021-04-25 19:54:18 +02:00
import java.awt.Color ;
2021-04-10 20:00:32 +02:00
import javax.annotation.Nonnull ;
2021-04-23 18:11:32 +02:00
import javax.annotation.Nullable ;
2021-04-10 20:00:32 +02:00
2021-04-23 18:11:32 +02:00
import org.lwjgl.glfw.GLFW ;
2021-04-16 04:22:38 +02:00
2021-04-10 20:00:32 +02:00
import com.electronwill.nightconfig.core.AbstractConfig ;
import com.electronwill.nightconfig.core.UnmodifiableConfig ;
import com.mojang.blaze3d.matrix.MatrixStack ;
2021-04-11 03:12:43 +02:00
import com.simibubi.create.foundation.config.ui.entries.BooleanEntry ;
2021-04-14 03:27:11 +02:00
import com.simibubi.create.foundation.config.ui.entries.EnumEntry ;
2021-04-13 23:54:26 +02:00
import com.simibubi.create.foundation.config.ui.entries.NumberEntry ;
2021-04-10 20:00:32 +02:00
import com.simibubi.create.foundation.config.ui.entries.SubMenuEntry ;
2021-04-23 18:11:32 +02:00
import com.simibubi.create.foundation.config.ui.entries.ValueEntry ;
import com.simibubi.create.foundation.gui.AllIcons ;
import com.simibubi.create.foundation.gui.ConfirmationScreen ;
import com.simibubi.create.foundation.gui.DelegatedStencilElement ;
import com.simibubi.create.foundation.gui.ScreenOpener ;
2021-04-25 19:54:18 +02:00
import com.simibubi.create.foundation.gui.Theme ;
2021-04-23 18:11:32 +02:00
import com.simibubi.create.foundation.gui.UIRenderHelper ;
2021-04-25 19:54:18 +02:00
import com.simibubi.create.foundation.gui.widgets.BoxWidget ;
2021-04-23 18:11:32 +02:00
import com.simibubi.create.foundation.item.TooltipHelper ;
2021-04-27 02:48:50 +02:00
import com.simibubi.create.foundation.networking.AllPackets ;
2021-04-28 21:44:03 +02:00
import com.simibubi.create.foundation.utility.Couple ;
2021-04-16 04:22:38 +02:00
import net.minecraft.client.Minecraft ;
2021-04-23 18:11:32 +02:00
import net.minecraft.client.gui.IGuiEventListener ;
2021-04-16 04:22:38 +02:00
import net.minecraft.client.gui.screen.Screen ;
2021-04-23 18:11:32 +02:00
import net.minecraft.util.text.ITextProperties ;
import net.minecraft.util.text.StringTextComponent ;
import net.minecraft.util.text.TextFormatting ;
2021-04-16 04:22:38 +02:00
import net.minecraftforge.common.ForgeConfigSpec ;
2021-04-23 18:11:32 +02:00
import net.minecraftforge.fml.config.ModConfig ;
2021-04-10 20:00:32 +02:00
public class SubMenuConfigScreen extends ConfigScreen {
2021-04-23 18:11:32 +02:00
public final ModConfig . Type type ;
protected ForgeConfigSpec spec ;
protected UnmodifiableConfig configGroup ;
protected ConfigScreenList list ;
2021-04-10 20:00:32 +02:00
2021-04-25 19:54:18 +02:00
protected BoxWidget resetAll ;
protected BoxWidget saveChanges ;
protected BoxWidget discardChanges ;
protected BoxWidget goBack ;
protected BoxWidget serverLocked ;
2021-04-23 18:11:32 +02:00
protected int listWidth ;
protected String title ;
2021-04-10 20:00:32 +02:00
2021-04-23 18:11:32 +02:00
public SubMenuConfigScreen ( Screen parent , String title , ModConfig . Type type , ForgeConfigSpec configSpec , UnmodifiableConfig configGroup ) {
2021-04-10 20:00:32 +02:00
super ( parent ) ;
2021-04-23 18:11:32 +02:00
this . type = type ;
2021-04-10 20:00:32 +02:00
this . spec = configSpec ;
2021-04-23 18:11:32 +02:00
this . title = title ;
2021-04-10 20:00:32 +02:00
this . configGroup = configGroup ;
}
2021-04-23 18:11:32 +02:00
public SubMenuConfigScreen ( Screen parent , ModConfig . Type type , ForgeConfigSpec configSpec ) {
2021-04-10 20:00:32 +02:00
super ( parent ) ;
2021-04-23 18:11:32 +02:00
this . type = type ;
2021-04-10 20:00:32 +02:00
this . spec = configSpec ;
2021-04-23 18:11:32 +02:00
this . title = " root " ;
2021-04-10 20:00:32 +02:00
this . configGroup = configSpec . getValues ( ) ;
}
2021-04-23 18:11:32 +02:00
protected void clearChanges ( ) {
changes . clear ( ) ;
list . children ( )
. stream ( )
. filter ( e - > e instanceof ValueEntry )
. forEach ( e - > ( ( ValueEntry < ? > ) e ) . onValueChange ( ) ) ;
}
protected void saveChanges ( ) {
UnmodifiableConfig values = spec . getValues ( ) ;
changes . forEach ( ( path , value ) - > {
ForgeConfigSpec . ConfigValue configValue = values . get ( path ) ;
configValue . set ( value ) ;
2021-04-27 02:48:50 +02:00
if ( type = = ModConfig . Type . SERVER ) {
AllPackets . channel . sendToServer ( new CConfigureConfigPacket < > ( path , value ) ) ;
}
2021-04-23 18:11:32 +02:00
} ) ;
clearChanges ( ) ;
}
protected void resetConfig ( UnmodifiableConfig values ) {
values . valueMap ( ) . forEach ( ( key , obj ) - > {
if ( obj instanceof AbstractConfig ) {
resetConfig ( ( UnmodifiableConfig ) obj ) ;
} else if ( obj instanceof ForgeConfigSpec . ConfigValue < ? > ) {
ForgeConfigSpec . ConfigValue < ? > configValue = ( ForgeConfigSpec . ConfigValue < ? > ) obj ;
ForgeConfigSpec . ValueSpec valueSpec = spec . getRaw ( configValue . getPath ( ) ) ;
if ( ! configValue . get ( ) . equals ( valueSpec . getDefault ( ) ) )
changes . put ( String . join ( " . " , configValue . getPath ( ) ) , valueSpec . getDefault ( ) ) ;
}
} ) ;
list . children ( )
. stream ( )
. filter ( e - > e instanceof ValueEntry )
. forEach ( e - > ( ( ValueEntry < ? > ) e ) . onValueChange ( ) ) ;
}
2021-04-10 20:00:32 +02:00
@Override
public void tick ( ) {
super . tick ( ) ;
list . tick ( ) ;
}
@Override
protected void init ( ) {
widgets . clear ( ) ;
super . init ( ) ;
2021-04-27 20:07:29 +02:00
listWidth = Math . min ( width - 80 , 300 ) ;
2021-04-23 18:11:32 +02:00
int yCenter = height / 2 ;
int listL = this . width / 2 - listWidth / 2 ;
int listR = this . width / 2 + listWidth / 2 ;
2021-04-25 19:54:18 +02:00
resetAll = new BoxWidget ( listR + 10 , yCenter - 25 , 20 , 20 )
2021-04-28 21:44:03 +02:00
. withPadding ( 2 , 2 )
2021-04-25 19:54:18 +02:00
. withCallback ( ( x , y ) - >
new ConfirmationScreen ( )
. at ( x , y )
. withText ( ITextProperties . plain ( " You are about to reset all settings for the " + type . toString ( ) + " config. Are you sure? " ) )
. withAction ( success - > {
if ( success )
resetConfig ( spec . getValues ( ) ) ;
} )
. open ( this )
) ;
2021-04-28 21:44:03 +02:00
resetAll . showingElement ( AllIcons . I_CONFIG_RESET . asStencil ( ) . withElementRenderer ( BoxWidget . gradientFactory . apply ( resetAll ) ) ) ;
2021-04-23 18:11:32 +02:00
resetAll . getToolTip ( ) . add ( new StringTextComponent ( " Reset All " ) ) ;
resetAll . getToolTip ( ) . addAll ( TooltipHelper . cutStringTextComponent ( " Click here to reset all configs to their default value. " , TextFormatting . GRAY , TextFormatting . GRAY ) ) ;
2021-04-25 19:54:18 +02:00
saveChanges = new BoxWidget ( listL - 30 , yCenter - 25 , 20 , 20 )
2021-04-28 21:44:03 +02:00
. withPadding ( 2 , 2 )
2021-04-25 19:54:18 +02:00
. withCallback ( ( x , y ) - > {
if ( changes . isEmpty ( ) )
return ;
new ConfirmationScreen ( )
. at ( x , y )
2021-05-03 18:25:57 +02:00
. withText ( ITextProperties . plain ( " You are about to change " + changes . size ( ) + " value " + ( changes . size ( ) ! = 1 ? " s " : " " ) + " . Are you sure? " ) )
2021-04-25 19:54:18 +02:00
. withAction ( success - > {
if ( success )
saveChanges ( ) ;
} )
. open ( this ) ;
} ) ;
2021-04-28 21:44:03 +02:00
saveChanges . showingElement ( AllIcons . I_CONFIG_SAVE . asStencil ( ) . withElementRenderer ( BoxWidget . gradientFactory . apply ( saveChanges ) ) ) ;
2021-04-23 18:11:32 +02:00
saveChanges . getToolTip ( ) . add ( new StringTextComponent ( " Save Changes " ) ) ;
saveChanges . getToolTip ( ) . addAll ( TooltipHelper . cutStringTextComponent ( " Click here to save your current changes. " , TextFormatting . GRAY , TextFormatting . GRAY ) ) ;
2021-04-25 19:54:18 +02:00
discardChanges = new BoxWidget ( listL - 30 , yCenter + 5 , 20 , 20 )
2021-04-28 21:44:03 +02:00
. withPadding ( 2 , 2 )
2021-04-25 19:54:18 +02:00
. withCallback ( ( x , y ) - > {
if ( changes . isEmpty ( ) )
return ;
new ConfirmationScreen ( )
. at ( x , y )
2021-05-03 18:25:57 +02:00
. withText ( ITextProperties . plain ( " You are about to discard " + changes . size ( ) + " unsaved change " + ( changes . size ( ) ! = 1 ? " s " : " " ) + " . Are you sure? " ) )
2021-04-25 19:54:18 +02:00
. withAction ( success - > {
if ( success )
clearChanges ( ) ;
} )
. open ( this ) ;
} ) ;
2021-04-28 21:44:03 +02:00
discardChanges . showingElement ( AllIcons . I_CONFIG_DISCARD . asStencil ( ) . withElementRenderer ( BoxWidget . gradientFactory . apply ( discardChanges ) ) ) ;
2021-04-23 18:11:32 +02:00
discardChanges . getToolTip ( ) . add ( new StringTextComponent ( " Discard Changes " ) ) ;
discardChanges . getToolTip ( ) . addAll ( TooltipHelper . cutStringTextComponent ( " Click here to discard all the changes you made. " , TextFormatting . GRAY , TextFormatting . GRAY ) ) ;
2021-04-25 19:54:18 +02:00
goBack = new BoxWidget ( listL - 30 , yCenter + 65 , 20 , 20 )
2021-04-28 21:44:03 +02:00
. withPadding ( 2 , 2 )
2021-04-25 19:54:18 +02:00
. withCallback ( this : : attemptBackstep ) ;
2021-04-28 21:44:03 +02:00
goBack . showingElement ( AllIcons . I_CONFIG_BACK . asStencil ( ) . withElementRenderer ( BoxWidget . gradientFactory . apply ( goBack ) ) ) ;
2021-04-23 18:11:32 +02:00
goBack . getToolTip ( ) . add ( new StringTextComponent ( " Go Back " ) ) ;
widgets . add ( resetAll ) ;
widgets . add ( saveChanges ) ;
widgets . add ( discardChanges ) ;
widgets . add ( goBack ) ;
2021-04-27 20:07:29 +02:00
list = new ConfigScreenList ( client , listWidth , height - 60 , 45 , height - 15 , 40 ) ;
2021-04-16 04:22:38 +02:00
list . setLeftPos ( this . width / 2 - list . getWidth ( ) / 2 ) ;
2021-04-10 20:00:32 +02:00
children . add ( list ) ;
2021-04-23 18:11:32 +02:00
configGroup . valueMap ( ) . forEach ( ( key , obj ) - > {
String humanKey = toHumanReadable ( key ) ;
2021-04-10 20:00:32 +02:00
2021-04-23 18:11:32 +02:00
if ( obj instanceof AbstractConfig ) {
SubMenuEntry entry = new SubMenuEntry ( this , humanKey , spec , ( UnmodifiableConfig ) obj ) ;
2021-04-10 20:00:32 +02:00
list . children ( ) . add ( entry ) ;
2021-04-23 18:11:32 +02:00
} else if ( obj instanceof ForgeConfigSpec . ConfigValue < ? > ) {
ForgeConfigSpec . ConfigValue < ? > configValue = ( ForgeConfigSpec . ConfigValue < ? > ) obj ;
2021-04-10 20:00:32 +02:00
ForgeConfigSpec . ValueSpec valueSpec = spec . getRaw ( configValue . getPath ( ) ) ;
Object value = configValue . get ( ) ;
2021-04-11 03:12:43 +02:00
if ( value instanceof Boolean ) {
BooleanEntry entry = new BooleanEntry ( humanKey , ( ForgeConfigSpec . ConfigValue < Boolean > ) configValue , valueSpec ) ;
list . children ( ) . add ( entry ) ;
2021-04-14 03:27:11 +02:00
} else if ( value instanceof Enum ) {
EnumEntry entry = new EnumEntry ( humanKey , ( ForgeConfigSpec . ConfigValue < Enum < ? > > ) configValue , valueSpec ) ;
list . children ( ) . add ( entry ) ;
2021-04-13 23:54:26 +02:00
} else if ( value instanceof Number ) {
NumberEntry < ? extends Number > entry = NumberEntry . create ( value , humanKey , configValue , valueSpec ) ;
if ( entry ! = null ) {
list . children ( ) . add ( entry ) ;
} else {
2021-04-23 18:11:32 +02:00
list . children ( ) . add ( new ConfigScreenList . LabeledEntry ( " n- " + obj . getClass ( ) . getSimpleName ( ) + " " + humanKey + " : " + value ) ) ;
2021-04-13 23:54:26 +02:00
}
2021-04-11 03:12:43 +02:00
} else {
list . children ( ) . add ( new ConfigScreenList . LabeledEntry ( humanKey + " : " + value ) ) ;
}
2021-04-10 20:00:32 +02:00
}
} ) ;
2021-04-23 18:11:32 +02:00
2021-04-25 19:54:18 +02:00
//extras for server configs
2021-04-23 18:11:32 +02:00
if ( type ! = ModConfig . Type . SERVER )
return ;
list . isForServer = true ;
boolean canEdit = client ! = null & & client . player ! = null & & client . player . hasPermissionLevel ( 2 ) ;
2021-04-28 21:44:03 +02:00
Couple < Color > red = Theme . p ( Theme . Key . BUTTON_FAIL ) ;
Couple < Color > green = Theme . p ( Theme . Key . BUTTON_SUCCESS ) ;
2021-04-23 18:11:32 +02:00
DelegatedStencilElement stencil = new DelegatedStencilElement ( ) ;
2021-04-25 19:54:18 +02:00
serverLocked = new BoxWidget ( listR + 10 , yCenter + 5 , 20 , 20 )
2021-04-28 21:44:03 +02:00
. withPadding ( 2 , 2 )
. showingElement ( stencil ) ;
2021-04-23 18:11:32 +02:00
if ( ! canEdit ) {
list . children ( ) . forEach ( e - > e . setEditable ( false ) ) ;
resetAll . active = false ;
2021-04-25 19:54:18 +02:00
stencil . withStencilRenderer ( ( ms , w , h , alpha ) - > AllIcons . I_CONFIG_LOCKED . draw ( ms , 0 , 0 ) ) ;
2021-04-28 21:44:03 +02:00
stencil . withElementRenderer ( ( ms , w , h , alpha ) - > UIRenderHelper . angledGradient ( ms , 90 , 8 , 0 , 16 , 16 , red ) ) ;
serverLocked . withBorderColors ( red ) ;
2021-04-23 18:11:32 +02:00
serverLocked . getToolTip ( ) . add ( new StringTextComponent ( " Locked " ) . formatted ( TextFormatting . BOLD ) ) ;
serverLocked . getToolTip ( ) . addAll ( TooltipHelper . cutStringTextComponent ( " You don't have enough permissions to edit the server config. You can still look at the current values here though. " , TextFormatting . GRAY , TextFormatting . GRAY ) ) ;
} else {
2021-04-25 19:54:18 +02:00
stencil . withStencilRenderer ( ( ms , w , h , alpha ) - > AllIcons . I_CONFIG_UNLOCKED . draw ( ms , 0 , 0 ) ) ;
2021-04-28 21:44:03 +02:00
stencil . withElementRenderer ( ( ms , w , h , alpha ) - > UIRenderHelper . angledGradient ( ms , 90 , 8 , 0 , 16 , 16 , green ) ) ;
serverLocked . withBorderColors ( green ) ;
2021-04-23 18:11:32 +02:00
serverLocked . getToolTip ( ) . add ( new StringTextComponent ( " Unlocked " ) . formatted ( TextFormatting . BOLD ) ) ;
2021-05-03 16:14:58 +02:00
serverLocked . getToolTip ( ) . addAll ( TooltipHelper . cutStringTextComponent ( " You have enough permissions to edit the server config. Changes you make here will be synced with the server when you save them. " , TextFormatting . GRAY , TextFormatting . GRAY ) ) ;
2021-04-23 18:11:32 +02:00
}
widgets . add ( serverLocked ) ;
2021-04-10 20:00:32 +02:00
}
@Override
protected void renderWindow ( MatrixStack ms , int mouseX , int mouseY , float partialTicks ) {
super . renderWindow ( ms , mouseX , mouseY , partialTicks ) ;
2021-04-23 18:11:32 +02:00
int x = width / 2 ;
2021-04-28 21:44:03 +02:00
drawCenteredString ( ms , client . fontRenderer , " Editing config: " + type . toString ( ) + " @ " + title , x , 15 , Theme . i ( Theme . Key . TEXT ) ) ;
2021-04-23 18:11:32 +02:00
2021-04-10 20:00:32 +02:00
list . render ( ms , mouseX , mouseY , partialTicks ) ;
}
2021-04-16 01:50:35 +02:00
@Override
protected void renderWindowForeground ( MatrixStack ms , int mouseX , int mouseY , float partialTicks ) {
super . renderWindowForeground ( ms , mouseX , mouseY , partialTicks ) ;
}
2021-04-10 20:00:32 +02:00
@Override
public void resize ( @Nonnull Minecraft client , int width , int height ) {
double scroll = list . getScrollAmount ( ) ;
init ( client , width , height ) ;
list . setScrollAmount ( scroll ) ;
}
2021-04-23 18:11:32 +02:00
@Nullable
@Override
public IGuiEventListener getFocused ( ) {
if ( ConfigScreenList . currentText ! = null )
return ConfigScreenList . currentText ;
return super . getFocused ( ) ;
}
@Override
public boolean keyPressed ( int code , int p_keyPressed_2_ , int p_keyPressed_3_ ) {
if ( super . keyPressed ( code , p_keyPressed_2_ , p_keyPressed_3_ ) )
return true ;
if ( code = = GLFW . GLFW_KEY_BACKSPACE ) {
attemptBackstep ( ) ;
}
return false ;
}
private void attemptBackstep ( ) {
if ( ! changes . isEmpty ( ) & & parent instanceof BaseConfigScreen ) {
new ConfirmationScreen ( )
. centered ( )
2021-05-03 18:25:57 +02:00
. addText ( ITextProperties . plain ( " You still have " + changes . size ( ) + " unsaved change " + ( changes . size ( ) ! = 1 ? " s " : " " ) + " for this config. " ) )
2021-04-23 18:11:32 +02:00
. addText ( ITextProperties . plain ( " Leaving this screen will discard them without saving. Are you sure? " ) )
. withAction ( success - > {
if ( ! success )
return ;
changes . clear ( ) ;
ScreenOpener . open ( parent ) ;
} )
. open ( this ) ;
} else {
ScreenOpener . open ( parent ) ;
}
}
@Override
public void onClose ( ) {
if ( changes . isEmpty ( ) ) {
super . onClose ( ) ;
return ;
}
new ConfirmationScreen ( )
. centered ( )
2021-05-03 18:25:57 +02:00
. addText ( ITextProperties . plain ( " You still have " + changes . size ( ) + " unsaved change " + ( changes . size ( ) ! = 1 ? " s " : " " ) + " for this config. " ) )
2021-04-23 18:11:32 +02:00
. addText ( ITextProperties . plain ( " Leaving this screen will discard them without saving. Are you sure? " ) )
. withAction ( success - > {
if ( ! success )
return ;
changes . clear ( ) ;
super . onClose ( ) ;
} )
. open ( this ) ;
}
2021-04-10 20:00:32 +02:00
}