diff --git a/.gitignore b/.gitignore index eb32fe5f..4545d0dc 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ forge/src/main/java/**/mod forge/src/main/java/net/londonunderground/mod forge/src/main/resources/assets forge/src/main/resources/data +forge/run #forge/src/main/resources/META-INF # java diff --git a/fabric/src/main/java/com/lx862/jcm/mixin/compat/SimpleDefaultedRegistryMixin.java b/fabric/src/main/java/com/lx862/jcm/mixin/compat/SimpleDefaultedRegistryMixin.java index 0d0c4569..24866135 100644 --- a/fabric/src/main/java/com/lx862/jcm/mixin/compat/SimpleDefaultedRegistryMixin.java +++ b/fabric/src/main/java/com/lx862/jcm/mixin/compat/SimpleDefaultedRegistryMixin.java @@ -19,6 +19,7 @@ * See <a href="https://github.com/Noaaan/MythicMetals/blob/1.20/src/main/java/nourl/mythicmetals/mixin/DefaultedRegistryMixin.java">here</a> * And <a href="https://github.com/orgs/FabricMC/discussions/2361">https://github.com/orgs/FabricMC/discussions/2361</a> */ + #if MC_VERSION < "11904" @Mixin(DefaultedRegistry.class) #else diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/PIDSManager.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/PIDSManager.java index 3a990e6c..e831c69c 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/PIDSManager.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/PIDSManager.java @@ -59,4 +59,4 @@ public static List<PIDSPresetBase> getCustomPresets() { public static void reset() { presetList.entrySet().stream().filter(e -> !e.getValue().builtin).collect(Collectors.toList()).clear(); } -} +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/CustomComponentPIDSPreset.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/CustomComponentPIDSPreset.java index 68cfda4a..4084e198 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/CustomComponentPIDSPreset.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/CustomComponentPIDSPreset.java @@ -10,6 +10,7 @@ import com.lx862.jcm.mod.data.pids.preset.components.base.TextureComponent; import com.lx862.jcm.mod.render.text.TextRenderingManager; import com.lx862.jcm.mod.util.JCMLogger; +import org.apache.commons.lang3.NotImplementedException; import org.mtr.core.operation.ArrivalResponse; import org.mtr.libraries.it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.mtr.mapping.holder.BlockPos; @@ -40,7 +41,10 @@ public static CustomComponentPIDSPreset parse(JsonObject rootJsonObject) { } boolean builtin = rootJsonObject.has("builtin") && rootJsonObject.get("builtin").getAsBoolean(); - String componentFile = ResourceManagerHelper.readResource(new Identifier(rootJsonObject.get("file").getAsString())); + Identifier componentFileLocation = Identifier.tryParse(rootJsonObject.get("file").getAsString()); + if(componentFileLocation == null) return null; + + String componentFile = ResourceManagerHelper.readResource(componentFileLocation); JsonArray jsonArray = new JsonParser().parse(componentFile).getAsJsonArray(); CustomComponentPIDSPreset preset = new CustomComponentPIDSPreset(id, name, builtin); @@ -96,4 +100,11 @@ public int getTextColor() { public boolean isRowHidden(int row) { return false; } + + @Override + public JsonObject toJson() { + JsonObject jsonObject = super.toJson(); + jsonObject.addProperty("TODO", "TODO"); + return jsonObject; + } } diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/JsonPIDSPreset.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/JsonPIDSPreset.java index d7de8007..20118f8c 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/JsonPIDSPreset.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/JsonPIDSPreset.java @@ -201,4 +201,4 @@ public int getTextColor() { public boolean isRowHidden(int row) { return rowHidden.length - 1 < row ? false : rowHidden[row]; } -} +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/MutableJsonPIDSPreset.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/MutableJsonPIDSPreset.java new file mode 100644 index 00000000..74eea0e1 --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/MutableJsonPIDSPreset.java @@ -0,0 +1,45 @@ +package com.lx862.jcm.mod.data.pids.preset; + +import com.lx862.jcm.mod.render.TextOverflowMode; +import org.mtr.mapping.holder.Identifier; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class MutableJsonPIDSPreset extends JsonPIDSPreset { + public MutableJsonPIDSPreset(String id, @Nullable String name, @Nonnull Identifier background, @Nullable String fontId, TextOverflowMode textOverflowMode, boolean[] rowHidden, boolean showClock, boolean showWeather, boolean topPadding, int textColor) { + super(id, name, background, fontId, textOverflowMode, rowHidden, showClock, showWeather, topPadding, textColor); + } + + public void setId(String id) { + this.id = id; + } + + public void setName(String name) { + this.id = name; + } + + public void setShowWeather(boolean newShowWeather) { + showWeather = newShowWeather; + } + + public void setShowClock(boolean newShowClock) { + showClock = newShowClock; + } + + public void setBackground(Identifier newBackground) { + background = newBackground; + } + + public void setTopPadding(boolean newTopPadding) { + topPadding = newTopPadding; + } + + public void setColor(int newColor) { + textColor = newColor; + } + + public void setRowHidden(int i, boolean bool) { + rowHidden[i] = bool; + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/PIDSPresetBase.java b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/PIDSPresetBase.java index 854954f3..16da56b4 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/PIDSPresetBase.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/data/pids/preset/PIDSPresetBase.java @@ -1,5 +1,6 @@ package com.lx862.jcm.mod.data.pids.preset; +import com.google.gson.JsonObject; import com.lx862.jcm.mod.block.entity.PIDSBlockEntity; import com.lx862.jcm.mod.data.pids.preset.components.base.PIDSComponent; import com.lx862.jcm.mod.render.RenderHelper; @@ -18,8 +19,8 @@ import java.util.List; public abstract class PIDSPresetBase implements RenderHelper { - private final String id; - private final String name; + protected String id; + protected String name; public final boolean builtin; public PIDSPresetBase(String id, @Nullable String name, boolean builtin) { this.id = id; @@ -47,6 +48,13 @@ public void drawAtlasBackground(GraphicsHolder graphicsHolder, int width, int he RenderHelper.drawTexture(graphicsHolder,0, height, 0, width, width, facing, ARGB_WHITE, MAX_RENDER_LIGHT); } + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("id", id); + jsonObject.addProperty("name", name == null ? id : name); + return jsonObject; + } + public abstract List<PIDSComponent> getComponents(ObjectArrayList<ArrivalResponse> arrivals, String[] customMessages, boolean[] rowHidden, int x, int y, int screenWidth, int screenHeight, int rows, boolean hidePlatform); public abstract String getFont(); public abstract @Nonnull Identifier getBackground(); diff --git a/fabric/src/main/java/com/lx862/jcm/mod/registry/Blocks.java b/fabric/src/main/java/com/lx862/jcm/mod/registry/Blocks.java index c70f9a4b..f4170a71 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/registry/Blocks.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/registry/Blocks.java @@ -5,6 +5,7 @@ import com.lx862.jcm.mod.util.BlockUtil; import com.lx862.jcm.mod.util.JCMLogger; import org.mtr.mapping.holder.Block; +import org.mtr.mapping.holder.Property; import org.mtr.mapping.holder.RenderLayer; import org.mtr.mapping.mapper.BlockHelper; import org.mtr.mapping.registry.BlockRegistryObject; @@ -50,7 +51,6 @@ public final class Blocks { if (isLit) return 15; else return 0; }).nonOpaque())), ItemGroups.JCM_MAIN); - public static final BlockRegistryObject SUBSIDY_MACHINE = RegistryHelper.registerBlockItem("subsidy_machine", () -> new Block(new SubsidyMachineBlock(BlockHelper.createBlockSettings(false).nonOpaque())), ItemGroups.JCM_MAIN); public static final BlockRegistryObject SOUND_LOOPER = RegistryHelper.registerBlockItem("sound_looper", () -> new Block(new SoundLooperBlock(BlockHelper.createBlockSettings(false))), ItemGroups.JCM_MAIN); public static final BlockRegistryObject STATION_NAME_STANDING = RegistryHelper.registerBlockItem("station_name_standing", () -> new Block(new StationNameStandingBlock(BlockHelper.createBlockSettings(false).strength(4.0f).nonOpaque())), ItemGroups.JCM_MAIN); diff --git a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreen.java b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreen.java new file mode 100644 index 00000000..a52924c0 --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreen.java @@ -0,0 +1,168 @@ +package com.lx862.jcm.mod.render.gui.screen; + +import com.google.gson.*; +import com.lx862.jcm.mod.Constants; +import com.lx862.jcm.mod.data.pids.PIDSManager; +import com.lx862.jcm.mod.data.pids.preset.PIDSPresetBase; +import com.lx862.jcm.mod.render.GuiHelper; +import com.lx862.jcm.mod.render.RenderHelper; +import com.lx862.jcm.mod.render.gui.screen.base.TitledScreen; +import com.lx862.jcm.mod.render.gui.widget.ContentItem; +import com.lx862.jcm.mod.render.gui.widget.HorizontalWidgetSet; +import com.lx862.jcm.mod.render.gui.widget.ListViewWidget; +import com.lx862.jcm.mod.render.gui.widget.MappedWidget; +import com.lx862.jcm.mod.resources.JCMResourceManager; +import com.lx862.jcm.mod.util.JCMLogger; +import com.lx862.jcm.mod.util.TextCategory; +import com.lx862.jcm.mod.util.TextUtil; +import org.mtr.mapping.holder.*; +import org.mtr.mapping.mapper.ButtonWidgetExtension; +import org.mtr.mapping.mapper.GuiDrawing; + +import java.io.File; +import java.io.FileReader; + +public class EditorSaveScreen extends TitledScreen implements RenderHelper, GuiHelper { + private static final Identifier PIDS_PREVIEW_BASE = new Identifier("jsblock:textures/gui/pids_preview.png"); + private final File resourcePackFolder; + private final ListViewWidget listViewWidget; + private final PIDSPresetBase oldPreset; + private final PIDSPresetBase newPreset; + private final String associatedRP; + private final Screen previousScreen; + public EditorSaveScreen(PIDSPresetBase oldPreset, PIDSPresetBase newPreset, Screen previousScreen) { + super(false); + this.resourcePackFolder = new File(org.mtr.mapping.holder.MinecraftClient.getInstance().getRunDirectoryMapped(), "resourcepacks"); + this.listViewWidget = new ListViewWidget(); + this.newPreset = newPreset; + this.oldPreset = oldPreset; + this.associatedRP = getAssociatedResourcePack(this.oldPreset.getId()); + this.previousScreen = previousScreen; + } + + @Override + protected void init2() { + super.init2(); + int contentWidth = (int)Math.min((width * 0.75), MAX_CONTENT_WIDTH); + int listViewHeight = (int)((height - 60) * 0.76); + int startX = (width - contentWidth) / 2; + int startY = TEXT_PADDING * 6; + + listViewWidget.reset(); + addConfigEntries(); + listViewWidget.setXYSize(startX, startY, contentWidth, listViewHeight); + addChild(new ClickableWidget(listViewWidget)); +// +// if(associatedRP == null) { +// openSaveAsScreen(); +// } + } + + @Override + public MutableText getScreenTitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.title"); + } + + @Override + public MutableText getScreenSubtitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_save.subtitle", newPreset.getId()); + } + + public void addConfigEntries() { + listViewWidget.addCategory(TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.category.save_edits")); + addResourcePackListing(PIDSManager.getPreset(newPreset.getId())); + } + + private void addResourcePackListing(PIDSPresetBase preset) { + if(associatedRP == null) return; + + ButtonWidgetExtension saveBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.save"), (btn) -> { + onClose2(); + }); + + ButtonWidgetExtension saveAsBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.saveas"), (btn) -> openSaveAsScreen()); + + HorizontalWidgetSet widgetSet = new HorizontalWidgetSet(); + widgetSet.addWidget(new MappedWidget(saveBtn)); + widgetSet.setXYSize(0, 0, 100, 20); + + HorizontalWidgetSet widgetSet2 = new HorizontalWidgetSet(); + widgetSet2.addWidget(new MappedWidget(saveAsBtn)); + widgetSet2.setXYSize(0, 0, 100, 20); + + addChild(new ClickableWidget(saveBtn)); + addChild(new ClickableWidget(saveAsBtn)); + addChild(new ClickableWidget(widgetSet)); + addChild(new ClickableWidget(widgetSet2)); + ContentItem contentItem = new ContentItem(TextUtil.literal(associatedRP), new MappedWidget(widgetSet), 26); + ContentItem contentItem2 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.title.saveas"), new MappedWidget(widgetSet2), 26); + + contentItem.setIconCallback((guiDrawing, startX, startY, width, height) -> { + drawPIDSPreview(preset, guiDrawing, startX, startY, width, height, false); + }); + listViewWidget.add(contentItem); + listViewWidget.add(contentItem2); + } + + private void openSaveAsScreen() { + MinecraftClient.getInstance().openScreen( + new Screen(new EditorSaveScreenExtended(oldPreset, newPreset, previousScreen).withPreviousScreen(new Screen(this))) + ); + } + + public static void drawPIDSPreview(PIDSPresetBase preset, GuiDrawing guiDrawing, int startX, int startY, int width, int height, boolean backgroundOnly) { + final int offset = 6; + + GuiHelper.drawTexture(guiDrawing, PIDS_PREVIEW_BASE, startX, startY, width, height); + if(preset == null) return; + + GuiHelper.drawTexture(guiDrawing, preset.getBackground(), startX+0.5, startY+offset+0.5, width-1, height-offset-4); + + if(!backgroundOnly) { + double perRow = height / 8.5; + double rowHeight = Math.max(0.5, height / 24.0); + for(int i = 0; i < 4; i++) { + if(preset.isRowHidden(i)) continue; + double curY = startY + offset + ((i+1) * perRow); + GuiHelper.drawRectangle(guiDrawing, startX+1.5, curY, width * 0.55, rowHeight, preset.getTextColor()); + GuiHelper.drawRectangle(guiDrawing, startX + (width * 0.65), curY, rowHeight, rowHeight, preset.getTextColor()); + GuiHelper.drawRectangle(guiDrawing, startX + (width * 0.75), curY, (width * 0.2)-0.5, rowHeight, preset.getTextColor()); + } + } + } + + private String getAssociatedResourcePack(String targetPresetId) { + for(File file : resourcePackFolder.listFiles()) { + if(file.isDirectory()) { + File jsonFile = resourcePackFolder.toPath().resolve(file.getName()).resolve("assets").resolve(Constants.MOD_ID).resolve("joban_custom_resources.json").toFile(); + if(jsonFile.exists()) { + JsonArray presetsInRP; + try { + presetsInRP = new JsonParser().parse(new FileReader(jsonFile)).getAsJsonObject().get("pids_images").getAsJsonArray(); + } catch (Exception e) { + JCMLogger.debug("Cannot read PIDS Preset from Resource Pack!"); + continue; + } + + for(int i = 0; i < presetsInRP.size(); i++) { + PIDSPresetBase pidsPreset = PIDSManager.parsePreset(presetsInRP.get(i).getAsJsonObject()); + if(pidsPreset != null && pidsPreset.getId().equals(oldPreset.getId())) { + return file.getName(); + } + } + } + } + } + return null; + } + + @Override + public void onClose2() { + if(associatedRP != null) { + JCMResourceManager.updatePresetInResourcePack(oldPreset, newPreset, associatedRP); + JCMResourceManager.reloadResources(); + } + + super.onClose2(); + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreenExtended.java b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreenExtended.java new file mode 100644 index 00000000..b114ef8e --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/EditorSaveScreenExtended.java @@ -0,0 +1,158 @@ +package com.lx862.jcm.mod.render.gui.screen; + +import com.lx862.jcm.mod.Constants; +import com.lx862.jcm.mod.data.pids.PIDSManager; +import com.lx862.jcm.mod.data.pids.preset.PIDSPresetBase; +import com.lx862.jcm.mod.render.GuiHelper; +import com.lx862.jcm.mod.render.RenderHelper; +import com.lx862.jcm.mod.render.gui.screen.base.TitledScreen; +import com.lx862.jcm.mod.render.gui.widget.ContentItem; +import com.lx862.jcm.mod.render.gui.widget.HorizontalWidgetSet; +import com.lx862.jcm.mod.render.gui.widget.ListViewWidget; +import com.lx862.jcm.mod.render.gui.widget.MappedWidget; +import com.lx862.jcm.mod.resources.JCMResourceManager; +import com.lx862.jcm.mod.util.TextCategory; +import com.lx862.jcm.mod.util.TextUtil; +import org.mtr.mapping.holder.*; +import org.mtr.mapping.mapper.ButtonWidgetExtension; +import org.mtr.mapping.mapper.GuiDrawing; +import org.mtr.mapping.mapper.TextFieldWidgetExtension; +import org.mtr.mapping.tool.TextCase; + +import java.io.File; + +public class EditorSaveScreenExtended extends TitledScreen implements RenderHelper, GuiHelper { + private static final Identifier PIDS_PREVIEW_BASE = new Identifier("jsblock:textures/gui/pids_preview.png"); + private final TextFieldWidgetExtension searchBox; + private final File resourcePackFolder; + private final ListViewWidget listViewWidget; + private final PIDSPresetBase newPreset; + private final PIDSPresetBase oldPreset; + private final Screen previousScreen; + public EditorSaveScreenExtended(PIDSPresetBase oldPreset, PIDSPresetBase newPreset, Screen previousScreen) { + super(false); + this.resourcePackFolder = new File(org.mtr.mapping.holder.MinecraftClient.getInstance().getRunDirectoryMapped(), "resourcepacks"); + this.listViewWidget = new ListViewWidget(); + this.searchBox = new TextFieldWidgetExtension(0, 0, 0, 22, 60, TextCase.DEFAULT, null, TextUtil.translatable(TextCategory.GUI, "widget.search").getString()); + this.newPreset = newPreset; + this.oldPreset = oldPreset; + this.previousScreen = previousScreen; + } + + @Override + protected void init2() { + super.init2(); + int contentWidth = (int)Math.min((width * 0.75), MAX_CONTENT_WIDTH); + int listViewHeight = (int)((height - 60) * 0.76); + int startX = (width - contentWidth) / 2; + int searchStartY = TEXT_PADDING * 5; + int startY = searchStartY + (TEXT_PADDING * 3); + + listViewWidget.reset(); + addConfigEntries(); + searchBox.setX2(startX); + searchBox.setY2(searchStartY); + searchBox.setWidth2(contentWidth); + searchBox.setChangedListener2(string -> { + listViewWidget.setSearchTerm(string); + }); + + listViewWidget.setXYSize(startX, startY, contentWidth, listViewHeight); + addChild(new ClickableWidget(listViewWidget)); + addChild(new ClickableWidget(searchBox)); + } + + @Override + public MutableText getScreenTitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.title"); + } + + @Override + public MutableText getScreenSubtitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_save.subtitle", newPreset.getId()); + } + + public void addConfigEntries() { + if(!PIDSManager.getCustomPresets().isEmpty()) { + listViewWidget.addCategory(TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.category.save_edits")); + File[] resourcePacks = resourcePackFolder.listFiles(); + if (resourcePacks != null) { + for (File pack : resourcePacks) { + if (pack.isDirectory()) { + File jsonFile = pack.toPath().resolve("assets").resolve(Constants.MOD_ID).resolve("joban_custom_resources.json").toFile(); + if (jsonFile.exists()) { + String packName = pack.getName(); + addResourcePackListing(packName); + } + } + } + } + + ButtonWidgetExtension exportBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.export"), (btn) -> { + openExportScreen(); + }); + + HorizontalWidgetSet widgetSet2 = new HorizontalWidgetSet(); + widgetSet2.addWidget(new MappedWidget(exportBtn)); + widgetSet2.setXYSize(0, 0, 100, 20); + + addChild(new ClickableWidget(exportBtn)); + addChild(new ClickableWidget(widgetSet2)); + + ContentItem contentItem2 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.new"), new MappedWidget(widgetSet2), 26); + + listViewWidget.add(contentItem2); + } + } + + private void openExportScreen() { + MinecraftClient.getInstance().openScreen( + new Screen(new ExportScreen(oldPreset, newPreset).withPreviousScreen(previousScreen)) + ); + } + + private void addResourcePackListing(String packName) { + ButtonWidgetExtension saveBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.save"), (btn) -> { + JCMResourceManager.updatePresetInResourcePack(oldPreset, newPreset, packName); + onClose2(); + }); + + HorizontalWidgetSet widgetSet = new HorizontalWidgetSet(); + widgetSet.addWidget(new MappedWidget(saveBtn)); + widgetSet.setXYSize(0, 0, 100, 20); + + addChild(new ClickableWidget(saveBtn)); + addChild(new ClickableWidget(widgetSet)); + ContentItem contentItem = new ContentItem(TextUtil.literal(packName), new MappedWidget(widgetSet), 26); + + listViewWidget.add(contentItem); + } + + public static void drawPIDSPreview(PIDSPresetBase preset, GuiDrawing guiDrawing, int startX, int startY, int width, int height, boolean backgroundOnly) { + final int offset = 6; + + // Background + GuiHelper.drawTexture(guiDrawing, PIDS_PREVIEW_BASE, startX, startY, width, height); + if(preset == null) return; + + GuiHelper.drawTexture(guiDrawing, preset.getBackground(), startX+0.5, startY+offset+0.5, width-1, height-offset-4); + + if(!backgroundOnly) { + double perRow = height / 8.5; + double rowHeight = Math.max(0.5, height / 24.0); + for(int i = 0; i < 4; i++) { + if(preset.isRowHidden(i)) continue; + double curY = startY + offset + ((i+1) * perRow); + GuiHelper.drawRectangle(guiDrawing, startX+1.5, curY, width * 0.55, rowHeight, preset.getTextColor()); + GuiHelper.drawRectangle(guiDrawing, startX + (width * 0.65), curY, rowHeight, rowHeight, preset.getTextColor()); + GuiHelper.drawRectangle(guiDrawing, startX + (width * 0.75), curY, (width * 0.2)-0.5, rowHeight, preset.getTextColor()); + } + } + } + + @Override + public void onClose2() { + JCMResourceManager.reloadResources(); + super.onClose2(); + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/ExportScreen.java b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/ExportScreen.java new file mode 100644 index 00000000..8bc65a40 --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/ExportScreen.java @@ -0,0 +1,221 @@ +package com.lx862.jcm.mod.render.gui.screen; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.lx862.jcm.mod.Constants; +import com.lx862.jcm.mod.data.pids.PIDSManager; +import com.lx862.jcm.mod.data.pids.preset.PIDSPresetBase; +import com.lx862.jcm.mod.render.GuiHelper; +import com.lx862.jcm.mod.render.RenderHelper; +import com.lx862.jcm.mod.render.gui.screen.base.TitledScreen; +import com.lx862.jcm.mod.render.gui.widget.ContentItem; +import com.lx862.jcm.mod.render.gui.widget.ListViewWidget; +import com.lx862.jcm.mod.render.gui.widget.MappedWidget; +import com.lx862.jcm.mod.util.JCMLogger; +import com.lx862.jcm.mod.util.TextCategory; +import com.lx862.jcm.mod.util.TextUtil; +import org.mtr.mapping.holder.*; +import org.mtr.mapping.mapper.ButtonWidgetExtension; +import org.mtr.mapping.mapper.TextFieldWidgetExtension; +import org.mtr.mapping.tool.TextCase; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +public class ExportScreen extends TitledScreen implements RenderHelper, GuiHelper { + private final File resourcePackFolder; + private final ListViewWidget listViewWidget; + private final PIDSPresetBase oldPreset; + private final PIDSPresetBase newPreset; + private final String associatedRP; + public ExportScreen(PIDSPresetBase oldPreset, PIDSPresetBase newPreset) { + super(false); + this.resourcePackFolder = new File(MinecraftClient.getInstance().getRunDirectoryMapped(), "resourcepacks"); + this.listViewWidget = new ListViewWidget(); + this.newPreset = newPreset; + this.oldPreset = oldPreset; + this.associatedRP = getAssociatedResourcePack(this.oldPreset.getId()); + } + + @Override + protected void init2() { + super.init2(); + int contentWidth = (int)Math.min((width * 0.75), MAX_CONTENT_WIDTH); + int listViewHeight = (int)(6 * 25.4); + int startX = (width - contentWidth) / 2; + int startY = TEXT_PADDING * 6; + + listViewWidget.reset(); + addConfigEntries(); + listViewWidget.setXYSize(startX, startY, contentWidth, listViewHeight); + addChild(new ClickableWidget(listViewWidget)); + } + + @Override + public MutableText getScreenTitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.title"); + } + + @Override + public MutableText getScreenSubtitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_save.subtitle", newPreset.getId()); + } + + public void addConfigEntries() { + listViewWidget.addCategory(TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.new2")); + addResourcePackListing(PIDSManager.getPreset(newPreset.getId())); + } + + private void addResourcePackListing(PIDSPresetBase preset) { + if(associatedRP == null) return; + + TextFieldWidgetExtension textField1 = new TextFieldWidgetExtension(0, 0, 160, 20, "", 100, TextCase.DEFAULT, null, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.field.tooltip.rpname").getString()); + TextFieldWidgetExtension textField2 = new TextFieldWidgetExtension(0, 0, 160, 20, "", 100, TextCase.DEFAULT, null, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.field.tooltip.rpdesc").getString()); + TextFieldWidgetExtension textField3 = new TextFieldWidgetExtension(0, 0, 160, 20, "", 100, TextCase.DEFAULT, null, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.field.tooltip.rpid").getString()); + + textField3.setText2(this.oldPreset.getId()); + + ButtonWidgetExtension exportBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.export2"), (btn) -> { + export(textField1, textField2, textField3); + onClose2(); + }); + + ButtonWidgetExtension backBtn = new ButtonWidgetExtension(0, 0, 60, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.back"), (btn) -> { + onClose2(); + }); + + addChild(new ClickableWidget(textField1)); + addChild(new ClickableWidget(textField2)); + addChild(new ClickableWidget(textField3)); + addChild(new ClickableWidget(exportBtn)); + addChild(new ClickableWidget(backBtn)); + + ContentItem contentItem = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.field.rpname"), new MappedWidget(textField1), 26); + ContentItem contentItem1 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.field.rpdesc"), new MappedWidget(textField2), 26); + ContentItem contentItem2 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.field.rpid"), new MappedWidget(textField3), 26); + ContentItem contentItem3 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.title.export"), new MappedWidget(exportBtn), 26); + ContentItem contentItem4 = new ContentItem(TextUtil.translatable(TextCategory.GUI,"pids_preset.listview.widget.title.back"), new MappedWidget(backBtn), 26); + + listViewWidget.add(contentItem); + listViewWidget.add(contentItem1); + listViewWidget.add(contentItem2); + listViewWidget.add(contentItem3); + listViewWidget.add(contentItem4); + } + + private String getAssociatedResourcePack(String targetPresetId) { + for(File file : resourcePackFolder.listFiles()) { + if(file.isDirectory()) { + File jsonFile = resourcePackFolder.toPath().resolve(file.getName()).resolve("assets").resolve(Constants.MOD_ID).resolve("joban_custom_resources.json").toFile(); + if(jsonFile.exists()) { + JsonArray presetsInRP; + try { + presetsInRP = new JsonParser().parse(new FileReader(jsonFile)).getAsJsonObject().get("pids_images").getAsJsonArray(); + } catch (Exception e) { + JCMLogger.debug("Cannot read PIDS Preset from Resource Pack!"); + continue; + } + + for(int i = 0; i < presetsInRP.size(); i++) { + PIDSPresetBase pidsPreset = PIDSManager.parsePreset(presetsInRP.get(i).getAsJsonObject()); + if(pidsPreset != null && pidsPreset.getId().equals(oldPreset.getId())) { + return file.getName(); + } + } + } + } + } + return null; + } + + public void export(TextFieldWidgetExtension textField1, TextFieldWidgetExtension textField2, TextFieldWidgetExtension textField3) { + String rpName = textField1.getText2(); + String rpDesc = textField2.getText2(); + String rpID = textField3.getText2(); + int packFormat = 26; + + File rpFolder = new File(resourcePackFolder, rpName); + if (!rpFolder.exists()) { + rpFolder.mkdirs(); + } + + JsonObject pack = new JsonObject(); + pack.addProperty("pack_format", packFormat); + pack.addProperty("description", rpDesc); + + JsonObject packMeta = new JsonObject(); + packMeta.add("pack", pack); + + File packMcmeta = new File(rpFolder, "pack.mcmeta"); + try { + FileWriter writer = new FileWriter(packMcmeta); + new GsonBuilder().setPrettyPrinting().create().toJson(packMeta, writer); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + File assetsFolder = new File(rpFolder, "assets"); + File modFolder = new File(assetsFolder, Constants.MOD_ID); + File customResourcesJson = new File(modFolder, "joban_custom_resources.json"); + if (!modFolder.exists()) { + modFolder.mkdirs(); + } + + JsonArray presetsArray = new JsonArray(); + JsonObject presetObject = newPreset.toJson(); + presetObject.addProperty("id", textField3.getText2()); + presetObject.addProperty("name", textField3.getText2()); + presetsArray.add(presetObject); + JsonObject rootObject = new JsonObject(); + rootObject.add("pids_images", presetsArray); + try { + FileWriter writer = new FileWriter(customResourcesJson); + new GsonBuilder().setPrettyPrinting().create().toJson(rootObject, writer); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + copyResources(associatedRP, rpFolder); + } + + private void copyResources(String oldRPName, File newRpFolder) { + File oldRPFolder = new File(resourcePackFolder, oldRPName); + File oldAssetsFolder = new File(oldRPFolder, "assets"); + File oldModFolder = new File(oldAssetsFolder, Constants.MOD_ID); + + String backgroundPath = oldPreset.getBackground().getNamespace() + ":" + oldPreset.getBackground().getPath(); + String[] folders = backgroundPath.split(":"); + + File destFolder = new File(newRpFolder, "assets"); + for (int i = 0; i < folders.length - 1; i++) { + destFolder = new File(destFolder, folders[i]); + } + + if (folders.length > 0) { + copyResources(oldModFolder, destFolder, folders[folders.length - 1]); + } else { + JCMLogger.error("Invalid background path: " + backgroundPath); + } + } + + private void copyResources(File sourceFolder, File destFolder, String fileName) { + File sourceFile = new File(sourceFolder, fileName); + File destFile = new File(destFolder, fileName); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + try { + Files.copy(sourceFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + JCMLogger.error("Failed to copy resource: " + sourceFile + " to " + destFile, e); + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/PIDSPresetScreen.java b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/PIDSPresetScreen.java index 35117015..58e94384 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/PIDSPresetScreen.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/PIDSPresetScreen.java @@ -11,10 +11,8 @@ import com.lx862.jcm.mod.render.gui.widget.MappedWidget; import com.lx862.jcm.mod.util.TextCategory; import com.lx862.jcm.mod.util.TextUtil; -import org.mtr.mapping.holder.ClickableWidget; -import org.mtr.mapping.holder.Identifier; -import org.mtr.mapping.holder.MutableText; -import org.mtr.mapping.holder.Text; + +import org.mtr.mapping.holder.*; import org.mtr.mapping.mapper.ButtonWidgetExtension; import org.mtr.mapping.mapper.GuiDrawing; import org.mtr.mapping.mapper.TextFieldWidgetExtension; @@ -89,7 +87,9 @@ private void addPreset(PIDSPresetBase preset) { }); ButtonWidgetExtension editBtn = new ButtonWidgetExtension(0, 0, 40, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.listview.widget.edit"), (btn) -> { - // TODO: Launch screen to edit PIDS preset + MinecraftClient.getInstance().openScreen( + new Screen(new VisualEditorScreen(preset.getId(), new Screen(this)).withPreviousScreen(new Screen(this))) + ); }); if(preset.getId().equals(selectedPreset)) { @@ -97,10 +97,10 @@ private void addPreset(PIDSPresetBase preset) { selectBtn.active = false; } -// if(preset.builtin) { -// // Can't edit built-in preset -// editBtn.active = false; -// } + if(preset.builtin) { + // Can't edit built-in preset + editBtn.active = false; + } HorizontalWidgetSet widgetSet = new HorizontalWidgetSet(); if(!preset.builtin) widgetSet.addWidget(new MappedWidget(editBtn)); @@ -124,7 +124,7 @@ public static void drawPIDSPreview(PIDSPresetBase preset, GuiDrawing guiDrawing, // Background GuiHelper.drawTexture(guiDrawing, PIDS_PREVIEW_BASE, startX, startY, width, height); if(preset == null) return; - + GuiHelper.drawTexture(guiDrawing, preset.getBackground(), startX+0.5, startY+offset+0.5, width-1, height-offset-4); if(!backgroundOnly) { @@ -149,4 +149,4 @@ private void choose(String id) { public boolean isPauseScreen2() { return false; } -} +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/VisualEditorScreen.java b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/VisualEditorScreen.java new file mode 100644 index 00000000..cef1671f --- /dev/null +++ b/fabric/src/main/java/com/lx862/jcm/mod/render/gui/screen/VisualEditorScreen.java @@ -0,0 +1,228 @@ +package com.lx862.jcm.mod.render.gui.screen; + +import com.lx862.jcm.mod.Constants; +import com.lx862.jcm.mod.data.pids.PIDSManager; +import com.lx862.jcm.mod.data.pids.preset.JsonPIDSPreset; +import com.lx862.jcm.mod.data.pids.preset.MutableJsonPIDSPreset; +import com.lx862.jcm.mod.data.pids.preset.PIDSPresetBase; +import com.lx862.jcm.mod.render.GuiHelper; +import com.lx862.jcm.mod.render.gui.screen.base.TitledScreen; +import com.lx862.jcm.mod.util.TextCategory; +import com.lx862.jcm.mod.util.TextUtil; +import org.mtr.mapping.holder.*; +import org.mtr.mapping.mapper.*; +import org.mtr.mapping.tool.TextCase; + +import java.io.File; +import java.io.IOException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class VisualEditorScreen extends TitledScreen { + private final File resourcePackFolder; + private final CheckboxWidgetExtension[] hideRowCheckboxes = new CheckboxWidgetExtension[4]; + private final TextFieldWidgetExtension idTextField; + private final TextFieldWidgetExtension backgroundTextField; + private final TextFieldWidgetExtension colorTextField; + private final CheckboxWidgetExtension showWeatherCheckbox; + private final CheckboxWidgetExtension showClockCheckbox; + private final JsonPIDSPreset originalPreset; + private final MutableJsonPIDSPreset editedPreset; + private final Screen previousScreen; + public VisualEditorScreen(String presetId, Screen previousScreen) { + super(false); + this.resourcePackFolder = new File(org.mtr.mapping.holder.MinecraftClient.getInstance().getRunDirectoryMapped(), "resourcepacks"); + this.previousScreen = previousScreen; + this.originalPreset = (JsonPIDSPreset) PIDSManager.getPreset(presetId); + this.editedPreset = originalPreset.toMutable(); + + this.backgroundTextField = new TextFieldWidgetExtension(20, 0, 200, 20, Integer.MAX_VALUE, TextCase.DEFAULT, null, null); + this.backgroundTextField.setText2(editedPreset.getBackground().getNamespace() + ":" + editedPreset.getBackground().getPath()); + this.backgroundTextField.setChangedListener2(str -> { + Identifier newId = Identifier.tryParse(str); + if(newId != null) editedPreset.background = newId; + }); + + this.idTextField = new TextFieldWidgetExtension(20, 0, 200, 20, Integer.MAX_VALUE, TextCase.DEFAULT, null, null); + this.idTextField.setText2(editedPreset.getId()); + this.idTextField.setChangedListener2(str -> editedPreset.setId(str)); + + this.colorTextField = new TextFieldWidgetExtension(20, 0, 200, 20, Integer.MAX_VALUE, TextCase.DEFAULT, null, null); + this.colorTextField.setText2(Integer.toHexString(editedPreset.getTextColor() - 0xFF000000)); + this.colorTextField.setChangedListener2(str -> { + try { + editedPreset.textColor = (255 << 24) + (int)Integer.parseInt(str, 16); + } catch (Exception e) { + } + }); + + this.showWeatherCheckbox = new CheckboxWidgetExtension(20, 0, 200, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.weather"), true, isChecked -> { + editedPreset.showWeather = isChecked; + }); + + this.showClockCheckbox = new CheckboxWidgetExtension(20, this.height / 6 + 120, 200, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.clock"), true, isChecked -> { + editedPreset.showClock = isChecked; + }); + } + + @Override + protected void init2() { + super.init2(); + + idTextField.setY2(this.height / 6 + 20); + addChild(new ClickableWidget(idTextField)); + + backgroundTextField.setY2(this.height / 6 + 45); + addChild(new ClickableWidget(backgroundTextField)); + + colorTextField.setY2(this.height / 6 + 70); + colorTextField.setText2(Integer.toHexString(editedPreset.getTextColor())); + addChild(new ClickableWidget(colorTextField)); + + showWeatherCheckbox.setY2(this.height / 6 + 95); + addChild(new ClickableWidget(showWeatherCheckbox)); + + showClockCheckbox.setY2(this.height / 6 + 120); + addChild(new ClickableWidget(showClockCheckbox)); + + int totalWidth = hideRowCheckboxes.length * 30; + int horizontalGap = (this.width - totalWidth) / (hideRowCheckboxes.length + 1); + int startX = horizontalGap; + + for (int i = 0; i < hideRowCheckboxes.length; i++) { + int x = startX + i * (30 + horizontalGap) - 15; + int y = this.height - 35; + final int index = i; + hideRowCheckboxes[i] = new CheckboxWidgetExtension(x, y, 20, 20, TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.hiderow", (i+1)), true, isChecked -> { + editedPreset.rowHidden[index] = isChecked; + }); + addChild(new ClickableWidget(hideRowCheckboxes[i])); + } + populateCurrentPresetFields(); + } + + @Override + public void render(GraphicsHolder graphicsHolder, int mouseX, int mouseY, float delta) { + super.render(graphicsHolder, mouseX, mouseY, delta); + renderPIDSPreview(graphicsHolder, editedPreset); + + // this was for tooltips + // if (idTextField.isMouseOver(mouseX, mouseY)) { + // renderWithTooltip(context, Text.of("The name of the template"), mouseX, + // mouseY); + // } else if (backgroundTextField.isMouseOver(mouseX, mouseY)) { + // renderTooltip(matrices, Text.of("The background path of the PID"), mouseX, + // mouseY); + // } else if (colorTextField.isMouseOver(mouseX, mouseY)) { + // renderTooltip(matrices, Text.of("The color of the text shown on the PID"), + // mouseX, mouseY); + // } + } + + @Override + public MutableText getScreenTitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.title"); + } + + @Override + public MutableText getScreenSubtitle() { + return TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.editingpreset").append(":").append(" ").append(editedPreset.getId()); + } + + @Override + public boolean isPauseScreen2() { + return false; + } + + @Override + public void onClose2() { + super.onClose2(); + MinecraftClient.getInstance().openScreen( + new Screen(new EditorSaveScreen(originalPreset, editedPreset, previousScreen).withPreviousScreen(previousScreen)) + ); + } + + private void populateCurrentPresetFields() { + idTextField.setText2(editedPreset.getId()); + backgroundTextField.setText2(editedPreset.getBackground().getNamespace() + ":" + editedPreset.getBackground().getPath()); + colorTextField.setText2(Integer.toHexString(editedPreset.getTextColor())); + showWeatherCheckbox.setChecked(editedPreset.getShowWeather()); + showClockCheckbox.setChecked(editedPreset.getShowClock()); + + for(int i = 0; i < 4; i++) { + hideRowCheckboxes[i].setChecked(editedPreset.isRowHidden(i)); + } + } + + private void renderPIDSPreview(GraphicsHolder context, JsonPIDSPreset pidsPreset) { + Identifier backgroundId = pidsPreset.getBackground(); + Identifier frameTexture = new Identifier(Constants.MOD_ID, "textures/editor/frame.png"); + int textColor = pidsPreset.getTextColor(); + + GuiDrawing guiDrawing = new GuiDrawing(context); + + int previewWidth = 160; + int previewHeight = 90; + + int baseWidth = 427; + double scaleFactor = (double)getWidthMapped() / baseWidth; + double frameScaleFactor = 1.2; + double scaledWidth = previewWidth * scaleFactor; + double scaledHeight = previewHeight * scaleFactor; + + int startX = (getWidthMapped() / 2) + 30; + int startY = (getHeightMapped() / 4); + + int frameX = startX - (int)(((previewWidth * 0.932 * scaleFactor * frameScaleFactor) - (previewWidth * scaleFactor)) / 2); + int frameY = startY - (int)((previewHeight * scaleFactor * frameScaleFactor - previewHeight * scaleFactor) / 2); + + context.drawCenteredText("Preview", (int)(startX + (scaledWidth / 2)), startY - 20, 0xFFFFFF); + + context.push(); + context.translate((getWidthMapped() / 2.0) + 30, startY, 0); + context.scale((float)scaleFactor, (float)scaleFactor, (float)scaleFactor); + + GuiHelper.drawTexture(guiDrawing, frameTexture, frameX, frameY, (int)(previewWidth * 0.932 * scaleFactor * frameScaleFactor), (int)(previewHeight * scaleFactor * frameScaleFactor)); + // drawTexture unaffected by matrices scale, probably bug in mappings + GuiHelper.drawTexture(guiDrawing, backgroundId, startX, startY, previewWidth * scaleFactor, previewHeight * scaleFactor); + if (pidsPreset.getShowWeather()) { + GuiHelper.drawTexture(guiDrawing, new Identifier(Constants.MOD_ID, "textures/block/pids/weather_sunny.png"), startX + 7, startY, 11 * scaleFactor, 11 * scaleFactor); + } + + World world = World.cast(MinecraftClient.getInstance().getWorldMapped()); + + if (pidsPreset.getShowClock() && world != null) { + long timeNow = WorldHelper.getTimeOfDay(world) + 6000; + long hours = timeNow / 1000; + long minutes = Math.round((timeNow - (hours * 1000)) / 16.8); + String timeString = String.format("%02d:%02d", hours % 24, minutes % 60); + + context.drawText(timeString, 130, 5, 0xFFFFFF, false, GraphicsHolder.getDefaultLight()); + } + + { + context.push(); + context.translate(0, 1, 0); + if(editedPreset.topPadding) context.translate(0, 14, 0); + context.scale(1.4F, 1.4F, 1.4F); + for(int i = 0; i < 4; i++) { + if (!pidsPreset.isRowHidden(i)) { + context.drawText(TextUtil.translatable(TextCategory.GUI, "pids_preset.pids_editor.station"), 5, (int)(i * 14), textColor, false, GraphicsHolder.getDefaultLight()); + } + } + context.pop(); + } + + context.pop(); + } + + private static boolean isZipContainsFile(File zipFile, String filePath) { + try (ZipFile zf = new ZipFile(zipFile)) { + ZipEntry entry = zf.getEntry(filePath); + return entry != null; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java b/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java index a8c80abf..395fac95 100644 --- a/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java +++ b/fabric/src/main/java/com/lx862/jcm/mod/resources/JCMResourceManager.java @@ -35,4 +35,4 @@ private static void parseCustomResources() { } })); } -} +} \ No newline at end of file diff --git a/fabric/src/main/resources/assets/jsblock/lang/en_us.json b/fabric/src/main/resources/assets/jsblock/lang/en_us.json index a7f52c54..1f6f836a 100644 --- a/fabric/src/main/resources/assets/jsblock/lang/en_us.json +++ b/fabric/src/main/resources/assets/jsblock/lang/en_us.json @@ -106,15 +106,56 @@ "gui.jsblock.pids.listview.widget.row_hidden": "Hide Arrivals", "gui.jsblock.pids_preset.listview.category.builtin": "Built-in Preset", "gui.jsblock.pids_preset.listview.category.custom": "Custom Preset", + "gui.jsblock.pids_preset.listview.category.save_edits": "Save Changes", "gui.jsblock.pids_preset.listview.widget.choose": "Choose", "gui.jsblock.pids_preset.listview.widget.edit": "Edit", "gui.jsblock.pids_preset.listview.widget.selected": "Selected", + "gui.jsblock.pids_preset.listview.widget.save": "Save", + "gui.jsblock.pids_preset.listview.widget.export": "Export...", + "gui.jsblock.pids_preset.listview.widget.export2": "Export", + "gui.jsblock.pids_preset.listview.widget.back": "Back", + "gui.jsblock.pids_preset.listview.widget.title.export": "Export the resource pack", + "gui.jsblock.pids_preset.listview.widget.title.back": "Go Back", + "gui.jsblock.pids_preset.listview.widget.saveas": "Save As...", + "gui.jsblock.pids_preset.listview.widget.field.rpname": "Resource Pack Name", + "gui.jsblock.pids_preset.listview.widget.field.rpdesc": "Resource Pack Description", + "gui.jsblock.pids_preset.listview.widget.field.rpid": "Template ID", + "gui.jsblock.pids_preset.listview.widget.field.tooltip.rpname": "My resource pack", + "gui.jsblock.pids_preset.listview.widget.field.tooltip.rpdesc": "A very cool resource pack!", + "gui.jsblock.pids_preset.listview.widget.field.tooltip.rpid": "id", + "gui.jsblock.pids_preset.listview.widget.title.saveas": "Save the changes to a different resource pack", + "gui.jsblock.pids_preset.listview.widget.new": "Export as a new resource pack", + "gui.jsblock.pids_preset.listview.widget.new2": "Exporting as a new resource pack", "gui.jsblock.pids_preset.subtitle": "Selected > %s", "gui.jsblock.pids_preset.title": "PIDS Preset", + "gui.jsblock.pids_save.subtitle": "Saving > %s", "gui.jsblock.sound_looper.listview.title.limit_range": "Limit sound range", "gui.jsblock.sound_looper.listview.title.need_redstone": "Require Redstone Power", "gui.jsblock.sound_looper.listview.title.pos1": "Position 1 (X, Y, Z)", "gui.jsblock.sound_looper.listview.title.pos2": "Position 2 (X, Y, Z)", + "gui.jsblock.mismatched_versions": "Please update the Joban Client Mod and try again.", + "gui.jsblock.pids.listview.title.hide_platform_number": "Hide Platform Number", + "gui.jsblock.pids.listview.title.filtered_platform": "Showing arrivals for %sPlatform %s", + "gui.jsblock.pids.listview.title.filtered_platform.nearby": "Nearby ", + "gui.jsblock.pids.listview.title.pids_preset": "PIDS Preset", + "gui.jsblock.pids.listview.widget.change_platform": "Change...", + "gui.jsblock.pids.listview.widget.custom_message": "Custom messages", + "gui.jsblock.pids.listview.widget.row_hidden": "Hide Arrivals", + "gui.jsblock.pids.listview.widget.choose_preset": "Choose", + "gui.jsblock.pids_preset.title": "PIDS Preset", + "gui.jsblock.pids_preset.subtitle": "Selected > %s", + "gui.jsblock.pids_preset.listview.category.builtin": "Built-in Preset", + "gui.jsblock.pids_preset.listview.category.custom": "Custom Preset", + "gui.jsblock.pids_preset.listview.widget.edit": "Edit", + "gui.jsblock.pids_preset.listview.widget.choose": "Choose", + "gui.jsblock.pids_preset.listview.widget.selected": "Selected", + "gui.jsblock.pids_preset.pids_editor.title": "PIDS Editor", + "gui.jsblock.pids_preset.pids_editor.editingpreset": "Editing preset", + "gui.jsblock.pids_preset.pids_editor.weather": "Show Weather", + "gui.jsblock.pids_preset.pids_editor.clock": "Show Clock", + "gui.jsblock.pids_preset.pids_editor.hiderow": "Hide Row %d", + "gui.jsblock.pids_preset.pids_editor.station": "Station", + "gui.jsblock.pids_preset.pids_editor.back": "Back", "gui.jsblock.sound_looper.listview.title.repeat_tick": "Loop interval in Ticks (1s = 20 Ticks)", "gui.jsblock.sound_looper.listview.title.sound_category": "Sound Category", "gui.jsblock.sound_looper.listview.title.sound_id": "The identifier for the sound", diff --git a/fabric/src/main/resources/assets/jsblock/lang/it_it.json b/fabric/src/main/resources/assets/jsblock/lang/it_it.json index 507d622a..c70f0771 100644 --- a/fabric/src/main/resources/assets/jsblock/lang/it_it.json +++ b/fabric/src/main/resources/assets/jsblock/lang/it_it.json @@ -1,11 +1,16 @@ { + "itemGroup.jsblock.main": "Blocchi Mod Joban Client", + "itemGroup.jsblock.ceiling": "Blocchi Mod Joban Client - Soffitte", + "itemGroup.jsblock.pids": "Blocchi Mod Joban Client - PIDS", + "block.jsblock.apg_door_drl": "APG (Variante Linea Disneyland Resorts)", "block.jsblock.apg_glass_drl": "APG (Variante Linea Disneyland Resorts)", "block.jsblock.apg_glass_end_drl": "APG (Variante Linea Disneyland Resorts)", "block.jsblock.auto_iron_door": "Porta di Ferro Automatica", "block.jsblock.block.rv_pids_pole": "Deve essere piazzato sopra i PIDS Railway Vision", - "block.jsblock.buffer_stop": "Respingente (Stile Linea East Rail)", + "block.jsblock.pids.time": "%02d:%02d", "block.jsblock.butterfly_light": "Indicatore chiusura porte (Luce a Farfalla)", + "block.jsblock.buffer_stop": "Respingente (Stile Linea East Rail)", "block.jsblock.ceiling_slanted": "Soffitta Inclinata", "block.jsblock.circle_wall_1": "Muro Circolare (1)", "block.jsblock.circle_wall_2": "Muro Circolare (2)", @@ -16,132 +21,141 @@ "block.jsblock.circle_wall_7": "Muro Circolare (7)", "block.jsblock.departure_pole": "Palo (Per Timer di Partenza)", "block.jsblock.departure_timer": "Timer di Partenza", - "block.jsblock.exit_sign_even": "Cartello di uscita (Orientazione:numero paro)", + "block.jsblock.tcl_emg_stop_button": "Bottone del freno d'Emergenza (Stile Linea Tung Chung)", + "block.jsblock.mtr_enquiry_machine": "Macchina di inchiesta", + "block.jsblock.rv_enquiry_machine": "Macchina di inchiesta Railway Vision", + "block.jsblock.mtr_enquiry_machine_wall": " Macchina di inchiesta MTR (Montata sul muro)", + "block.jsblock.kcr_enquiry_machine": "Macchina di inchiesta KCR (Montata sul muro)", "block.jsblock.exit_sign_odd": "Cartello di uscita", + "block.jsblock.exit_sign_even": "Cartello di uscita (Orientazione:numero paro)", "block.jsblock.faresaver": "Salvaprezzo", "block.jsblock.fire_alarm": "Allarme Incendio", + "block.jsblock.kcr_name_sign": "Cartello con il nome stazione (Stile KCR)", + "block.jsblock.kcr_name_sign_station_color": "Cartello con il nome stazione (Stile KCR) (Colore Stazione)", + "block.jsblock.kcr_emg_stop_sign": "Cartello Freno di emergenza KCR", "block.jsblock.helpline_1": "Assistenza Telefonica (Con Sticker)", "block.jsblock.helpline_2": "Assistenza Telefonica", - "block.jsblock.helpline_standing": "Assistenza Telefonica (con appoggio)", "block.jsblock.helpline_standing_eal": "Assistenza Telefonica (Stile Linea East Rail)", - "block.jsblock.kcr_emg_stop_sign": "Cartello Freno di emergenza KCR", - "block.jsblock.kcr_enquiry_machine": "Macchina di inchiesta KCR (Montata sul muro)", - "block.jsblock.kcr_name_sign": "Cartello con il nome stazione (Stile KCR)", - "block.jsblock.kcr_name_sign_station_color": "Cartello con il nome stazione (Stile KCR) (Colore Stazione)", - "block.jsblock.kcr_trespass_sign": "Cartello KCR:'Vietato oltrepassare' ", - "block.jsblock.light_block": "Risorsa di luce", - "block.jsblock.light_lantern": "Lanterna di luce", + "block.jsblock.helpline_standing": "Assistenza Telefonica (con appoggio)", + "block.jsblock.tml_emg_stop_button": "Bottone del freno d'Emergenza (Con appoggio, TML)", + "block.jsblock.sil_emg_stop_button": "Bottone del freno d'Emergenza (Con appoggio, SIL)", "block.jsblock.lrt_inter_car_barrier_left": "Barriera carrozza LRT (Sinistra)", "block.jsblock.lrt_inter_car_barrier_middle": "Barriera carrozza LRT (Metà)", "block.jsblock.lrt_inter_car_barrier_right": "Barriera carrozza LRT (Destra)", - "block.jsblock.lrt_trespass_sign": "Cartello LRT:'Vietato oltrepassare' ", - "block.jsblock.mtr_enquiry_machine": "Macchina di inchiesta", - "block.jsblock.mtr_enquiry_machine_wall": " Macchina di inchiesta MTR (Montata sul muro)", + "block.jsblock.light_block": "Risorsa di luce", + "block.jsblock.light_lantern": "Lanterna di luce", + "block.jsblock.spot_lamp": "Lampadina", "block.jsblock.mtr_stairs": "Scale MTR", - "block.jsblock.mtr_trespass_sign": "Cartello MTR:'Vietato oltrepassare' ", "block.jsblock.operator_button": "Bottone riservato a Operatori", "block.jsblock.pids_1a": "Sistema di Visualizzazione delle Informazioni Passeggere (PIDS)", "block.jsblock.pids_lcd": "PIDS Vecchia Linea Tsueng Kwan O", "block.jsblock.pids_rv": "PIDS della Railway Vision", "block.jsblock.pids_rv_sil": "PIDS della Railway Vision (Variante SIL, Stazione Ocean Park e Stazione Wong Chuk Hang)", "block.jsblock.pids_rv_sil_2": "PIDS della Railway Vision (Variante SIL, Stazione Admiralty e Stazione South Horizon)", - "block.jsblock.rv_enquiry_machine": "Macchina di inchiesta Railway Vision", "block.jsblock.rv_pids_pole": "Palo per PIDS della Railway Vision", + "block.jsblock.signal_light_red_1": "Segnale a semaforo (Rosso in basso)", + "block.jsblock.signal_light_red_2": "Segnale a semaforo (Rosso in alto)", "block.jsblock.signal_light_blue": "Segnale a semaforo (Blu in alto)", "block.jsblock.signal_light_green": "Segnale a semaforo (Verde in basso)", "block.jsblock.signal_light_inverted_1": "Segnale a semaforo (Blu e Rosso Invertiti)", "block.jsblock.signal_light_inverted_2": "Segnale a semaforo (Blu e Verde Invertiti)", - "block.jsblock.signal_light_red_1": "Segnale a semaforo (Rosso in basso)", - "block.jsblock.signal_light_red_2": "Segnale a semaforo (Rosso in alto)", - "block.jsblock.sil_emg_stop_button": "Bottone del freno d'Emergenza (Con appoggio, SIL)", "block.jsblock.sound_looper": "Ripetitore di suoni", - "block.jsblock.spot_lamp": "Lampadina", "block.jsblock.station_ceiling_wrl": "Soffitta Stazioni MTR (2009)", - "block.jsblock.station_ceiling_wrl_pole": "Pali Soffitta Stazioni MTR (2009)", "block.jsblock.station_ceiling_wrl_single": "Soffitta stazione MTR (2009) (Singolo)", - "block.jsblock.station_ceiling_wrl_single_pole": "Palo Soffitta stazione MTR Pole (2009) (Singolo)", - "block.jsblock.station_ceiling_wrl_single_station_color": "Soffitta stazione MTR (2009, Colore Stazione) (Singolo)", "block.jsblock.station_ceiling_wrl_station_color": "Soffitta Stazioni MTR (2009, Colore Stazione)", + "block.jsblock.station_ceiling_wrl_single_station_color": "Soffitta stazione MTR (2009, Colore Stazione) (Singolo)", + "block.jsblock.station_ceiling_wrl_pole": "Pali Soffitta Stazioni MTR (2009)", + "block.jsblock.station_ceiling_wrl_single_pole": "Palo Soffitta stazione MTR Pole (2009) (Singolo)", "block.jsblock.station_name_standing": "Nome Stazione (Con Appoggio)", "block.jsblock.subsidy_machine": "Macchina ricariche", - "block.jsblock.tcl_emg_stop_button": "Bottone del freno d'Emergenza (Stile Linea Tung Chung)", - "block.jsblock.thales_ticket_barrier_bare": "Tornello Thales (Parte in Metallo)", "block.jsblock.thales_ticket_barrier_entrance": "Tornello Thales (Entrata)", "block.jsblock.thales_ticket_barrier_exit": "Tornello Thales (Uscita)", - "block.jsblock.tml_emg_stop_button": "Bottone del freno d'Emergenza (Con appoggio, TML)", + "block.jsblock.thales_ticket_barrier_bare": "Tornello Thales (Parte in Metallo)", "block.jsblock.train_model_e44": "Modellino Treno (E44)", + "block.jsblock.mtr_trespass_sign": "Cartello MTR:'Vietato oltrepassare' ", + "block.jsblock.kcr_trespass_sign": "Cartello KCR:'Vietato oltrepassare' ", + "block.jsblock.lrt_trespass_sign": "Cartello LRT:'Vietato oltrepassare' ", "block.jsblock.water_machine": "Fontana d'acqua", - "gui.jsblock.atlas_config.not_initialized": "TextureTextRenderer non è abilitato, Il nuovo rendering del testo è stato abilitato?", - "gui.jsblock.block_config.discard": "Elimina Impostazioni", - "gui.jsblock.block_config.save": "Salva Impostazioni", - "gui.jsblock.block_config.subtitle": "A: %d %d %d", - "gui.jsblock.block_config.subtitle_with_station": "A: %d %d %d | %s", + + "item.jsblock.apg_door_drl": "APG (Variante Linea Disneyland Resorts)", + "item.jsblock.apg_glass_drl": "APG (Variante Linea Disneyland Resorts)", + "item.jsblock.apg_glass_end_drl": "APG (Variante Linea Disneyland Resorts)", + + "hud.jsblock.enquiry_machine.success": "Soldi Caricati: $%s", + "hud.jsblock.faresaver.success": "Lo sconto di $%d sarà usato alla prossima uscita da una stazione", + "hud.jsblock.faresaver.success.sarcasm": "Il così chiamato \"Sconto\" sarà usato alla prossima uscita da una stazione.", + "hud.jsblock.faresaver.fail": "Possiedi già uno sconto di $%d per il tuo prossimo viaggio!", + "hud.jsblock.faresaver.saved": "Hai salvato $%d.", + "hud.jsblock.faresaver.saved_sarcasm": "Hai perso $%d.", + "hud.jsblock.light_block.success": "Livello di luce: %d", + "hud.jsblock.kcr_name_sign.success": "Direzione Cambiata!", + "hud.jsblock.kcr_emg_stop_sign.success": "Direzione Cambiata!", + "hud.jsblock.operator_button.fail": "Hai bisogno della chiave da macchinista per usarlo!", + "hud.jsblock.subsidy_machine.success": "$%d sono stati aggiunti alla tua card, adesso hai $%d", + "hud.jsblock.subsidy_machine.fail": "Prima di riprovare, Attendi %d secondi.", + "gui.jsblock.brand": "Mod Joban Client", "gui.jsblock.butterfly_light.countdown": "Tempo di fermata rimasto quando inizia a lampeggiare", - "gui.jsblock.config.crash_log": "Mostra l'ultimo crash log", - "gui.jsblock.config.discard": "Cancella configurazione", "gui.jsblock.config.fail": "La Configurazione non può essere salvata!", + "gui.jsblock.config.version": "Versione %s", + "gui.jsblock.config.save": "Salva configurazione", + "gui.jsblock.config.discard": "Cancella configurazione", + "gui.jsblock.atlas_config.not_initialized": "TextureTextRenderer non è abilitato, Il nuovo rendering del testo è stato abilitato?", + "gui.jsblock.config.reset": "Azzerra configurazione", + "gui.jsblock.config.crash_log": "Mostra l'ultimo crash log", "gui.jsblock.config.latest_log": "Mostra l'ultimo log", - "gui.jsblock.config.listview.category.debug": "Debug", - "gui.jsblock.config.listview.category.experimental": "Sperimentale", "gui.jsblock.config.listview.category.general": "Generale", - "gui.jsblock.config.listview.title.custom_font": "Usa carattere personalizzato", - "gui.jsblock.config.listview.title.debug_mode": "Abilita modalità debug", + "gui.jsblock.config.listview.category.experimental": "Sperimentale", + "gui.jsblock.config.listview.category.debug": "Debug", "gui.jsblock.config.listview.title.disable_rendering": "Disabilita Rendering", + "gui.jsblock.config.listview.title.custom_font": "Usa carattere personalizzato", "gui.jsblock.config.listview.title.new_text_rendering": "Abilita il nuovo rendering sperimentale del testo", + "gui.jsblock.config.listview.title.debug_mode": "Abilita modalità debug", "gui.jsblock.config.listview.title.open_atlas_screen": "Visualizza l'atlas del testo del pacchetto di risorse", "gui.jsblock.config.listview.widget.open": "Apri", - "gui.jsblock.config.reset": "Azzerra configurazione", - "gui.jsblock.config.save": "Salva configurazione", - "gui.jsblock.config.version": "Versione %s", + "gui.jsblock.block_config.subtitle": "A: %d %d %d", + "gui.jsblock.block_config.subtitle_with_station": "A: %d %d %d | %s", + "gui.jsblock.block_config.save": "Salva Impostazioni", + "gui.jsblock.block_config.discard": "Elimina Impostazioni", "gui.jsblock.faresaver.currency": "Valuta", "gui.jsblock.faresaver.discount": "Quantità Sconto", - "gui.jsblock.pids.listview.title.filtered_platform": "Mostrando arrivi del %sPlatform %s", + "gui.jsblock.sound_looper.listview.title.sound_category": "Categoria/Sorgente Suono", + "gui.jsblock.sound_looper.listview.title.sound_volume": "Volume Suono (%)", + "gui.jsblock.sound_looper.listview.title.limit_range": "Limita la gamma sonora", + "gui.jsblock.sound_looper.listview.title.need_redstone": "Richiede l'alimentazione di pietrarossa", + "gui.jsblock.sound_looper.listview.title.pos1": "Posizione 1 (X, Y, Z)", + "gui.jsblock.sound_looper.listview.title.pos2": "Posizione 2 (X, Y, Z)", + "gui.jsblock.sound_looper.listview.title.repeat_tick": "Intervallo di ripetizione in Ticks (1s = 20 Ticks)", + "gui.jsblock.sound_looper.listview.title.sound_id": "L'Identificatore per il suono", + "gui.jsblock.mismatched_versions": "Per favore aggiorna la Mod Joban Client e prova di nuovo.", "gui.jsblock.pids.listview.title.hide_platform_number": "Nascondi numero binario", "gui.jsblock.pids.listview.title.pids_preset": "configurazione PIDS", - "gui.jsblock.pids.listview.widget.change_platform": "Cambia...", - "gui.jsblock.pids.listview.widget.choose_preset": "Seleziona", "gui.jsblock.pids.listview.widget.custom_message": "Messaggi personalizzati", "gui.jsblock.pids.listview.widget.row_hidden": "Nascondi arrivi", + "gui.jsblock.pids.listview.widget.choose_preset": "Seleziona", + "gui.jsblock.pids_preset.title": "Configurazione PIDS", + "gui.jsblock.pids_preset.subtitle": "Selezionato > %s", "gui.jsblock.pids_preset.listview.category.builtin": "Configurazioni pre-installate", "gui.jsblock.pids_preset.listview.category.custom": "Configurazione Personalizzata", - "gui.jsblock.pids_preset.listview.widget.choose": "Seleziona", "gui.jsblock.pids_preset.listview.widget.edit": "Modifica", + "gui.jsblock.pids_preset.listview.widget.choose": "Seleziona", "gui.jsblock.pids_preset.listview.widget.selected": "Selezionato", - "gui.jsblock.pids_preset.subtitle": "Selezionato > %s", - "gui.jsblock.pids_preset.title": "Configurazione PIDS", - "gui.jsblock.sound_looper.listview.title.limit_range": "Limita la gamma sonora", - "gui.jsblock.sound_looper.listview.title.need_redstone": "Richiede l'alimentazione di pietrarossa", - "gui.jsblock.sound_looper.listview.title.pos1": "Posizione 1 (X, Y, Z)", - "gui.jsblock.sound_looper.listview.title.pos2": "Posizione 2 (X, Y, Z)", - "gui.jsblock.sound_looper.listview.title.repeat_tick": "Intervallo di ripetizione in Ticks (1s = 20 Ticks)", - "gui.jsblock.sound_looper.listview.title.sound_category": "Categoria/Sorgente Suono", - "gui.jsblock.sound_looper.listview.title.sound_id": "L'Identificatore per il suono", - "gui.jsblock.sound_looper.listview.title.sound_volume": "Volume Suono (%)", - "gui.jsblock.subsidy_machine.cooldown": "Intervallo (Secondi)", + "gui.jsblock.pids.listview.title.filtered_platform": "Mostrando arrivi del %sPlatform %s", + "gui.jsblock.pids.listview.title.filtered_platform.nearby": "Vicino ", + "gui.jsblock.pids.listview.widget.change_platform": "Cambia...", + "gui.jsblock.pids_preset.pids_editor.title": "Editor PIDS", + "gui.jsblock.pids_preset.pids_editor.editingpreset": "Modificando preimpostazione", + "gui.jsblock.pids_preset.pids_editor.weather": "Mostra meteo", + "gui.jsblock.pids_preset.pids_editor.clock": "Mostra orologio", + "gui.jsblock.pids_preset.pids_editor.hiderow": "Nascondi riga %d", + "gui.jsblock.pids_preset.pids_editor.station": "Stazione", + "gui.jsblock.pids_preset.pids_editor.back": "Indietro", "gui.jsblock.subsidy_machine.currency": "$", "gui.jsblock.subsidy_machine.price": "Quantità di ricarica", - "gui.jsblock.widget.button.false": "no", + "gui.jsblock.subsidy_machine.cooldown": "Intervallo (Secondi)", "gui.jsblock.widget.button.true": "Sì", - "gui.jsblock.widget.numeric_text_field.decrement": "▼", - "gui.jsblock.widget.numeric_text_field.increment": "▲", + "gui.jsblock.widget.button.false": "no", "gui.jsblock.widget.search": "Cerca qui...", - "hud.jsblock.enquiry_machine.success": "Soldi Caricati: $%s", - "hud.jsblock.faresaver.fail": "Possiedi già uno sconto di $%d per il tuo prossimo viaggio!", - "hud.jsblock.faresaver.saved": "Hai salvato $%d.", - "hud.jsblock.faresaver.saved_sarcasm": "Hai perso $%d.", - "hud.jsblock.faresaver.success": "Lo sconto di $%d sarà usato alla prossima uscita da una stazione", - "hud.jsblock.faresaver.success.sarcasm": "Il così chiamato \"Sconto\" sarà usato alla prossima uscita da una stazione.", - "hud.jsblock.kcr_emg_stop_sign.success": "Direzione Cambiata!", - "hud.jsblock.kcr_name_sign.success": "Direzione Cambiata!", - "hud.jsblock.light_block.success": "Livello di luce: %d", - "hud.jsblock.operator_button.fail": "Hai bisogno della chiave da macchinista per usarlo!", - "hud.jsblock.subsidy_machine.fail": "Prima di riprovare, Attendi %d secondi.", - "hud.jsblock.subsidy_machine.success": "$%d sono stati aggiunti alla tua card, adesso hai $%d", - "item.jsblock.apg_door_drl": "APG (Variante Linea Disneyland Resorts)", - "item.jsblock.apg_glass_drl": "APG (Variante Linea Disneyland Resorts)", - "item.jsblock.apg_glass_end_drl": "APG (Variante Linea Disneyland Resorts)", - "itemGroup.jsblock.ceiling": "Blocchi Mod Joban Client - Soffitte", - "itemGroup.jsblock.main": "Blocchi Mod Joban Client", - "itemGroup.jsblock.pids": "Blocchi Mod Joban Client - PIDS" + "gui.jsblock.widget.numeric_text_field.increment": "▲", + "gui.jsblock.widget.numeric_text_field.decrement": "▼" } \ No newline at end of file diff --git a/fabric/src/main/resources/assets/jsblock/textures/editor/frame.png b/fabric/src/main/resources/assets/jsblock/textures/editor/frame.png new file mode 100644 index 00000000..a3a7e08d Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/editor/frame.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/clock.png b/fabric/src/main/resources/assets/jsblock/textures/ve/clock.png new file mode 100644 index 00000000..b9a45307 Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/clock.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/line1.png b/fabric/src/main/resources/assets/jsblock/textures/ve/line1.png new file mode 100644 index 00000000..091c1c4c Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/line1.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/line2.png b/fabric/src/main/resources/assets/jsblock/textures/ve/line2.png new file mode 100644 index 00000000..e03a15ad Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/line2.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/line3.png b/fabric/src/main/resources/assets/jsblock/textures/ve/line3.png new file mode 100644 index 00000000..8bcbe736 Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/line3.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/line4.png b/fabric/src/main/resources/assets/jsblock/textures/ve/line4.png new file mode 100644 index 00000000..57b89bd3 Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/line4.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/missing.png b/fabric/src/main/resources/assets/jsblock/textures/ve/missing.png new file mode 100644 index 00000000..f4a5d600 Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/missing.png differ diff --git a/fabric/src/main/resources/assets/jsblock/textures/ve/weather.png b/fabric/src/main/resources/assets/jsblock/textures/ve/weather.png new file mode 100644 index 00000000..2093fe40 Binary files /dev/null and b/fabric/src/main/resources/assets/jsblock/textures/ve/weather.png differ