From 96400966d709e2c2de487a8206730a2b1f026262 Mon Sep 17 00:00:00 2001 From: svitoos Date: Wed, 18 Sep 2019 20:32:14 +0300 Subject: [PATCH] - Add config (json5, jankson) - Add config gui (Cloth Config API and Mod Menu) --- build.gradle | 7 + .../dan200/computercraft/ComputerCraft.java | 3 + .../client/ModMenuIntegration.java | 23 ++ .../computercraft/client/gui/GuiConfig.java | 220 ++++++++++++++ .../computercraft/shared/util/Config.java | 282 ++++++++++++++++++ .../assets/computercraft/lang/en_us.json | 3 + src/main/resources/fabric.mod.json | 7 +- 7 files changed, 543 insertions(+), 2 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/ModMenuIntegration.java create mode 100644 src/main/java/dan200/computercraft/client/gui/GuiConfig.java create mode 100644 src/main/java/dan200/computercraft/shared/util/Config.java diff --git a/build.gradle b/build.gradle index 5512fd537..46fb5e804 100644 --- a/build.gradle +++ b/build.gradle @@ -56,8 +56,15 @@ dependencies { modCompile "net.fabricmc:fabric-loader:0.6.1+build.165" modCompile "net.fabricmc.fabric-api:fabric-api:0.3.2+build.226-1.14" + modImplementation "me.shedaniel.cloth:config-2:1.1.2" + modImplementation "io.github.prospector:modmenu:1.7.13+build.123" + + implementation "blue.endless:jankson:1.1.2" implementation 'com.google.code.findbugs:jsr305:3.0.2' + include "me.shedaniel.cloth:config-2:1.1.2" + include "blue.endless:jankson:1.1.0" + shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' shade 'javax.vecmath:vecmath:1.5.2' diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 1fc044cb4..b89534663 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -34,6 +34,7 @@ import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.*; +import dan200.computercraft.shared.util.Config; import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; @@ -44,6 +45,7 @@ import org.apache.logging.log4j.Logger; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Paths; import java.util.EnumSet; import java.util.concurrent.TimeUnit; @@ -196,6 +198,7 @@ public final class ComputerCraft implements ModInitializer @Override public void onInitialize() { + Config.load( Paths.get( FabricLoader.getInstance().getConfigDirectory().getPath(), MOD_ID + ".json5" ) ); ComputerCraftProxyCommon.setup(); if( FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT ) { diff --git a/src/main/java/dan200/computercraft/client/ModMenuIntegration.java b/src/main/java/dan200/computercraft/client/ModMenuIntegration.java new file mode 100644 index 000000000..207e217f9 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/ModMenuIntegration.java @@ -0,0 +1,23 @@ +package dan200.computercraft.client; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.GuiConfig; +import io.github.prospector.modmenu.api.ModMenuApi; +import net.minecraft.client.gui.screen.Screen; + +import java.util.function.Function; + +public class ModMenuIntegration implements ModMenuApi +{ + @Override + public Function getConfigScreenFactory() + { + return GuiConfig::getScreen; + } + + @Override + public String getModId() + { + return ComputerCraft.MOD_ID; + } +} diff --git a/src/main/java/dan200/computercraft/client/gui/GuiConfig.java b/src/main/java/dan200/computercraft/client/gui/GuiConfig.java new file mode 100644 index 000000000..53db385df --- /dev/null +++ b/src/main/java/dan200/computercraft/client/gui/GuiConfig.java @@ -0,0 +1,220 @@ +package dan200.computercraft.client.gui; + +import dan200.computercraft.core.apis.http.websocket.Websocket; +import dan200.computercraft.shared.util.Config; +import me.shedaniel.clothconfig2.api.ConfigBuilder; +import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import net.minecraft.client.gui.screen.Screen; + +import java.util.Arrays; + +public final class GuiConfig +{ + private GuiConfig() {} + + public static Screen getScreen( Screen parentScreen ) + { + Config config = Config.get(); + ConfigBuilder builder = ConfigBuilder.create().setParentScreen( parentScreen ).setTitle( "gui.computercraft.config.title" ).setSavingRunnable( () -> { + Config.save(); + Config.sync(); + } ); + + ConfigEntryBuilder entryBuilder = ConfigEntryBuilder.create(); + + builder.getOrCreateCategory( key( "general" ) ) + + .addEntry( entryBuilder.startIntField( key( "computer_space_limit" ), config.general.computer_space_limit ) + .setSaveConsumer( v -> config.general.computer_space_limit = v ) + .setDefaultValue( Config.defaultConfig.general.computer_space_limit ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "floppy_space_limit" ), config.general.floppy_space_limit ) + .setSaveConsumer( v -> config.general.floppy_space_limit = v ) + .setDefaultValue( Config.defaultConfig.general.floppy_space_limit ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "maximum_open_files" ), config.general.maximum_open_files ) + .setSaveConsumer( v -> config.general.maximum_open_files = v ) + .setDefaultValue( Config.defaultConfig.general.maximum_open_files ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startBooleanToggle( key( "disable_lua51_features" ), config.general.disable_lua51_features ) + .setSaveConsumer( v -> config.general.disable_lua51_features = v ) + .setDefaultValue( Config.defaultConfig.general.disable_lua51_features ) + .build() ) + + .addEntry( entryBuilder.startStrField( key( "default_computer_settings" ), config.general.default_computer_settings ) + .setSaveConsumer( v -> config.general.default_computer_settings = v ) + .setDefaultValue( Config.defaultConfig.general.default_computer_settings ) + .build() ) + + .addEntry( entryBuilder.startBooleanToggle( key( "debug_enabled" ), config.general.debug_enabled ) + .setSaveConsumer( v -> config.general.debug_enabled = v ) + .setDefaultValue( Config.defaultConfig.general.debug_enabled ) + .build() ) + + .addEntry( entryBuilder.startBooleanToggle( key( "log_computer_errors" ), config.general.log_computer_errors ) + .setSaveConsumer( v -> config.general.log_computer_errors = v ) + .setDefaultValue( Config.defaultConfig.general.log_computer_errors ) + .build() ); + + builder.getOrCreateCategory( key( "execution" ) ) + + .addEntry( entryBuilder.startIntField( key( "execution.computer_threads" ), config.execution.computer_threads ) + .setSaveConsumer( v -> config.execution.computer_threads = v ) + .setDefaultValue( Config.defaultConfig.execution.computer_threads ) + .setMin( 1 ) + .requireRestart() + .build() ) + + .addEntry( entryBuilder.startLongField( key( "execution.max_main_global_time" ), config.execution.max_main_global_time ) + .setSaveConsumer( v -> config.execution.max_main_global_time = v ) + .setDefaultValue( Config.defaultConfig.execution.max_main_global_time ) + .setMin( 1 ) + .build() ) + + .addEntry( entryBuilder.startLongField( key( "execution.max_main_computer_time" ), config.execution.max_main_computer_time ) + .setSaveConsumer( v -> config.execution.max_main_computer_time = v ) + .setDefaultValue( Config.defaultConfig.execution.max_main_computer_time ) + .setMin( 1 ) + .build() ); + + builder.getOrCreateCategory( key( "http" ) ) + + .addEntry( entryBuilder.startBooleanToggle( key( "http.enabled" ), config.http.enabled ) + .setSaveConsumer( v -> config.http.enabled = v ) + .setDefaultValue( Config.defaultConfig.http.enabled ) + .build() ) + + .addEntry( entryBuilder.startBooleanToggle( key( "http.websocket_enabled" ), config.http.websocket_enabled ) + .setSaveConsumer( v -> config.http.websocket_enabled = v ) + .setDefaultValue( Config.defaultConfig.http.websocket_enabled ) + .build() ) + + .addEntry( entryBuilder.startStrList( key( "http.whitelist" ), Arrays.asList( config.http.whitelist ) ) + .setSaveConsumer( v -> config.http.whitelist = v.toArray( new String[0] ) ) + .setDefaultValue( Arrays.asList( Config.defaultConfig.http.whitelist ) ) + .build() ) + + .addEntry( entryBuilder.startStrList( key( "http.blacklist" ), Arrays.asList( config.http.blacklist ) ) + .setSaveConsumer( v -> config.http.blacklist = v.toArray( new String[0] ) ) + .setDefaultValue( Arrays.asList( Config.defaultConfig.http.blacklist ) ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "http.timeout" ), config.http.timeout ) + .setSaveConsumer( v -> config.http.timeout = v ) + .setDefaultValue( Config.defaultConfig.http.timeout ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "http.max_requests" ), config.http.max_requests ) + .setSaveConsumer( v -> config.http.max_requests = v ) + .setDefaultValue( Config.defaultConfig.http.max_requests ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startLongField( key( "http.max_download" ), config.http.max_download ) + .setSaveConsumer( v -> config.http.max_download = v ) + .setDefaultValue( Config.defaultConfig.http.max_download ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startLongField( key( "http.max_upload" ), config.http.max_upload ) + .setSaveConsumer( v -> config.http.max_upload = v ) + .setDefaultValue( Config.defaultConfig.http.max_upload ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "http.max_websockets" ), config.http.max_websockets ) + .setSaveConsumer( v -> config.http.max_websockets = v ) + .setDefaultValue( Config.defaultConfig.http.max_websockets ) + .setMin( 1 ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "http.max_websocket_message" ), config.http.max_websocket_message ) + .setSaveConsumer( v -> config.http.max_websocket_message = v ) + .setDefaultValue( Config.defaultConfig.http.max_websocket_message ) + .setMin( 0 ) + .setMax( Websocket.MAX_MESSAGE_SIZE ) + .build() ); + + builder.getOrCreateCategory( key( "peripheral" ) ) + + .addEntry( entryBuilder.startBooleanToggle( key( "peripheral.command_block_enabled" ), config.peripheral.command_block_enabled ) + .setSaveConsumer( v -> config.peripheral.command_block_enabled = v ) + .setDefaultValue( Config.defaultConfig.peripheral.command_block_enabled ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "peripheral.modem_range" ), config.peripheral.modem_range ) + .setSaveConsumer( v -> config.peripheral.modem_range = v ) + .setDefaultValue( Config.defaultConfig.peripheral.modem_range ) + .setMin( 0 ) + .setMax( Config.MODEM_MAX_RANGE ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "peripheral.modem_high_altitude_range" ), config.peripheral.modem_high_altitude_range ) + .setSaveConsumer( v -> config.peripheral.modem_high_altitude_range = v ) + .setDefaultValue( Config.defaultConfig.peripheral.modem_high_altitude_range ) + .setMin( 0 ) + .setMax( Config.MODEM_MAX_RANGE ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "peripheral.modem_range_during_storm" ), config.peripheral.modem_range_during_storm ) + .setSaveConsumer( v -> config.peripheral.modem_range_during_storm = v ) + .setDefaultValue( Config.defaultConfig.peripheral.modem_range_during_storm ) + .setMin( 0 ) + .setMax( Config.MODEM_MAX_RANGE ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "peripheral.modem_high_altitude_range_during_storm" ), config.peripheral.modem_high_altitude_range_during_storm ) + .setSaveConsumer( v -> config.peripheral.modem_high_altitude_range_during_storm = v ) + .setDefaultValue( Config.defaultConfig.peripheral.modem_high_altitude_range_during_storm ) + .setMin( 0 ) + .setMax( Config.MODEM_MAX_RANGE ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "peripheral.max_notes_per_tick" ), config.peripheral.max_notes_per_tick ) + .setSaveConsumer( v -> config.peripheral.max_notes_per_tick = v ) + .setDefaultValue( Config.defaultConfig.peripheral.max_notes_per_tick ) + .setMin( 1 ) + .build() ); + + builder.getOrCreateCategory( key( "turtle" ) ) + + .addEntry( entryBuilder.startBooleanToggle( key( "turtle.need_fuel" ), config.turtle.need_fuel ) + .setSaveConsumer( v -> config.turtle.need_fuel = v ) + .setDefaultValue( Config.defaultConfig.turtle.need_fuel ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "turtle.normal_fuel_limit" ), config.turtle.normal_fuel_limit ) + .setSaveConsumer( v -> config.turtle.normal_fuel_limit = v ) + .setDefaultValue( Config.defaultConfig.turtle.normal_fuel_limit ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startIntField( key( "turtle.advanced_fuel_limit" ), config.turtle.advanced_fuel_limit ) + .setSaveConsumer( v -> config.turtle.advanced_fuel_limit = v ) + .setDefaultValue( Config.defaultConfig.turtle.advanced_fuel_limit ) + .setMin( 0 ) + .build() ) + + .addEntry( entryBuilder.startBooleanToggle( key( "turtle.obey_block_protection" ), config.turtle.obey_block_protection ) + .setSaveConsumer( v -> config.turtle.obey_block_protection = v ) + .setDefaultValue( Config.defaultConfig.turtle.obey_block_protection ) + .build() ) + + .addEntry( entryBuilder.startStrList( key( "turtle.disabled_actions" ), Arrays.asList( config.turtle.disabled_actions ) ) + .setSaveConsumer( v -> config.turtle.disabled_actions = v.toArray( new String[0] ) ) + .setDefaultValue( Arrays.asList( Config.defaultConfig.turtle.disabled_actions ) ) + .build() ); + + return builder.build(); + } + + private static String key( String name ) + { + return "gui.computercraft.config." + name; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java new file mode 100644 index 000000000..d4851f6fc --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -0,0 +1,282 @@ +package dan200.computercraft.shared.util; + +import blue.endless.jankson.Comment; +import blue.endless.jankson.Jankson; +import blue.endless.jankson.JsonObject; +import blue.endless.jankson.impl.SyntaxError; +import com.google.common.base.CaseFormat; +import com.google.common.base.Converter; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.event.TurtleAction; +import dan200.computercraft.core.apis.AddressPredicate; +import dan200.computercraft.core.apis.http.websocket.Websocket; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; + +public class Config +{ + public static final transient int MODEM_MAX_RANGE = 100000; + + public General general = new General(); + + @Comment( "\nControls execution behaviour of computers. This is largely intended for fine-tuning " + + "servers, and generally shouldn't need to be touched" ) + public Execution execution = new Execution(); + + @Comment( "\nControls the HTTP API" ) + public Http http = new Http(); + + @Comment( "\nVarious options relating to peripherals." ) + public Peripheral peripheral = new Peripheral(); + + @Comment( "\nVarious options relating to turtles." ) + public Turtle turtle = new Turtle(); + + public static class General + { + @Comment( "\nThe disk space limit for computers and turtles, in bytes" ) + public int computer_space_limit = ComputerCraft.computerSpaceLimit; + + @Comment( "\nThe disk space limit for floppy disks, in bytes" ) + public int floppy_space_limit = ComputerCraft.floppySpaceLimit; + + @Comment( "\nSet how many files a computer can have open at the same time. Set to 0 for unlimited." ) + public int maximum_open_files = ComputerCraft.maximumFilesOpen; + + @Comment( "\nSet this to true to disable Lua 5.1 functions that will be removed in a future " + + "update. Useful for ensuring forward compatibility of your programs now." ) + public boolean disable_lua51_features = ComputerCraft.disable_lua51_features; + + @Comment( "\nA comma separated list of default system settings to set on new computers. Example: " + + "\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all autocompletion" ) + public String default_computer_settings = ComputerCraft.default_computer_settings; + + @Comment( "\nEnable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." ) + public boolean debug_enabled = ComputerCraft.debug_enable; + + @Comment( "\nLog exceptions thrown by peripherals and other Lua objects.\n" + + "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ) + public boolean log_computer_errors = ComputerCraft.logPeripheralErrors; + } + + public static class Execution + { + @Comment( "\nSet the number of threads computers can run on. A higher number means more computers can " + + "run at once, but may induce lag.\n" + + "Please note that some mods may not work with a thread count higher than 1. Use with caution." ) + public int computer_threads = ComputerCraft.computer_threads; + + @Comment( "\nThe maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" + + "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " + + "to be the upper bound of the average time." ) + public long max_main_global_time = (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainGlobalTime ); + + @Comment( "\nThe ideal maximum time a computer can execute for in a tick, in milliseconds.\n" + + "Note, we will quite possibly go over this limit, as there's no way to tell how long a will take - this aims " + + "to be the upper bound of the average time." ) + public long max_main_computer_time = (int) TimeUnit.NANOSECONDS.toMillis( ComputerCraft.maxMainComputerTime ); + } + + public static class Http + { + @Comment( "\nEnable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for " + + "more fine grained control than this)" ) + public boolean enabled = ComputerCraft.http_enable; + + @Comment( "\nEnable use of http websockets. This requires the \"http_enable\" option to also be true." ) + public boolean websocket_enabled = ComputerCraft.http_websocket_enable; + + @Comment( "\nA list of wildcards for domains or IP ranges that can be accessed through the " + + "\"http\" API on Computers.\n" + + "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to " + + "just subdomains of pastebin.com.\n" + + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) + public String[] whitelist = ComputerCraft.DEFAULT_HTTP_WHITELIST.clone(); + + @Comment( "\nA list of wildcards for domains or IP ranges that cannot be accessed through the " + + "\"http\" API on Computers.\n" + + "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block " + + "access to all subdomains of github.com.\n" + + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) + public String[] blacklist = ComputerCraft.DEFAULT_HTTP_BLACKLIST.clone(); + + @Comment( "\nThe period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) + public int timeout = ComputerCraft.httpTimeout; + + @Comment( "\nThe number of http requests a computer can make at one time. Additional requests " + + "will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ) + public int max_requests = ComputerCraft.httpMaxRequests; + + @Comment( "\nThe maximum size (in bytes) that a computer can download in a single request. " + + "Note that responses may receive more data than allowed, but this data will not be returned to the client." ) + public long max_download = ComputerCraft.httpMaxDownload; + + @Comment( "\nThe maximum size (in bytes) that a computer can upload in a single request. This " + + "includes headers and POST text." ) + public long max_upload = ComputerCraft.httpMaxUpload; + + @Comment( "\nThe number of websockets a computer can have open at one time. Set to 0 for unlimited." ) + public int max_websockets = ComputerCraft.httpMaxWebsockets; + + @Comment( "\nThe maximum size (in bytes) that a computer can send or receive in one websocket packet." ) + public int max_websocket_message = ComputerCraft.httpMaxWebsocketMessage; + } + + public static class Peripheral + { + @Comment( "\n\nEnable Command Block peripheral support" ) + public boolean command_block_enabled = ComputerCraft.enableCommandBlock; + + @Comment( "\nThe range of Wireless Modems at low altitude in clear weather, in meters" ) + public int modem_range = ComputerCraft.modem_range; + + @Comment( "\nThe range of Wireless Modems at maximum altitude in clear weather, in meters" ) + public int modem_high_altitude_range = ComputerCraft.modem_highAltitudeRange; + + @Comment( "\nThe range of Wireless Modems at low altitude in stormy weather, in meters" ) + public int modem_range_during_storm = ComputerCraft.modem_rangeDuringStorm; + + @Comment( "\nThe range of Wireless Modems at maximum altitude in stormy weather, in meters" ) + public int modem_high_altitude_range_during_storm = ComputerCraft.modem_highAltitudeRangeDuringStorm; + + @Comment( "\nMaximum amount of notes a speaker can play at once" ) + public int max_notes_per_tick = ComputerCraft.maxNotesPerTick; + } + + public static class Turtle + { + @Comment( "\nSet whether Turtles require fuel to move" ) + public boolean need_fuel = ComputerCraft.turtlesNeedFuel; + + @Comment( "\nThe fuel limit for Turtles" ) + public int normal_fuel_limit = ComputerCraft.turtleFuelLimit; + + @Comment( "\nThe fuel limit for Advanced Turtles" ) + public int advanced_fuel_limit = ComputerCraft.advancedTurtleFuelLimit; + + @Comment( "\nIf set to true, Turtles will be unable to build, dig, or enter protected " + + "areas (such as near the server spawn point)" ) + public boolean obey_block_protection = ComputerCraft.turtlesObeyBlockProtection; + + @Comment( "\nIf set to true, Turtles will push entities out of the way instead of stopping if " + + "there is space to do so" ) + public boolean can_push = ComputerCraft.turtlesCanPush; + + @Comment( "\nA list of turtle actions which are disabled." ) + public String[] disabled_actions = new String[0]; + } + + private static transient Path configPath; + private static transient Config config; + public static final transient Config defaultConfig = new Config(); + + public static Config get() + { + return config; + } + + public static void load( Path path ) + { + configPath = path; + + if( Files.exists( configPath ) ) + { + Jankson jankson = Jankson.builder().build(); + try + { + JsonObject jsonObject = jankson.load( Files.newInputStream( configPath ) ); + config = jankson.fromJson( jsonObject, Config.class ); + } + catch( IOException | SyntaxError e ) + { + config = new Config(); + ComputerCraft.log.error( "Failed to load config! Use default config." ); + e.printStackTrace(); + return; + } + } + else + { + config = new Config(); + } + save(); + sync(); + } + + public static void save() + { + Jankson jankson = Jankson.builder().build(); + try + { + String configData = jankson.toJson( config ).toJson( true, true ); + Files.write( configPath, configData.getBytes() ); + } + catch( IOException e ) + { + ComputerCraft.log.error( "Failed to save config!" ); + e.printStackTrace(); + } + } + + public static void sync() + { + // General + ComputerCraft.computerSpaceLimit = config.general.computer_space_limit; + ComputerCraft.floppySpaceLimit = config.general.floppy_space_limit; + ComputerCraft.maximumFilesOpen = Math.max( 0, config.general.maximum_open_files ); + ComputerCraft.disable_lua51_features = config.general.disable_lua51_features; + ComputerCraft.default_computer_settings = config.general.default_computer_settings; + ComputerCraft.debug_enable = config.general.debug_enabled; + ComputerCraft.logPeripheralErrors = config.general.log_computer_errors; + + // Execution + ComputerCraft.computer_threads = Math.max( 1, config.execution.computer_threads ); + ComputerCraft.maxMainGlobalTime = Math.max( 1, config.execution.max_main_global_time ); + ComputerCraft.maxMainComputerTime = Math.max( 1, config.execution.max_main_computer_time ); + + // HTTP + ComputerCraft.http_enable = config.http.enabled; + ComputerCraft.http_websocket_enable = config.http.websocket_enabled; + ComputerCraft.http_whitelist = new AddressPredicate( config.http.whitelist ); + ComputerCraft.http_blacklist = new AddressPredicate( config.http.blacklist ); + + ComputerCraft.httpTimeout = Math.max( 0, config.http.timeout ); + ComputerCraft.httpMaxRequests = Math.max( 1, config.http.max_requests ); + ComputerCraft.httpMaxDownload = Math.max( 0, config.http.max_download ); + ComputerCraft.httpMaxUpload = Math.max( 0, config.http.max_upload ); + ComputerCraft.httpMaxWebsockets = Math.max( 1, config.http.max_websockets ); + ComputerCraft.httpMaxWebsocketMessage = Math.min( Math.max( 0, config.http.max_websocket_message ), Websocket.MAX_MESSAGE_SIZE ); + + // Peripheral + ComputerCraft.enableCommandBlock = config.peripheral.command_block_enabled; + ComputerCraft.maxNotesPerTick = Math.max( 1, config.peripheral.max_notes_per_tick ); + ComputerCraft.modem_range = Math.min( Math.max( 0, config.peripheral.modem_range ), MODEM_MAX_RANGE ); + ComputerCraft.modem_highAltitudeRange = Math.min( Math.max( 0, config.peripheral.modem_high_altitude_range ), MODEM_MAX_RANGE ); + ComputerCraft.modem_rangeDuringStorm = Math.min( Math.max( 0, config.peripheral.modem_range_during_storm ), MODEM_MAX_RANGE ); + ComputerCraft.modem_highAltitudeRangeDuringStorm = Math.min( Math.max( 0, config.peripheral.modem_high_altitude_range_during_storm ), MODEM_MAX_RANGE ); + + // Turtles + ComputerCraft.turtlesNeedFuel = config.turtle.need_fuel; + ComputerCraft.turtleFuelLimit = Math.max( 0, config.turtle.normal_fuel_limit ); + ComputerCraft.advancedTurtleFuelLimit = Math.max( 0, config.turtle.advanced_fuel_limit ); + ComputerCraft.turtlesObeyBlockProtection = config.turtle.obey_block_protection; + ComputerCraft.turtlesCanPush = config.turtle.can_push; + + ComputerCraft.turtleDisabledActions.clear(); + Converter converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE ); + for( String value : config.turtle.disabled_actions ) + { + try + { + ComputerCraft.turtleDisabledActions.add( TurtleAction.valueOf( converter.convert( value ) ) ); + } + catch( IllegalArgumentException e ) + { + ComputerCraft.log.error( "Unknown turtle action " + value ); + } + } + } +} diff --git a/src/main/resources/assets/computercraft/lang/en_us.json b/src/main/resources/assets/computercraft/lang/en_us.json index 8dd1bc9f0..b9494d46e 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.json +++ b/src/main/resources/assets/computercraft/lang/en_us.json @@ -146,6 +146,9 @@ "gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", "gui.computercraft.tooltip.disk_id": "(Disk ID: %s)", + "gui.computercraft.config.title": "CC:T for Fabric", + + "gui.computercraft.config.general": "General", "gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)", "gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)", "gui.computercraft.config.maximum_open_files": "Maximum files open per computer", diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 409f5130f..a1fd56110 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,10 +21,13 @@ "fabricloader": ">=0.4.0", "fabric": "*" }, - + "suggests": { + "modmenu": "*" + }, "environment": "*", "entrypoints": { - "main": [ "dan200.computercraft.ComputerCraft" ] + "main": [ "dan200.computercraft.ComputerCraft" ], + "modmenu": [ "dan200.computercraft.client.ModMenuIntegration" ] }, "mixins": [ { "config": "computercraft.client.json", "environment": "client" },