Compare commits

...

10 Commits

Author SHA1 Message Date
BRanulf
a2b8d2c0bd 改完首次提交 2025-06-10 22:14:17 +08:00
Joseph Garcia
e562c8e3cd
Update README.md 2023-04-27 14:36:37 -05:00
Joseph Garcia
d7221978d2 update libgui 2021-07-31 23:21:56 -05:00
Joseph Garcia
6dd6ef5a0f gradle changes 2021-07-31 23:06:27 -05:00
Joseph Garcia
8565d6e5ea handle no json error 2021-01-28 09:17:18 -06:00
Joseph Garcia
b9a5edab1a update to 1.16.5, add close button 2021-01-19 13:59:41 -06:00
Joseph Garcia
ae9bbe4337
Merge pull request #2 from Abbanon/master
Removed Mixin stuff since this mod doesn't even use Mixins, and cleaned up some code
2021-01-18 14:55:40 -06:00
Abbanon
3851aef330 whoops, restored a line to its original value 2021-01-17 06:16:03 -05:00
Abbanon
191c6d987c
Update gradle.properties 2021-01-17 06:11:25 -05:00
Abbanon
702834a6ec
Update fabric.mod.json 2021-01-17 05:57:38 -05:00
22 changed files with 1091 additions and 239 deletions

28
NOTICE.md Normal file
View File

@ -0,0 +1,28 @@
# 项目名称command-gui-buttons-revive
# 原始项目:[command-gui-buttons](https://github.com/joseph-garcia/command-gui-buttons)
# 许可证GNU General Public License v3.0 (GPL-3.0)
## 版权声明
- 原始项目版权归 joseph-garcia 所有 (© [原项目版权年份,但是原项目的许可证也不告诉我这些信息,啥都是空的,作者都是我填的])
- 本衍生作品的修改部分版权归 BRanulf 所有 (© 2025)
## 修改声明
此项目是基于 command-gui-buttons 的二次修改版本。
## 许可继承
- 本项目**整体**遵循 [GNU GPL v3 许可证](LICENSE)
- 您有权利根据 GPL v3 条款:
✓ 免费使用、修改本代码
✓ 重新分发源代码或编译版本
- **义务**:若您分发修改后的版本,必须:
✓ 公开修改后的完整源代码
✓ 保留此声明文件及原始许可文件
✓ 明确标注您的修改内容
## 免责声明
本软件按“原样”提供,作者不承担任何明示或暗示的担保责任。
使用本软件产生的风险由用户自行承担。
> 原始项目仓库https://github.com/joseph-garcia/command-gui-buttons
> 本项目仓库:[您的项目URL]

View File

@ -2,7 +2,7 @@
Command GUI Buttons is a fabric mod for Minecraft that allows users to create custom command buttons on their clients. Users can bring up this menu in-game with the G key, type in the Name and Command they want to create a button for, and press the + to create. It will then show up as a button on their screen to use whenever they want, as the button will automatically type and execute the command they initially entered. Command GUI Buttons is a fabric mod for Minecraft that allows users to create custom command buttons on their clients. Users can bring up this menu in-game with the G key, type in the Name and Command they want to create a button for, and press the + to create. It will then show up as a button on their screen to use whenever they want, as the button will automatically type and execute the command they initially entered.
![Cmd GUI Demo](https://jangoscreations.com/wp-content/uploads/2020/12/mcss.png) ![mcss](https://user-images.githubusercontent.com/16052684/234972699-a2be88ae-e4df-4130-b5ce-0b881b827810.png)
Create buttons for preset chat messages, commands like '/warp home', or anything else that goes in the chat box. Create buttons for preset chat messages, commands like '/warp home', or anything else that goes in the chat box.
@ -12,8 +12,7 @@ Create buttons for preset chat messages, commands like '/warp home', or anything
- Type in the Name and Command you want to save into a button - Type in the Name and Command you want to save into a button
- Press the + button - Press the + button
Up to 20 buttons are currently supported! More are planned.
### How It Works ### How It Works
The list of commands are serialized into a JSON format and stored locally on the users systems. The mod writes any new commands into the JSON as new buttons are created, and loads the JSON at the start of the game. A local list instance exists for reading and loading the buttons each time, so that file reading is kept to a minimum. The list of commands are serialized into a JSON format and stored locally on the users systems. The mod writes any new commands into the JSON as new buttons are created, and loads the JSON at the start of the game. A local list instance exists for reading and loading the buttons each time, so that file reading is kept to a minimum.

View File

@ -1,10 +1,10 @@
plugins { plugins {
id 'fabric-loom' version '0.5-SNAPSHOT' id 'fabric-loom' version '1.9.2'
id 'maven-publish' id 'maven-publish'
} }
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = "21"
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = "21"
archivesBaseName = project.archives_base_name archivesBaseName = project.archives_base_name
version = project.mod_version version = project.mod_version
@ -28,24 +28,24 @@ dependencies {
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// Serialization // Serialization
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.56' implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.56'
compile 'com.googlecode.json-simple:json-simple:1.1.1' implementation 'com.googlecode.json-simple:json-simple:1.1.1'
implementation 'com.cedarsoftware:json-io:4.10.1' implementation 'com.cedarsoftware:json-io:4.10.1'
compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1' implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
// includes // includes
include 'com.alibaba:fastjson:1.2.56' include 'com.alibaba:fastjson:1.2.56'
include 'com.googlecode.json-simple:json-simple:1.1.1' include 'com.googlecode.json-simple:json-simple:1.1.1'
include 'com.cedarsoftware:json-io:4.10.1' include 'com.cedarsoftware:json-io:4.10.1'
include "io.github.cottonmc:LibGui:3.2.2+1.16.3" // include files("libs/LibGui-12.0.1+1.21.2.jar")
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them. // You may need to force-disable transitiveness on them.
modImplementation "io.github.cottonmc:LibGui:3.2.2+1.16.3" modImplementation files("libs/LibGui-12.0.1+1.21.2.jar")
} }
processResources { processResources {
@ -67,7 +67,7 @@ tasks.withType(JavaCompile) {
// if it is present. // if it is present.
// If you remove this task, sources will not be generated. // If you remove this task, sources will not be generated.
task sourcesJar(type: Jar, dependsOn: classes) { task sourcesJar(type: Jar, dependsOn: classes) {
classifier = "sources" archiveClassifier = "sources"
from sourceSets.main.allSource from sourceSets.main.allSource
} }

View File

@ -3,15 +3,15 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/use # check these on https://fabricmc.net/use
minecraft_version=1.16.4 minecraft_version=1.21.4
yarn_mappings=1.16.4+build.3 yarn_mappings=1.21.4+build.8
loader_version=0.10.6+build.214 loader_version=0.16.10
# Mod Properties # Mod Properties
mod_version = 1.0.0 mod_version = 1.14.514.011
maven_group = com.josyf.commandbuttons maven_group = com.josyf.commandbuttons
archives_base_name = command-gui-buttons archives_base_name = command-gui-buttons-revive
# Dependencies # Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.25.1+build.416-1.16 fabric_version=0.119.3+1.21.4

Binary file not shown.

View File

@ -1,6 +1,5 @@
#Sun Dec 20 14:49:23 CST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

2
gradlew vendored
View File

@ -130,7 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath

21
gradlew.bat vendored
View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,21 +64,6 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.cottonmc</groupId>
<artifactId>LibGui</artifactId>
<version>12.0.1+1.21.2</version>
<name>LibGui</name>
<description>Minecraft GUI Library</description>
<url>https://github.com/CottonMC/LibGui</url>
<licenses>
<license>
<name>MIT</name>
<url>https://github.com/CottonMC/LibGui/blob/HEAD/LICENSE</url>
</license>
</licenses>
<developers>
<developer>
<name>CottonMC</name>
<url>https://github.com/CottonMC</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>io.github.juuxel</groupId>
<artifactId>libninepatch</artifactId>
<version>1.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.fabricmc.fabric-api</groupId>
<artifactId>fabric-api-base</artifactId>
<version>0.4.48+c47b9d4373</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.fabricmc.fabric-api</groupId>
<artifactId>fabric-networking-api-v1</artifactId>
<version>4.3.3+56ec7ac673</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.fabricmc</groupId>
<artifactId>fabric-loader</artifactId>
<version>0.16.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.fabricmc.fabric-api</groupId>
<artifactId>fabric-lifecycle-events-v1</artifactId>
<version>2.3.22+c47b9d4373</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.fabricmc.fabric-api</groupId>
<artifactId>fabric-rendering-v1</artifactId>
<version>8.0.5+c47b9d4373</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.fabricmc.fabric-api</groupId>
<artifactId>fabric-resource-loader-v0</artifactId>
<version>3.0.5+c47b9d4373</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.github.cottonmc</groupId>
<artifactId>Jankson-Fabric</artifactId>
<version>9.0.0+j1.2.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,72 @@
package com.josyf.commandbuttons;
import com.josyf.commandbuttons.gui.ButtonGUI;
import com.josyf.commandbuttons.gui.ButtonGUIScreen;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
import org.json.simple.JSONObject;
import org.lwjgl.glfw.GLFW;
import java.util.ArrayList;
public class CommandButtons implements ModInitializer {
public static final String MOD_ID = "mgbuttons";
private static ArrayList<JSONObject> masterCommList;
public static void main(String[] args) {
}
@Override
public void onInitialize() {
assignGuiToKey();
initArray();
}
private void assignGuiToKey() {
// Currently assigns to the G key
KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
"key.commandbuttons.opengui", // The translation key of the keybinding's name
InputUtil.Type.KEYSYM, // The type of the keybinding, KEYSYM for keyboard, MOUSE for mouse.
GLFW.GLFW_KEY_G, // The keycode of the key
"gui.commandbuttons.mgbuttons" // The translation key of the keybinding's category.
));
ClientTickEvents.END_CLIENT_TICK.register(client -> {
while (keyBinding.wasPressed()) {
MinecraftClient.getInstance().setScreen(new ButtonGUIScreen(new ButtonGUI()));
//client.player.closeScreen();
}
});
}
public static void runCommand(String command) {
MinecraftClient.getInstance().player.sendChatMessage(command);
}
// Assign masterCommList to JSONArray<objects> (from commands.json). Runs once.
static void initArray() {
masterCommList = ConfigFile.getArrayFromJsonFile();
// If commands.json doesn't exist yet, start a global list variable for future creation
if (masterCommList == null) {
setMasterCommList(new ArrayList<>());
}
}
public static ArrayList<JSONObject> getMasterCommList() {
return masterCommList;
}
public static void setMasterCommList(ArrayList<JSONObject> commList) {
masterCommList = commList;
}
}

View File

@ -0,0 +1,105 @@
package com.josyf.commandbuttons;
import com.alibaba.fastjson.JSON;
import com.cedarsoftware.util.io.JsonWriter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.*;
import java.io.*;
import java.util.ArrayList;
public class ConfigFile {
private static final JSONParser parser = new JSONParser();
private static FileWriter fileWriter;
// Read commands.json, convert it to an array, and append A JSON OBJECT
public static void appendToFile(JSONObject jsonObject) {
try {
Object obj = parser.parse(new FileReader("commands.json"));
JSONArray array = (JSONArray) obj;
array.add(jsonObject);
writeToFile(array);
} catch (IOException e) {
System.out.println("Commands.json 不存在。正在创建...");
JSONArray jsonArray = new JSONArray();
jsonArray.add(jsonObject);
writeToFile(jsonArray);
} catch (ParseException e) {
e.printStackTrace();
}
}
public static void removeFromFile(JSONObject jsonObject) {
try {
Object obj = parser.parse(new FileReader("commands.json"));
JSONArray array = (JSONArray) obj;
array.remove(jsonObject);
writeToFile(array);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
}
// overwrites current commands.json w/ updated jsonArray
private static void writeToFile(JSONArray jsonArray) {
try {
fileWriter = new FileWriter("commands.json");
String jArrayToString = JSON.toJSONString(jsonArray);
String formattedJson = JsonWriter.formatJson(jArrayToString);
fileWriter.write(formattedJson);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// parses commands.json into array, loop through array and add JSONObjects. returns array
public static ArrayList<JSONObject> getArrayFromJsonFile() {
ArrayList<JSONObject> commandObjects = new ArrayList<>();
try {
// assign array to JSONArray using our commands.json as an object
Object obj = parser.parse(new FileReader("commands.json"));
JSONArray array = (JSONArray) obj;
// so "array" is now a JSONArray full of JSONObjects
// now we will iterate through the array and add COs to our local CO array
for (int i = 0; i < array.size(); i++) {
JSONObject childObject = (JSONObject)array.get(i);
commandObjects.add(childObject);
if (i >= 19) break;
}
return commandObjects;
} catch (IOException | ParseException e) {
System.out.println("Commands.json尚未初始化");
}
return null;
}
public static void addObjectToCommList(JSONObject jsonObject) {
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
commListCopy.add(jsonObject);
CommandButtons.setMasterCommList(commListCopy);
}
public static void removeObject(JSONObject objToRemove) {
// get masterCommList and remove object from list
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
commListCopy.remove(objToRemove);
// get commands.json
// remove corresponding button from json
removeFromFile(objToRemove);
}
}

View File

@ -0,0 +1,166 @@
package com.josyf.commandbuttons.gui;
import com.josyf.commandbuttons.CommandButtons;
import com.josyf.commandbuttons.ConfigFile;
import io.github.cottonmc.cotton.gui.client.BackgroundPainter;
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription;
import io.github.cottonmc.cotton.gui.widget.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.TranslatableText;
import org.json.simple.JSONObject;
import java.util.ArrayList;
public class ButtonGUI extends LightweightGuiDescription {
int xValue = 0;
int yValue = 1;
public ButtonGUI() {
// initialize root panel of GUI
WGridPanel root = new WGridPanel();
setupBackground(root);
addCloseButton(root);
// Add delete toggle button
WToggleButton delToggle = new WToggleButton(new TranslatableText("Delete"));
root.add(delToggle, 0, 11, 3, 1);
addSavedButtons(root, delToggle);
addCommandSection(root, delToggle);
root.validate(this);
}
private void addCloseButton(WGridPanel root) {
WButton escButton = new WButton(new TranslatableText("x"));
escButton.setOnClick(() -> MinecraftClient.getInstance().player.closeScreen());
root.add(escButton, 17, 1, 2, 2);
}
private void addCommandSection(WGridPanel root, WToggleButton toggle) {
// Add text field for command NAME entry
WTextField nameTextField = new WTextField();
nameTextField.setMaxLength(11);
nameTextField.setSuggestion("Name");
root.add(nameTextField, 0, 12, 6, 1);
// Add text field for command / entry
WTextField commandTextField = new WTextField();
commandTextField.setSuggestion("/command");
commandTextField.setMaxLength(300);
root.add(commandTextField, 6, 12, 11, 1);
// Add button for command entry
WButton addCmdBtn = new WButton(new TranslatableText("+"));
addCmdBtn.setOnClick(() -> addGUIButton(root, nameTextField, commandTextField, toggle));
root.add(addCmdBtn, 18, 12, 1, 1);
}
// Function to save newly added buttons to commands.json
private void addGUIButton(WGridPanel root, WTextField name, WTextField command, WToggleButton isDeleteToggled) {
// Only add the button if there are contents in both
if (!name.getText().equals("") && !command.getText().equals("")) {
// Create a new Json object & append to masterCommList
JSONObject newJsonObject = new JSONObject();
newJsonObject.put("name", name.getText());
newJsonObject.put("command", command.getText());
if (!isListTooLong()) {
String commandString = command.getText();
WButton button = new WButton(new TranslatableText(name.getText()));
button.setOnClick(() -> {
if (isDeleteToggled.getToggle()) {
ConfigFile.removeObject(newJsonObject);
root.remove(button);
} else {
CommandButtons.runCommand(commandString);
}
});
root.add(button, xValue, yValue, 4, 1);
// append the buttons to masterList for future loading
ConfigFile.addObjectToCommList(newJsonObject);
ConfigFile.appendToFile(newJsonObject);
adjustBounds();
}
name.setText("");
command.setText("");
root.validate(this);
} else {
System.out.println("未输入名称和数值!");
}
}
// function to load buttons from commands.json
private void addGUIButton(WGridPanel root, String name, String command, WToggleButton isDeleteToggled, JSONObject object) {
if (!name.equals("") && !command.equals("")) {
WButton button = new WButton(new TranslatableText(name));
button.setOnClick(() -> {
if (isDeleteToggled.getToggle()) {
ConfigFile.removeObject(object);
root.remove(button);
} else {
CommandButtons.runCommand(command);
}
});
root.add(button, xValue, yValue, 4, 1);
adjustBounds();
root.validate(this);
} else {
System.out.println("未输入名称和数值!");
}
}
// Array will contain String class types. Convert these to objects.
private void addSavedButtons(WGridPanel root, WToggleButton toggle) {
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
// Then convert the objects to buttons
if (commListCopy != null) {
for (int i = 0; i < commListCopy.size(); i++) {
JSONObject object = commListCopy.get(i);
String name = commListCopy.get(i).get("name").toString();
String command = commListCopy.get(i).get("command").toString();
addGUIButton(root, name, command, toggle, object);
if (i >= 19) break;
}
}
}
private void adjustBounds() {
if (xValue % 12 == 0 && xValue != 0) {
yValue += 2;
xValue = 0;
} else {
xValue += 4;
}
}
private boolean isListTooLong() {
return CommandButtons.getMasterCommList().size() > 19;
}
// Change background panel color to transparent black
@Override
public void addPainters() {
super.addPainters();
this.rootPanel.setBackgroundPainter(BackgroundPainter.createColorful(0x4D000000));
}
private void setupBackground(WGridPanel root) {
setRootPanel(root);
root.setSize(350, 240);
}
}

View File

@ -0,0 +1,14 @@
package com.josyf.commandbuttons.gui;
import io.github.cottonmc.cotton.gui.GuiDescription;
import io.github.cottonmc.cotton.gui.client.CottonClientScreen;
public class ButtonGUIScreen extends CottonClientScreen {
public ButtonGUIScreen(GuiDescription description) {
super(description);
}
}

View File

@ -1,58 +1,59 @@
package com.josyf.commandbuttons; package com.josyf.commandbuttons;
import com.josyf.commandbuttons.gui.ButtonGUI; import com.josyf.commandbuttons.gui.ButtonGUI;
import com.josyf.commandbuttons.gui.ButtonGUIScreen; import com.josyf.commandbuttons.gui.ButtonGUIScreen;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
import net.minecraft.client.options.KeyBinding; import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil; import net.minecraft.client.util.InputUtil;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class CommandButtons implements ModInitializer { public class CommandButtons implements ModInitializer {
public static final String MOD_ID = "mgbuttons"; public static final String MOD_ID = "mgbuttons";
private static ArrayList<JSONObject> masterCommList; private static ArrayList<JSONObject> masterCommList;
public static void main(String[] args) {
}
@Override @Override
public void onInitialize() { public void onInitialize() {
assignGuiToKey(); assignGuiToKey();
initArray(); initArray();
} }
private void assignGuiToKey() { private void assignGuiToKey() {
// Currently assigns to the G key // 默认G键触发GUI
KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding( KeyBinding keyBinding = KeyBindingHelper.registerKeyBinding(new KeyBinding(
"key.commandbuttons.opengui", // The translation key of the keybinding's name "key.commandbuttons.opengui",
InputUtil.Type.KEYSYM, // The type of the keybinding, KEYSYM for keyboard, MOUSE for mouse. InputUtil.Type.KEYSYM,
GLFW.GLFW_KEY_G, // The keycode of the key GLFW.GLFW_KEY_G,
"gui.commandbuttons.mgbuttons" // The translation key of the keybinding's category. "gui.commandbuttons.mgbuttons"
)); ));
ClientTickEvents.END_CLIENT_TICK.register(client -> { ClientTickEvents.END_CLIENT_TICK.register(client -> {
while (keyBinding.wasPressed()) { while (keyBinding.wasPressed()) {
MinecraftClient.getInstance().openScreen(new ButtonGUIScreen(new ButtonGUI())); MinecraftClient.getInstance().setScreen(new ButtonGUIScreen(new ButtonGUI()));
//client.player.closeScreen();
} }
}); });
} }
public static void runCommand(String command) {
MinecraftClient.getInstance().player.sendChatMessage(command); // 执行命令一行一行来
public static void runCommands(List<String> commands) {
MinecraftClient client = MinecraftClient.getInstance();
if (client != null && client.player != null && client.player.networkHandler != null) {
for (String command : commands) {
if (command != null && !command.trim().isEmpty()) {
client.player.networkHandler.sendChatCommand(command.trim());
}
}
}
} }
// Assign masterCommList to JSONArray<objects> (from commands.json). Runs once.
static void initArray() { static void initArray() {
masterCommList = ConfigFile.getArrayFromJsonFile(); masterCommList = ConfigFile.getArrayFromJsonFile();
// If commands.json doesn't exist yet, start a global list variable for future creation // If commands.json doesn't exist yet, start a global list variable for future creation
@ -69,5 +70,10 @@ public class CommandButtons implements ModInitializer {
masterCommList = commList; masterCommList = commList;
} }
public static void refreshMasterCommList() {
masterCommList = ConfigFile.getArrayFromJsonFile();
if (masterCommList == null) {
masterCommList = new ArrayList<>();
}
}
} }

View File

@ -4,49 +4,86 @@ import com.alibaba.fastjson.JSON;
import com.cedarsoftware.util.io.JsonWriter; import com.cedarsoftware.util.io.JsonWriter;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; import org.json.simple.parser.ParseException;
import org.json.simple.parser.*;
import java.io.*; import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class ConfigFile { public class ConfigFile {
private static final JSONParser parser = new JSONParser(); private static final JSONParser parser = new JSONParser();
private static FileWriter fileWriter; private static final String CONFIG_FILE_NAME = "commands.json";
// Read commands.json, convert it to an array, and append A JSON OBJECT // Read commands.json, convert it to an array, and append A JSON OBJECT
public static void appendToFile(JSONObject jsonObject) { public static void appendToFile(JSONObject jsonObject) {
try { JSONArray array = getJsonArrayFromFile();
Object obj = parser.parse(new FileReader("commands.json")); if (array == null) {
JSONArray array = (JSONArray) obj; array = new JSONArray();
array.add(jsonObject); }
writeToFile(array); array.add(jsonObject);
} catch (IOException e) { writeToFile(array);
System.out.println("Commands.json doesn't exist. Creating one...!"); }
JSONArray jsonArray = new JSONArray();
jsonArray.add(jsonObject); // 按名称
writeToFile(jsonArray); public static void removeObjectByName(String name) {
} catch (ParseException e) { JSONArray array = getJsonArrayFromFile();
e.printStackTrace(); if (array == null) {
return;
}
JSONArray newArray = new JSONArray();
boolean removed = false;
for (Object obj : array) {
if (obj instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) obj;
if (jsonObject.containsKey("name") && jsonObject.get("name").equals(name)) {
removed = true;
} else {
newArray.add(jsonObject);
}
}
}
if (removed) {
writeToFile(newArray);
} }
} }
public static void removeFromFile(JSONObject jsonObject) { public static void updateObjectByName(String originalName, JSONObject updatedObject) {
try { JSONArray array = getJsonArrayFromFile();
Object obj = parser.parse(new FileReader("commands.json")); if (array == null) {
JSONArray array = (JSONArray) obj; return;
array.remove(jsonObject);
writeToFile(array);
} catch (IOException | ParseException e) {
e.printStackTrace();
} }
JSONArray newArray = new JSONArray();
boolean updated = false;
for (Object obj : array) {
if (obj instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) obj;
if (jsonObject.containsKey("name") && jsonObject.get("name").equals(originalName)) {
newArray.add(updatedObject);
updated = true;
} else {
newArray.add(jsonObject);
}
}
}
if (updated) {
writeToFile(newArray);
} else {
System.err.println("未找到名称为'" + originalName + "'的命令以进行更新。");
}
writeToFile(newArray);
} }
// overwrites current commands.json w/ updated jsonArray // overwrites current commands.json w/ updated jsonArray
private static void writeToFile(JSONArray jsonArray) { private static void writeToFile(JSONArray jsonArray) {
FileWriter fileWriter = null;
try { try {
fileWriter = new FileWriter("commands.json"); fileWriter = new FileWriter(CONFIG_FILE_NAME);
// Use fastjson for writing as it handles JSONArray better with JsonWriter formatting
String jArrayToString = JSON.toJSONString(jsonArray); String jArrayToString = JSON.toJSONString(jsonArray);
String formattedJson = JsonWriter.formatJson(jArrayToString); String formattedJson = JsonWriter.formatJson(jArrayToString);
fileWriter.write(formattedJson); fileWriter.write(formattedJson);
@ -54,56 +91,94 @@ public class ConfigFile {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {
fileWriter.flush(); if (fileWriter != null) {
fileWriter.close(); fileWriter.flush();
fileWriter.close();
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
// parses commands.json into array, loop through array and add JSONObjects. returns array // parses commands.json into JSONArray
public static ArrayList<JSONObject> getArrayFromJsonFile() { private static JSONArray getJsonArrayFromFile() {
ArrayList<JSONObject> commandObjects = new ArrayList<>(); try (FileReader reader = new FileReader(CONFIG_FILE_NAME)) {
try { Object obj = parser.parse(reader);
// assign array to JSONArray using our commands.json as an object if (obj instanceof JSONArray) {
Object obj = parser.parse(new FileReader("commands.json")); return (JSONArray) obj;
JSONArray array = (JSONArray) obj; } else if (obj instanceof JSONObject) {
// so "array" is now a JSONArray full of JSONObjects
// now we will iterate through the array and add COs to our local CO array System.err.println("配置文件不是一个 JSON 数组。返回空数组。");
for (int i = 0; i < array.size(); i++) { return new JSONArray();
JSONObject childObject = (JSONObject)array.get(i); } else {
commandObjects.add(childObject); System.err.println("配置文件包含意外的内容。返回空数组。");
System.out.println(i); return new JSONArray();
if (i >= 19) break;
} }
return commandObjects;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); System.out.println("Commands.json文件不存在或读取错误。返回null。");
return null;
} catch (ParseException e) { } catch (ParseException e) {
System.err.println("解析 commands.json 时出错:" + e.getMessage());
e.printStackTrace(); e.printStackTrace();
return new JSONArray();
} }
return null;
} }
public static void addObjectToCommList(JSONObject jsonObject) {
// parses commands.json into
public static ArrayList<JSONObject> getArrayFromJsonFile() {
JSONArray array = getJsonArrayFromFile();
if (array == null) {
return null;
}
ArrayList<JSONObject> commandObjects = new ArrayList<>();
for (Object obj : array) {
if (obj instanceof JSONObject) {
commandObjects.add((JSONObject) obj);
}
}
return commandObjects;
}
// 添加
public static void addObject(JSONObject jsonObject) {
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList(); ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
if (commListCopy == null) {
commListCopy = new ArrayList<>();
CommandButtons.setMasterCommList(commListCopy);
}
commListCopy.add(jsonObject); commListCopy.add(jsonObject);
CommandButtons.setMasterCommList(commListCopy); appendToFile(jsonObject);
} }
// 移除
public static void removeObject(JSONObject objToRemove) { public static void removeObject(JSONObject objToRemove) {
// get masterCommList and remove object from list
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList(); ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
commListCopy.remove(objToRemove); if (commListCopy != null) {
commListCopy.removeIf(obj -> obj.containsKey("name") && objToRemove.containsKey("name") && obj.get("name").equals(objToRemove.get("name")));
// get commands.json }
// remove corresponding button from json if (objToRemove.containsKey("name")) {
removeFromFile(objToRemove); removeObjectByName(objToRemove.get("name").toString());
} else {
System.err.println("无法删除没有“name”字段的对象。");
}
} }
// 编辑
public static void updateObject(String originalName, JSONObject updatedObject) {
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
if (commListCopy != null) {
for (int i = 0; i < commListCopy.size(); i++) {
JSONObject obj = commListCopy.get(i);
if (obj.containsKey("name") && obj.get("name").equals(originalName)) {
commListCopy.set(i, updatedObject);
break;
}
}
}
updateObjectByName(originalName, updatedObject);
}
} }

View File

@ -5,160 +5,126 @@ import com.josyf.commandbuttons.ConfigFile;
import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.BackgroundPainter;
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription;
import io.github.cottonmc.cotton.gui.widget.*; import io.github.cottonmc.cotton.gui.widget.*;
import net.minecraft.text.TranslatableText; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment;
import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment;
import net.minecraft.client.MinecraftClient;
import io.github.cottonmc.cotton.gui.widget.data.Insets;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class ButtonGUI extends LightweightGuiDescription { public class ButtonGUI extends LightweightGuiDescription {
int xValue = 0; private final Screen parentScreen;
int yValue = 1;
public ButtonGUI() { public ButtonGUI() {
this.parentScreen = MinecraftClient.getInstance().currentScreen;
// initialize root panel of GUI // initialize root panel of GUI
WGridPanel root = new WGridPanel(); WGridPanel root = new WGridPanel();
setRootPanel(root);
root.setSize(300, 200);
root.setInsets(new Insets(5));
setupBackground(root); setupBackground(root);
// Text GUI, not needed yet WLabel title = new WLabel(Text.translatable("gui.commandbuttons.title"), 0xcdcdcd);
// WLabel label = new WLabel(new LiteralText("Test"), 0xFFFFFF); title.setHorizontalAlignment(HorizontalAlignment.CENTER);
// root.add(label, 0, 4, 2, 1); root.add(title, 0, 0, 18, 1);
// Add delete toggle button addCloseButton(root);
WToggleButton delToggle = new WToggleButton(new TranslatableText("Delete"));
root.add(delToggle, 17, 0, 3, 1); WGridPanel commandListPanel = new WGridPanel();
WScrollPanel scrollPanel = new WScrollPanel(commandListPanel);
root.add(scrollPanel, 0, 2, 18, 8);
addSavedButtons(commandListPanel);
WButton addCommandButton = new WButton(Text.translatable("gui.commandbuttons.add_command"));
addCommandButton.setOnClick(this::openCreateCommandScreen);
root.add(addCommandButton, 0, 11, 18, 1);
addSavedButtons(root, delToggle);
addCommandSection(root, delToggle);
root.validate(this); root.validate(this);
} }
private void addCommandSection(WGridPanel root, WToggleButton toggle) { // 背景
// Add text field for command NAME entry private void setupBackground(WGridPanel root) {
WTextField nameTextField = new WTextField(); root.setBackgroundPainter(BackgroundPainter.createColorful(0x4D000000));
nameTextField.setMaxLength(11);
nameTextField.setSuggestion("Name");
root.add(nameTextField, 0, 12, 6, 1);
// Add text field for command / entry
WTextField commandTextField = new WTextField();
commandTextField.setSuggestion("/command");
commandTextField.setMaxLength(300);
root.add(commandTextField, 6, 12, 11, 1);
// Add button for command entry
WButton addCmdBtn = new WButton(new TranslatableText("+"));
addCmdBtn.setOnClick(() -> {
addGUIButton(root, nameTextField, commandTextField, toggle);
});
root.add(addCmdBtn, 18, 12, 1, 1);
} }
// Function to save newly added buttons to commands.json // 关闭按钮
private void addGUIButton(WGridPanel root, WTextField name, WTextField command, WToggleButton isDeleteToggled) { private void addCloseButton(WGridPanel root) {
// Only add the button if there are contents in both WButton escButton = new WButton(Text.translatable("gui.commandbuttons.close"));
if (!name.getText().equals("") && !command.getText().equals("")) { escButton.setOnClick(() -> MinecraftClient.getInstance().setScreen(this.parentScreen));
// Create a new Json object & append to masterCommList root.add(escButton, 17, 0, 1, 1);
JSONObject newJsonObject = new JSONObject(); }
newJsonObject.put("name", name.getText());
newJsonObject.put("command", command.getText());
if (!isListTooLong()) { // 保存的设置
String commandString = command.getText(); private void addSavedButtons(WGridPanel commandListPanel) {
WButton button = new WButton(new TranslatableText(name.getText())); ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
button.setOnClick(() -> { if (commListCopy != null) {
if (isDeleteToggled.getToggle()) { int yOffset = 0;
ConfigFile.removeObject(newJsonObject); for (JSONObject object : commListCopy) {
root.remove(button); if (object.containsKey("name") && object.containsKey("commands")) {
} else { String name = object.get("name").toString();
CommandButtons.runCommand(commandString); JSONArray commandsArray = (JSONArray) object.get("commands");
List<String> commands = new ArrayList<>();
for (Object cmdObj : commandsArray) {
if (cmdObj instanceof String) {
commands.add((String) cmdObj);
}
} }
}); WGridPanel commandEntryPanel = new WGridPanel();
root.add(button, xValue, yValue, 4, 1); commandEntryPanel.setSize(commandListPanel.getWidth(), 20);
// append the buttons to masterList for future loading WButton executeButton = new WButton(Text.literal(name));
ConfigFile.addObjectToCommList(newJsonObject); executeButton.setOnClick(() -> {
ConfigFile.appendToFile(newJsonObject); CommandButtons.runCommands(commands);
MinecraftClient.getInstance().setScreen(this.parentScreen);
});
commandEntryPanel.add(executeButton, 0, 0, 14, 1);
adjustBounds(); WButton editButton = new WButton(Text.translatable("gui.commandbuttons.edit"));
} editButton.setOnClick(() -> openEditCommandScreen(object));
commandEntryPanel.add(editButton, 15, 0, 3, 1);
name.setText(""); commandListPanel.add(commandEntryPanel, 0, yOffset, 18, 1);
command.setText(""); yOffset += 1;
root.validate(this);
} else {
System.out.println("No name and value entered!");
}
}
// function to load buttons from commands.json
private void addGUIButton(WGridPanel root, String name, String command, WToggleButton isDeleteToggled, JSONObject object) {
if (!name.equals("") && !command.equals("")) {
WButton button = new WButton(new TranslatableText(name));
button.setOnClick(() -> {
if (isDeleteToggled.getToggle()) {
ConfigFile.removeObject(object);
root.remove(button);
} else { } else {
CommandButtons.runCommand(command); System.err.println("在 commands.json 中跳过格式错误的命令对象:" + object.toJSONString());
} }
});
root.add(button, xValue, yValue, 4, 1);
adjustBounds();
root.validate(this);
} else {
System.out.println("No name and value entered!");
}
}
// Array will contain String class types. Convert these to objects.
private void addSavedButtons(WGridPanel root, WToggleButton toggle) {
ArrayList<JSONObject> commListCopy = CommandButtons.getMasterCommList();
// Then convert the objects to buttons
if (commListCopy != null) {
for (int i = 0; i < commListCopy.size(); i++) {
JSONObject object = commListCopy.get(i);
String name = commListCopy.get(i).get("name").toString();
String command = commListCopy.get(i).get("command").toString();
addGUIButton(root, name, command, toggle, object);
if (i >= 19) break;
} }
} }
}
// 新建按钮
private void openCreateCommandScreen() {
MinecraftClient.getInstance().setScreen(new ButtonGUIScreen(new CreateCommandGUI(this.parentScreen), this.parentScreen));
}
// 编辑按钮
private void openEditCommandScreen(JSONObject commandObject) {
MinecraftClient.getInstance().setScreen(new ButtonGUIScreen(new EditCommandGUI(commandObject, this.parentScreen), this.parentScreen));
} }
private void adjustBounds() {
if (xValue % 12 == 0 && xValue != 0) {
yValue += 2;
xValue = 0;
} else {
xValue += 4;
}
}
private boolean isListTooLong() {
return CommandButtons.getMasterCommList().size() > 19;
}
// Change background panel color to transparent black
@Override @Override
public void addPainters() { public void addPainters() {
super.addPainters();
this.rootPanel.setBackgroundPainter(BackgroundPainter.createColorful(0x4D000000));
} }
private void setupBackground(WGridPanel root) { @Override
setRootPanel(root); public boolean isTitleVisible() {
root.setSize(350, 240); return true;
} }
@Override
public int getTitleColor() {
return 0x404040;
}
} }

View File

@ -2,13 +2,25 @@ package com.josyf.commandbuttons.gui;
import io.github.cottonmc.cotton.gui.GuiDescription; import io.github.cottonmc.cotton.gui.GuiDescription;
import io.github.cottonmc.cotton.gui.client.CottonClientScreen; import io.github.cottonmc.cotton.gui.client.CottonClientScreen;
import net.minecraft.client.gui.screen.Screen;
public class ButtonGUIScreen extends CottonClientScreen { public class ButtonGUIScreen extends CottonClientScreen {
private final Screen parent;
public ButtonGUIScreen(GuiDescription description) { public ButtonGUIScreen(GuiDescription description) {
super(description); this(description, null);
} }
public ButtonGUIScreen(GuiDescription description, Screen parent) {
super(description);
this.parent = parent;
}
@Override
public void close() {
if (this.client != null) {
this.client.setScreen(this.parent);
}
}
} }

View File

@ -0,0 +1,142 @@
package com.josyf.commandbuttons.gui;
import com.josyf.commandbuttons.CommandButtons;
import com.josyf.commandbuttons.ConfigFile;
import io.github.cottonmc.cotton.gui.client.BackgroundPainter;
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription;
import io.github.cottonmc.cotton.gui.widget.*;
import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import io.github.cottonmc.cotton.gui.widget.data.Insets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class CreateCommandGUI extends LightweightGuiDescription {
private final Screen parentScreen;
private final WGridPanel commandsPanel;
private final ArrayList<WTextField> commandTextFields = new ArrayList<>();
private int nextCommandRow = 0;
public CreateCommandGUI(Screen parentScreen) {
this.parentScreen = parentScreen;
WGridPanel root = new WGridPanel();
setRootPanel(root);
root.setSize(280, 220);
root.setInsets(new Insets(5));
root.setBackgroundPainter(BackgroundPainter.createColorful(0x4D000000));
WLabel title = new WLabel(Text.translatable("gui.commandbuttons.create_title"), getTitleColor());
title.setHorizontalAlignment(HorizontalAlignment.CENTER);
root.add(title, 0, 0, 16, 1);
WLabel nameLabel = new WLabel(Text.translatable("gui.commandbuttons.name_label"));
root.add(nameLabel, 0, 2);
WTextField nameField = new WTextField();
nameField.setSuggestion(Text.translatable("gui.commandbuttons.commands_suggestion_name"));
root.add(nameField, 0, 3, 16, 1);
WLabel commandsLabel = new WLabel(Text.translatable("gui.commandbuttons.commands_label"));
root.add(commandsLabel, 0, 5);
commandsPanel = new WGridPanel();
WScrollPanel scrollPanel = new WScrollPanel(commandsPanel);
root.add(scrollPanel, 0, 6, 16, 8);
addCommandTextField("");
rebuildCommandsPanel();
WButton addCommandButton = new WButton(Text.literal("+"));
addCommandButton.setOnClick(() -> {
addCommandTextField("");
rebuildCommandsPanel();
});
root.add(addCommandButton, 16, 6, 1, 1);
WButton createButton = new WButton(Text.translatable("gui.commandbuttons.create"));
createButton.setOnClick(() -> {
String name = nameField.getText().trim();
List<String> commands = commandTextFields.stream()
.map(WTextField::getText)
.map(String::trim)
.filter(cmd -> !cmd.isEmpty())
.collect(Collectors.toList());
if (!name.isEmpty() && !commands.isEmpty()) {
JSONObject newCommand = new JSONObject();
newCommand.put("name", name);
JSONArray commandsArray = new JSONArray();
commandsArray.addAll(commands);
newCommand.put("commands", commandsArray);
ConfigFile.addObject(newCommand);
CommandButtons.refreshMasterCommList();
MinecraftClient.getInstance().setScreen(this.parentScreen);
} else {
System.out.println("名称或命令字段为空!");
}
});
root.add(createButton, 0, 15, 8, 1);
WButton cancelButton = new WButton(Text.translatable("gui.commandbuttons.cancel"));
cancelButton.setOnClick(() -> {
MinecraftClient.getInstance().setScreen(this.parentScreen);
});
root.add(cancelButton, 8, 15, 8, 1);
root.validate(this);
}
private void addCommandTextField(String initialText) {
WTextField textField = new WTextField();
textField.setText(initialText);
textField.setSuggestion(Text.translatable("gui.commandbuttons.commands_suggestion_command"));
commandTextFields.add(textField);
}
private void rebuildCommandsPanel() {
List<WWidget> currentPanelChildren = commandsPanel.streamChildren().collect(Collectors.toList());
for (WWidget child : currentPanelChildren) {
commandsPanel.remove(child);
}
nextCommandRow = 0;
for (WTextField textField : commandTextFields) {
commandsPanel.add(textField, 0, nextCommandRow, 15, 1);
WButton removeButton = new WButton(Text.literal("-"));
removeButton.setOnClick(() -> {
commandTextFields.remove(textField);
rebuildCommandsPanel();
});
commandsPanel.add(removeButton, 15, nextCommandRow, 1, 1);
nextCommandRow += 1;
}
if (commandTextFields.isEmpty()) {
addCommandTextField("");
rebuildCommandsPanel();
return;
}
commandsPanel.validate(this);
}
@Override
public boolean isTitleVisible() {
return false;
}
@Override
public int getTitleColor() {
return 0x404040;
}
}

View File

@ -0,0 +1,168 @@
package com.josyf.commandbuttons.gui;
import com.josyf.commandbuttons.CommandButtons;
import com.josyf.commandbuttons.ConfigFile;
import io.github.cottonmc.cotton.gui.client.BackgroundPainter;
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription;
import io.github.cottonmc.cotton.gui.widget.*;
import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import io.github.cottonmc.cotton.gui.widget.data.Insets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class EditCommandGUI extends LightweightGuiDescription {
private final JSONObject originalCommand;
private final String originalName;
private final Screen parentScreen;
private final WGridPanel commandsPanel;
private final ArrayList<WTextField> commandTextFields = new ArrayList<>();
private int nextCommandRow = 0;
public EditCommandGUI(JSONObject commandObject, Screen parentScreen) {
this.originalCommand = commandObject;
this.originalName = commandObject.containsKey("name") ? originalCommand.get("name").toString() : "";
this.parentScreen = parentScreen;
WGridPanel root = new WGridPanel();
setRootPanel(root);
root.setSize(280, 250);
root.setInsets(new Insets(5));
root.setBackgroundPainter(BackgroundPainter.createColorful(0x4D000000));
WLabel title = new WLabel(Text.translatable("gui.commandbuttons.edit_title"), getTitleColor());
title.setHorizontalAlignment(HorizontalAlignment.CENTER);
root.add(title, 0, 0, 16, 1);
WLabel nameLabel = new WLabel(Text.translatable("gui.commandbuttons.name_label"));
root.add(nameLabel, 0, 2);
WTextField nameField = new WTextField();
nameField.setText(originalName);
root.add(nameField, 0, 3, 16, 1);
WLabel commandsLabel = new WLabel(Text.translatable("gui.commandbuttons.commands_label"));
root.add(commandsLabel, 0, 5);
commandsPanel = new WGridPanel();
WScrollPanel scrollPanel = new WScrollPanel(commandsPanel);
root.add(scrollPanel, 0, 6, 16, 8);
loadCommandsIntoFields();
rebuildCommandsPanel();
WButton addCommandButton = new WButton(Text.literal("+"));
addCommandButton.setOnClick(() -> {
addCommandTextField("");
rebuildCommandsPanel();
});
root.add(addCommandButton, 16, 6, 1, 1);
WButton saveButton = new WButton(Text.translatable("gui.commandbuttons.save"));
saveButton.setOnClick(() -> {
String newName = nameField.getText().trim();
List<String> commands = commandTextFields.stream()
.map(WTextField::getText)
.map(String::trim)
.filter(cmd -> !cmd.isEmpty())
.collect(Collectors.toList());
if (!newName.isEmpty() && !commands.isEmpty()) {
JSONObject updatedCommand = new JSONObject();
updatedCommand.put("name", newName);
JSONArray commandsArray = new JSONArray();
commandsArray.addAll(commands);
updatedCommand.put("commands", commandsArray);
ConfigFile.updateObject(originalName, updatedCommand);
CommandButtons.refreshMasterCommList();
MinecraftClient.getInstance().setScreen(this.parentScreen);
} else {
System.out.println("名称或命令字段为空!");
}
});
root.add(saveButton, 0, 15, 8, 1);
WButton deleteButton = new WButton(Text.translatable("gui.commandbuttons.delete"));
deleteButton.setOnClick(() -> {
ConfigFile.removeObject(originalCommand);
CommandButtons.refreshMasterCommList();
MinecraftClient.getInstance().setScreen(this.parentScreen);
});
root.add(deleteButton, 0, 16, 8, 1);
WButton cancelButton = new WButton(Text.translatable("gui.commandbuttons.cancel"));
cancelButton.setOnClick(() -> {
MinecraftClient.getInstance().setScreen(this.parentScreen);
});
root.add(cancelButton, 8, 15, 8, 1);
root.validate(this);
}
private void loadCommandsIntoFields() {
commandTextFields.clear();
if (originalCommand.containsKey("commands") && originalCommand.get("commands") instanceof JSONArray) {
JSONArray commandsArray = (JSONArray) originalCommand.get("commands");
for (Object cmdObj : commandsArray) {
if (cmdObj instanceof String) {
addCommandTextField((String) cmdObj);
}
}
}
if (commandTextFields.isEmpty()) {
addCommandTextField("");
}
}
private void addCommandTextField(String initialText) {
WTextField textField = new WTextField();
textField.setText(initialText);
textField.setSuggestion(Text.of(Text.translatable("gui.commandbuttons.commands_suggestion_command")));
commandTextFields.add(textField);
}
private void rebuildCommandsPanel() {
List<WWidget> currentPanelChildren = commandsPanel.streamChildren().collect(Collectors.toList());
for (WWidget child : currentPanelChildren) {
commandsPanel.remove(child);
}
nextCommandRow = 0;
for (WTextField textField : commandTextFields) {
commandsPanel.add(textField, 0, nextCommandRow, 15, 1);
WButton removeButton = new WButton(Text.literal("-"));
removeButton.setOnClick(() -> {
commandTextFields.remove(textField);
rebuildCommandsPanel();
});
commandsPanel.add(removeButton, 15, nextCommandRow, 1, 1);
nextCommandRow += 1;
}
if (commandTextFields.isEmpty()) {
addCommandTextField("");
rebuildCommandsPanel();
return;
}
commandsPanel.validate(this);
}
@Override
public boolean isTitleVisible() {
return false;
}
@Override
public int getTitleColor() {
return 0x404040;
}
}

View File

@ -0,0 +1,18 @@
{
"key.commandbuttons.opengui": "Open Command Buttons GUI",
"gui.commandbuttons.mgbuttons": "Command Buttons",
"gui.commandbuttons.title": "Command Buttons",
"gui.commandbuttons.close": "X",
"gui.commandbuttons.add_command": "Add New Command",
"gui.commandbuttons.edit": "Edit",
"gui.commandbuttons.create_title": "Create New Command",
"gui.commandbuttons.edit_title": "Edit Command",
"gui.commandbuttons.name_label": "Name:",
"gui.commandbuttons.commands_label": "Commands (one per line, no / ):",
"gui.commandbuttons.create": "Create",
"gui.commandbuttons.save": "Save",
"gui.commandbuttons.delete": "Delete",
"gui.commandbuttons.cancel": "Cancel",
"gui.commandbuttons.commands_suggestion_name": "Command buttons name",
"gui.commandbuttons.commands_suggestion_command": "Command"
}

View File

@ -0,0 +1,18 @@
{
"key.commandbuttons.opengui": "打开命令按钮界面",
"gui.commandbuttons.mgbuttons": "命令按钮",
"gui.commandbuttons.title": "命令按钮",
"gui.commandbuttons.close": "X",
"gui.commandbuttons.add_command": "添加新命令",
"gui.commandbuttons.edit": "编辑",
"gui.commandbuttons.create_title": "创建新命令",
"gui.commandbuttons.edit_title": "编辑命令",
"gui.commandbuttons.name_label": "名称:",
"gui.commandbuttons.commands_label": "命令(每行一条,不要斜杠):",
"gui.commandbuttons.create": "创建",
"gui.commandbuttons.save": "保存",
"gui.commandbuttons.delete": "删除",
"gui.commandbuttons.cancel": "取消",
"gui.commandbuttons.commands_suggestion_name": "命令按钮名称",
"gui.commandbuttons.commands_suggestion_command": "命令"
}

View File

@ -1,17 +1,18 @@
{ {
"schemaVersion": 1, "schemaVersion": 1,
"id": "command-gui-buttons", "id": "command-gui-buttons-revive",
"version": "${version}", "version": "${version}",
"name": "Command GUI Buttons", "name": "Command GUI Buttons",
"description": "Create GUI buttons in-game to execute commands.", "description": "Create GUI buttons in-game to execute commands.",
"authors": [ "authors": [
"JosephG", "JosephG",
"Abbanon" "Abbanon",
"BRanulf(This version ONLY)"
], ],
"contact": { "contact": {
"homepage": "https://www.curseforge.com/minecraft/mc-mods/command-gui-buttons", "homepage": "https://git.branulf.top/Branulf/command-gui-buttons-revive",
"sources": "https://github.com/joseph-garcia/command-gui-buttons" "sources": "https://git.branulf.top/Branulf/command-gui-buttons-revive"
}, },
"license": "gpl-3.0", "license": "gpl-3.0",
@ -27,9 +28,9 @@
], ],
"depends": { "depends": {
"fabricloader": ">=0.7.4", "fabricloader": ">=0.16.10",
"fabric": "*", "fabric": "*",
"minecraft": "1.16.x", "minecraft": "1.21.4",
"fabric-key-binding-api-v1": "*" "fabric-key-binding-api-v1": "*"
}, },
"suggests": { "suggests": {