initial commit
This commit is contained in:
commit
67bca8c9e0
40
.github/workflows/build.yml
vendored
Executable file
40
.github/workflows/build.yml
vendored
Executable file
@ -0,0 +1,40 @@
|
||||
# Automatically build the project and run any configured tests for every push
|
||||
# and submitted pull request. This can help catch issues that only occur on
|
||||
# certain platforms or Java versions, and provides a first line of defence
|
||||
# against bad commits.
|
||||
|
||||
name: build
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
# Use these Java versions
|
||||
java: [
|
||||
17, # Current Java LTS & minimum supported by Minecraft
|
||||
]
|
||||
# and run on both Linux and Windows
|
||||
os: [ubuntu-22.04, windows-2022]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: validate gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
- name: setup jdk ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: ${{ matrix.java }}
|
||||
distribution: 'microsoft'
|
||||
- name: make gradle wrapper executable
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: chmod +x ./gradlew
|
||||
- name: build
|
||||
run: ./gradlew build
|
||||
- name: capture build artifacts
|
||||
if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Artifacts
|
||||
path: build/libs/
|
21
.gitignore
vendored
Executable file
21
.gitignore
vendored
Executable file
@ -0,0 +1,21 @@
|
||||
*
|
||||
|
||||
!/src
|
||||
!/src/**/*
|
||||
|
||||
!/doc
|
||||
!/doc/**/*
|
||||
|
||||
!/.github
|
||||
!/.github/**/*
|
||||
|
||||
!/.gitignore
|
||||
!/.gitattributes
|
||||
!/LICENSE
|
||||
!/README.md
|
||||
!/settings.gradle
|
||||
!/build.gradle
|
||||
!/gradle.properties
|
||||
!/gradle
|
||||
!/gradle/wrapper
|
||||
!/gradle/wrapper/gradle-wrapper.properties
|
46
build.gradle
Executable file
46
build.gradle
Executable file
@ -0,0 +1,46 @@
|
||||
plugins {
|
||||
id 'fabric-loom' version '1.0-SNAPSHOT'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://jitpack.io' }
|
||||
maven { url 'https://maven.terraformersmc.com/releases' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
|
||||
implementation 'com.github.topchetoeu:jscript:v0.8.7-beta'
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}"
|
||||
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(17)
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs = [ "src/java" ]
|
||||
main.resources.srcDirs = [ "src/assets" ]
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand (
|
||||
version: project.project_version,
|
||||
name: project.project_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
base.archivesName = project.project_name
|
||||
version = project.project_version
|
||||
group = project.project_group
|
19
gradle.properties
Executable file
19
gradle.properties
Executable file
@ -0,0 +1,19 @@
|
||||
# Done to increase the memory available to gradle.
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
org.gradle.parallel=true
|
||||
|
||||
# Dependencies
|
||||
|
||||
minecraft_version=1.19.4
|
||||
yarn_mappings=1.19.4+build.2
|
||||
loader_version=0.15.3
|
||||
fabric_version=0.87.2+1.19.4
|
||||
modmenu_version=6.3.1
|
||||
|
||||
# Project properties
|
||||
|
||||
project_version=0.0.1-alpha
|
||||
project_name = mcscript
|
||||
project_group me.topchetoeu
|
||||
|
||||
# Dependencies
|
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
12
settings.gradle
Executable file
12
settings.gradle
Executable file
@ -0,0 +1,12 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = properties.project_name
|
24
src/assets/fabric.mod.json
Executable file
24
src/assets/fabric.mod.json
Executable file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "${name}",
|
||||
"version": "${version}",
|
||||
"name": "MC-Jscript",
|
||||
"description": "A simple mod loader for Javascript mods.",
|
||||
"authors": [ "TopcehtoEU" ],
|
||||
"license": "MIT",
|
||||
"icon": "${name}/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"client": [ "me.topchetoeu.mcscript.McScript" ],
|
||||
"main": [ "me.topchetoeu.mcscript.McScript" ]
|
||||
},
|
||||
"mixins": [ "mcscript.mixins.json" ],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.14.11",
|
||||
"fabric-api": "*",
|
||||
"minecraft": "~1.19.3",
|
||||
"modmenu": "~1.19.3",
|
||||
"java": ">=17"
|
||||
},
|
||||
"suggests": { }
|
||||
}
|
15
src/assets/mcscript.mixins.json
Executable file
15
src/assets/mcscript.mixins.json
Executable file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "me.topchetoeu.mcscript.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [],
|
||||
"client": [
|
||||
"ChatScreenMixin",
|
||||
"MinecraftClientMixin",
|
||||
"KeyboardMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
BIN
src/assets/mcscript/icon.png
Executable file
BIN
src/assets/mcscript/icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 449 B |
24
src/java/me/topchetoeu/mcscript/ClientCommandMessageReceiver.java
Executable file
24
src/java/me/topchetoeu/mcscript/ClientCommandMessageReceiver.java
Executable file
@ -0,0 +1,24 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ClientCommandMessageReceiver implements MessageReceiver {
|
||||
public final FabricClientCommandSource receiver;
|
||||
|
||||
@Override
|
||||
public void sendError(String msg) {
|
||||
receiver.sendError(Text.of(msg));
|
||||
}
|
||||
@Override
|
||||
public void sendInfo(String msg) {
|
||||
receiver.sendFeedback(Text.of(msg));
|
||||
}
|
||||
|
||||
public ClientCommandMessageReceiver(FabricClientCommandSource receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
}
|
21
src/java/me/topchetoeu/mcscript/ClientMessageReceiver.java
Executable file
21
src/java/me/topchetoeu/mcscript/ClientMessageReceiver.java
Executable file
@ -0,0 +1,21 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class ClientMessageReceiver implements MessageReceiver {
|
||||
public final MinecraftClient client = MinecraftClient.getInstance();
|
||||
|
||||
@Override
|
||||
public void sendError(String msg) {
|
||||
client.player.sendMessage(Text.literal("").append(msg).formatted(Formatting.RED));
|
||||
}
|
||||
@Override
|
||||
public void sendInfo(String msg) {
|
||||
client.player.sendMessage(Text.of(msg));
|
||||
}
|
||||
}
|
12
src/java/me/topchetoeu/mcscript/EnvironmentFactory.java
Normal file
12
src/java/me/topchetoeu/mcscript/EnvironmentFactory.java
Normal file
@ -0,0 +1,12 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.jscript.core.engine.Context;
|
||||
|
||||
public interface EnvironmentFactory {
|
||||
Iterable<String> dependancies();
|
||||
|
||||
String name();
|
||||
void apply(Context ctx, Map<String, EnvironmentFactory> dependancies);
|
||||
}
|
141
src/java/me/topchetoeu/mcscript/McScript.java
Executable file
141
src/java/me/topchetoeu/mcscript/McScript.java
Executable file
@ -0,0 +1,141 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
|
||||
import static com.mojang.brigadier.arguments.StringArgumentType.greedyString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.core.engine.Context;
|
||||
import me.topchetoeu.jscript.core.engine.Engine;
|
||||
import me.topchetoeu.jscript.core.engine.Environment;
|
||||
import me.topchetoeu.jscript.core.engine.values.Values;
|
||||
import me.topchetoeu.jscript.lib.Internals;
|
||||
import me.topchetoeu.jscript.utils.filesystem.File;
|
||||
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
|
||||
import me.topchetoeu.jscript.utils.filesystem.LineReader;
|
||||
import me.topchetoeu.jscript.utils.filesystem.LineWriter;
|
||||
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
|
||||
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
|
||||
import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
|
||||
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
|
||||
import me.topchetoeu.mcscript.events.ChatMessageCallback;
|
||||
import me.topchetoeu.mcscript.gui.DevScreen;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager;
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class McScript implements ModInitializer, ClientModInitializer {
|
||||
private boolean openDev = false;
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("jscript");
|
||||
|
||||
private void execute(int i, Environment env, Engine engine, String raw, MessageReceiver msg) {
|
||||
try {
|
||||
var res = engine.pushMsg(false, env, new Filename("repl", i + ".js"), raw, null).await();
|
||||
msg.sendInfo(Values.toReadable(new Context(engine, env), res));
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
msg.sendError(Values.errorToReadable(e, ""));
|
||||
}
|
||||
}
|
||||
|
||||
private Environment createEnv(String location, LineReader in, LineWriter out) {
|
||||
var env = new Environment();
|
||||
var inFile = File.ofLineReader(in);
|
||||
var outFile = File.ofLineWriter(out);
|
||||
Internals.apply(env);
|
||||
|
||||
var fs = new RootFilesystem(PermissionsProvider.get(env));
|
||||
fs.protocols.put("std", new STDFilesystem().add("in", inFile).add("out", outFile));
|
||||
|
||||
var perms = new PermissionsManager();
|
||||
|
||||
env.add(PermissionsProvider.ENV_KEY, perms);
|
||||
env.add(Filesystem.ENV_KEY, fs);
|
||||
|
||||
env.global.define(null, "env", true, location);
|
||||
return env;
|
||||
}
|
||||
|
||||
@Override public void onInitialize() {
|
||||
var engine = new Engine();
|
||||
|
||||
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
|
||||
engine.start();
|
||||
|
||||
var env = createEnv("SERVER", () -> null, value -> {
|
||||
for (var line : value.split("\n", -1)) LOGGER.info(line);
|
||||
});
|
||||
|
||||
var i = new int[1];
|
||||
|
||||
server.getCommandManager().getDispatcher().register(CommandManager.literal("msc")
|
||||
.then(CommandManager.argument("code", greedyString()).executes(c -> {
|
||||
String str = getString(c, "code");
|
||||
var receiver = new ServerCommandMessageReceiver(c.getSource());
|
||||
execute(i[0]++, env, engine, str, receiver);
|
||||
return 1;
|
||||
}))
|
||||
);
|
||||
});
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(server -> {
|
||||
engine.stop();
|
||||
});
|
||||
}
|
||||
|
||||
@net.fabricmc.api.Environment(EnvType.CLIENT)
|
||||
@Override public void onInitializeClient() {
|
||||
var dev = new DevScreen();
|
||||
var engine = new Engine();
|
||||
|
||||
ClientLifecycleEvents.CLIENT_STARTED.register((client) -> {
|
||||
try {
|
||||
Files.createDirectories(Path.of("scripts"));
|
||||
}
|
||||
catch (IOException e) { /* so be it */ }
|
||||
|
||||
var receiver = new ClientMessageReceiver();
|
||||
var env = createEnv("CLIENT", () -> null, value -> MinecraftClient.getInstance().player.sendMessage(Text.of(value)));
|
||||
engine.start();
|
||||
|
||||
var i = new int[1];
|
||||
ChatMessageCallback.EVENT.register(args -> {
|
||||
if (args.message.startsWith("#")) {
|
||||
execute(i[0]++, env, engine, args.message.substring(1), receiver);
|
||||
args.cancelled = true;
|
||||
}
|
||||
});
|
||||
ClientTickEvents.END_CLIENT_TICK.register((_1) -> {
|
||||
if (openDev) {
|
||||
client.setScreenAndRender(dev);
|
||||
openDev = false;
|
||||
}
|
||||
});
|
||||
ClientCommandRegistrationCallback.EVENT.register((disp, _1) -> {
|
||||
disp.register(ClientCommandManager.literal("dev")
|
||||
.executes(c -> {
|
||||
openDev = true;
|
||||
return 1;
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
ClientLifecycleEvents.CLIENT_STOPPING.register((client) -> {
|
||||
engine.stop();
|
||||
});
|
||||
}
|
||||
}
|
6
src/java/me/topchetoeu/mcscript/MessageReceiver.java
Executable file
6
src/java/me/topchetoeu/mcscript/MessageReceiver.java
Executable file
@ -0,0 +1,6 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
public interface MessageReceiver {
|
||||
public void sendError(String msg);
|
||||
public void sendInfo(String msg);
|
||||
}
|
21
src/java/me/topchetoeu/mcscript/ServerCommandMessageReceiver.java
Executable file
21
src/java/me/topchetoeu/mcscript/ServerCommandMessageReceiver.java
Executable file
@ -0,0 +1,21 @@
|
||||
package me.topchetoeu.mcscript;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class ServerCommandMessageReceiver implements MessageReceiver {
|
||||
public final ServerCommandSource receiver;
|
||||
|
||||
@Override
|
||||
public void sendInfo(String msg) {
|
||||
receiver.sendFeedback(Text.of(msg), false);
|
||||
}
|
||||
@Override
|
||||
public void sendError(String msg) {
|
||||
receiver.sendError(Text.of(msg));
|
||||
}
|
||||
|
||||
public ServerCommandMessageReceiver(ServerCommandSource receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
}
|
17
src/java/me/topchetoeu/mcscript/events/ChatMessageCallback.java
Executable file
17
src/java/me/topchetoeu/mcscript/events/ChatMessageCallback.java
Executable file
@ -0,0 +1,17 @@
|
||||
package me.topchetoeu.mcscript.events;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
public interface ChatMessageCallback {
|
||||
public static class ChatArgs {
|
||||
public String message;
|
||||
public boolean cancelled;
|
||||
}
|
||||
|
||||
void execute(ChatArgs args);
|
||||
|
||||
public static final Event<ChatMessageCallback> EVENT = EventFactory.createArrayBacked(ChatMessageCallback.class, arr -> args -> {
|
||||
for (var el : arr) el.execute(args);
|
||||
});
|
||||
}
|
40
src/java/me/topchetoeu/mcscript/gui/ButtonWidget.java
Executable file
40
src/java/me/topchetoeu/mcscript/gui/ButtonWidget.java
Executable file
@ -0,0 +1,40 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class ButtonWidget extends Widget {
|
||||
public interface ClickHandler {
|
||||
void click();
|
||||
}
|
||||
|
||||
public final ClickHandler handler;
|
||||
public final String text;
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
if (isMouseOver(mx, my)) fill(mat, x, y, x + w, y + h, theme.get("bg-2"));
|
||||
else fill(mat, x, y, x + w, y + h, theme.get("bg-1"));
|
||||
|
||||
theme.font.draw(mat, text, x + (w - theme.font.getWidth(text)) / 2, y + (h - theme.fontSize()) / 2, theme.get("text"));
|
||||
|
||||
super.render(mat, mx, my, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mx, double my, int button) {
|
||||
if (isMouseOver(mx, my) && button == 0) {
|
||||
handler.click();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return true; }
|
||||
|
||||
public ButtonWidget(Theme theme, String text, ClickHandler handler) {
|
||||
super(theme);
|
||||
this.handler = handler;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
82
src/java/me/topchetoeu/mcscript/gui/DevEditorWidget.java
Executable file
82
src/java/me/topchetoeu/mcscript/gui/DevEditorWidget.java
Executable file
@ -0,0 +1,82 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class DevEditorWidget extends Widget {
|
||||
private DevTextBoxWidget tab;
|
||||
|
||||
private void updateTab() {
|
||||
if (tab == null) return;
|
||||
tab.setMultiline(true).setRect(x, y + theme.fontSize() + theme.get("padding-s"), w, h - theme.fontSize() - theme.get("padding-s"));
|
||||
tab.theme.setTheme(theme);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return false; }
|
||||
@Override
|
||||
public Widget setRect(int x, int y, int w, int h) {
|
||||
super.setRect(x, y, w, h);
|
||||
updateTab();
|
||||
return this;
|
||||
}
|
||||
|
||||
public DevTextBoxWidget get() {
|
||||
return tab;
|
||||
}
|
||||
public void set(DevTextBoxWidget tab) {
|
||||
if (this.tab == tab) return;
|
||||
this.tab = tab;
|
||||
updateTab();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
if (tab == null) return false;
|
||||
return tab.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
@Override
|
||||
public boolean charTyped(char chr, int modifiers) {
|
||||
if (tab == null) return false;
|
||||
return tab.charTyped(chr, modifiers);
|
||||
}
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (tab == null) return false;
|
||||
return tab.mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
|
||||
if (tab == null) return false;
|
||||
return tab.mouseScrolled(mouseX, mouseY, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendNarrations(NarrationMessageBuilder nmb) {
|
||||
}
|
||||
@Override
|
||||
public SelectionType getType() {
|
||||
return SelectionType.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
if (tab == null) {
|
||||
String text = "No file opened :(";
|
||||
int cx = w - theme.font.getWidth(text);
|
||||
int cy = h - theme.fontSize();
|
||||
|
||||
fill(mat, x, y, x + w, y + h, theme.get("bg-1"));
|
||||
theme.font.draw(mat, text, x + cx / 2, x + cy / 2, theme.get("text"));
|
||||
}
|
||||
else {
|
||||
tab.render(mat, mx, my, delta);
|
||||
fill(mat, x, y, x + w, y + theme.fontSize() + 2, theme.get("bg-2"));
|
||||
theme.font.draw(mat, tab.getFile().getAbsoluteFile().toString(), x + 5, y + 2, theme.get("text"));
|
||||
}
|
||||
}
|
||||
|
||||
public DevEditorWidget(Theme theme) {
|
||||
super(theme);
|
||||
}
|
||||
}
|
165
src/java/me/topchetoeu/mcscript/gui/DevScreen.java
Executable file
165
src/java/me/topchetoeu/mcscript/gui/DevScreen.java
Executable file
@ -0,0 +1,165 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import me.topchetoeu.mcscript.gui.OpenFileScreen.OpenHandler;
|
||||
import me.topchetoeu.mcscript.gui.SaveFileScreen.SaveHandler;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class DevScreen extends Screen implements OpenHandler, SaveHandler {
|
||||
private enum Focus {
|
||||
EDITOR,
|
||||
MENU,
|
||||
}
|
||||
|
||||
private Theme theme;
|
||||
private DevEditorWidget editor;
|
||||
private DevTabListWidget tabs;
|
||||
|
||||
private Focus focus = Focus.EDITOR;
|
||||
private int untitledI = 1;
|
||||
|
||||
// private int altI = 0;
|
||||
|
||||
// private void drawFileMenu(MatrixStack matrices) {
|
||||
// int h = theme.fontSize() + 2;
|
||||
|
||||
// int x = 1;
|
||||
// int y = height - 15;
|
||||
// int i = 0;
|
||||
|
||||
// fill(matrices, 0, this.height - h, this.width, this.height, Argb.getArgb(255, 40, 40, 40));
|
||||
|
||||
// for (var el : ListExt.of("Save", "Open", "Close", "Quit")) {
|
||||
// int w = font.getWidth(el) + 10;
|
||||
|
||||
// if (focus == Focus.MENU && altI == i++) {
|
||||
// fill(matrices, x, y, x + w, y + h, Argb.getArgb(255, 80, 80, 80));
|
||||
// }
|
||||
// font.draw(matrices, el, x + 5, y + 1, Argb.getArgb(255, 255, 255, 255));
|
||||
// x += w;
|
||||
// }
|
||||
// }
|
||||
|
||||
public void fileOpened(File file) {
|
||||
try {
|
||||
tabs.add(new DevTextBoxWidget(file, theme));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void fileSaved(File file) {
|
||||
var tab = tabs.getTab();
|
||||
if (tab != null) {
|
||||
try {
|
||||
tab.saveFileAs(file);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getUntitled() {
|
||||
while (true) {
|
||||
int i = untitledI++;
|
||||
if (!new File("untitled" + i + ".ms").exists()) return i;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
try {
|
||||
boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0;
|
||||
boolean alt = (modifiers & GLFW.GLFW_MOD_ALT) != 0;
|
||||
boolean shift = (modifiers & GLFW.GLFW_MOD_SHIFT) != 0;
|
||||
if (ctrl) {
|
||||
if (keyCode == GLFW.GLFW_KEY_N) {
|
||||
tabs.add(new DevTextBoxWidget(new File("untitled" + getUntitled() + ".ms"), theme));
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_W) {
|
||||
tabs.close();
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_S) {
|
||||
if (!alt) tabs.getTab().saveFile();
|
||||
else client.setScreen(new SaveFileScreen(this, theme, new File(""), Text.of("Save file:"), this));
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_O) {
|
||||
client.setScreen(new OpenFileScreen(this, theme, new File(""), Text.of("Open file:"), this));
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_TAB) {
|
||||
if (shift) tabs.prev();
|
||||
else tabs.next();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||
client.setScreen(null);
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_LEFT_ALT) {
|
||||
if (focus == Focus.MENU) focus = Focus.EDITOR;
|
||||
else focus = Focus.MENU;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return this.getFocused() != null && this.getFocused().keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
protected void init() {
|
||||
if (theme == null) {
|
||||
theme = Theme.dark(MinecraftClient.getInstance().textRenderer);
|
||||
editor = new DevEditorWidget(theme);
|
||||
tabs = new DevTabListWidget(theme, tab -> editor.set(tab));
|
||||
}
|
||||
|
||||
addDrawableChild(editor);
|
||||
addDrawableChild(tabs);
|
||||
setFocused(editor);
|
||||
|
||||
editor.setRect(0, 0, width - 100, height);
|
||||
tabs.setRect(width - 100, 0, 100, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
var res = super.mouseClicked(mouseX, mouseY, button);
|
||||
return res;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean changeFocus(boolean lookForwards) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
public DevScreen() {
|
||||
super(Text.of("McScript IDE"));
|
||||
|
||||
// try {
|
||||
// this.tabs.add(new DevTab(new File("test1.ms"), font));
|
||||
// this.tabs.add(new DevTab(new File("test1.ms"), font));
|
||||
// this.tabs.add(new DevTab(new File("test3.ms"), font));
|
||||
// }
|
||||
// catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// this.tabs.add(new DevTab(0, "", "test2.ms"));
|
||||
// this.tabs.add(new DevTab(0, "", "test3.ms"));
|
||||
}
|
||||
}
|
121
src/java/me/topchetoeu/mcscript/gui/DevTabListWidget.java
Executable file
121
src/java/me/topchetoeu/mcscript/gui/DevTabListWidget.java
Executable file
@ -0,0 +1,121 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class DevTabListWidget extends Widget {
|
||||
public static interface TabChangeHandle {
|
||||
void tabChanged(DevTextBoxWidget tab);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return false; }
|
||||
|
||||
public final TabChangeHandle changeHandle;
|
||||
|
||||
private int tabI = -1;
|
||||
private ArrayList<DevTextBoxWidget> tabs = new ArrayList<>();
|
||||
|
||||
|
||||
public DevTextBoxWidget getTab() {
|
||||
if (tabs.size() == 0) return null;
|
||||
return tabs.get(tabI);
|
||||
}
|
||||
public void setTab(DevTextBoxWidget tab) {
|
||||
if (tabs.contains(tab)) tabs.add(tab);
|
||||
tabI = tabs.indexOf(tab);
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
|
||||
public void next() {
|
||||
if (tabs.size() < 2) return;
|
||||
tabI++;
|
||||
if (tabI >= tabs.size()) tabI = 0;
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
public void prev() {
|
||||
if (tabs.size() < 2) return;
|
||||
tabI--;
|
||||
if (tabI < 0) tabI = tabs.size() - 1;
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
public void add(DevTextBoxWidget tab) {
|
||||
tabs.add(++tabI, tab);
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
public void close() {
|
||||
if (tabs.size() == 0) return;
|
||||
tabs.remove(tabI);
|
||||
if (tabI == tabs.size()) {
|
||||
tabI--;
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mx, double my, int button) {
|
||||
if (!isMouseOver(mx, my)) return false;
|
||||
mx -= x; my -= y;
|
||||
|
||||
int i = (int)((my - theme.get("padding-l")) / (theme.fontSize() + 4));
|
||||
if (i >= 0 && i < tabs.size()) {
|
||||
if (button == 2) {
|
||||
tabs.remove(tabI);
|
||||
if (tabI == tabs.size()) {
|
||||
tabI--;
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabI = i;
|
||||
changeHandle.tabChanged(getTab());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
int h = theme.fontSize() + 4;
|
||||
|
||||
mat.push();
|
||||
mat.translate(x, y, 0);
|
||||
|
||||
fill(mat, 0, 0, w, theme.get("padding-l"), theme.get("bg-3"));
|
||||
|
||||
mat.push();
|
||||
mat.translate(0, theme.get("padding-l"), 0);
|
||||
|
||||
for (int i = 0; i < tabs.size(); i++) {
|
||||
int col = theme.get("bg-3");
|
||||
if (tabI == i) col = theme.get("bg-4");
|
||||
fill(mat, 0, i * h, w, (i + 1) * h, col);
|
||||
|
||||
var name = tabs.get(i).getFile().getName();
|
||||
if (!tabs.get(i).fileIsSaved()) name = "*" + name;
|
||||
theme.font.draw(mat, name, 5, i * h + 2, theme.get("text"));
|
||||
}
|
||||
|
||||
mat.pop();
|
||||
|
||||
fill(mat, 0, tabs.size() * h + theme.get("padding-l"), w, this.h, theme.get("bg-3"));
|
||||
|
||||
mat.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendNarrations(NarrationMessageBuilder var1) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public SelectionType getType() {
|
||||
return SelectionType.NONE;
|
||||
}
|
||||
|
||||
public DevTabListWidget(Theme theme, TabChangeHandle changeHandle) {
|
||||
super(theme);
|
||||
this.changeHandle = changeHandle;
|
||||
}
|
||||
}
|
95
src/java/me/topchetoeu/mcscript/gui/DevTextBoxWidget.java
Executable file
95
src/java/me/topchetoeu/mcscript/gui/DevTextBoxWidget.java
Executable file
@ -0,0 +1,95 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.nio.file.Files;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class DevTextBoxWidget extends TextBoxWidget {
|
||||
private File file;
|
||||
private FileTracker tracker;
|
||||
|
||||
private boolean saved;
|
||||
private String conflict = null;
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean fileExists() {
|
||||
return tracker.exists();
|
||||
}
|
||||
public boolean fileIsSaved() {
|
||||
return saved;
|
||||
}
|
||||
public boolean fileHasConflict() {
|
||||
return conflict != null;
|
||||
}
|
||||
public String getFileConflictReason() {
|
||||
return conflict;
|
||||
}
|
||||
public void saveFile() throws IOException {
|
||||
Files.writeString(file.toPath(), getValue());
|
||||
tracker.wasChanged();
|
||||
saved = true;
|
||||
conflict = null;
|
||||
}
|
||||
public void saveFileAs(File file) throws IOException {
|
||||
file.getParentFile().mkdirs();
|
||||
Files.writeString(file.toPath(), getValue());
|
||||
tracker.wasChanged();
|
||||
this.file = file;
|
||||
this.tracker = new FileTracker(file);
|
||||
saved = true;
|
||||
conflict = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return false; }
|
||||
@Override
|
||||
protected void textChanged() {
|
||||
saved = false;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (tracker.wasCreated()) {
|
||||
conflict = "File was created";
|
||||
saved = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (tracker.wasChanged()) {
|
||||
if (saved) this.setValue(Files.readString(file.toPath()));
|
||||
else conflict = "File was changed";
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (tracker.wasDeleted()) {
|
||||
saved = false;
|
||||
conflict = null;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void render(MatrixStack mat, int x, int y, float delta) {
|
||||
update();
|
||||
super.render(mat, x, y, delta);
|
||||
}
|
||||
|
||||
public DevTextBoxWidget(File file, Theme theme) throws IOException {
|
||||
super(theme);
|
||||
this.file = file;
|
||||
this.tracker = new FileTracker(file);
|
||||
if (tracker.exists()) {
|
||||
saved = true;
|
||||
this.setMultiline(true);
|
||||
this.setValue(Files.readString(file.toPath()));
|
||||
}
|
||||
else saved = false;
|
||||
}
|
||||
}
|
94
src/java/me/topchetoeu/mcscript/gui/FileDialogScreen.java
Executable file
94
src/java/me/topchetoeu/mcscript/gui/FileDialogScreen.java
Executable file
@ -0,0 +1,94 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public abstract class FileDialogScreen extends Screen {
|
||||
public final Screen parent;
|
||||
public final Theme theme;
|
||||
protected final FileListWidget list;
|
||||
protected final ButtonWidget ok;
|
||||
protected final ButtonWidget cancel;
|
||||
protected final TextBoxWidget name;
|
||||
|
||||
protected abstract String okButtonText();
|
||||
protected abstract void okPressed(File file);
|
||||
protected abstract void selected(File file);
|
||||
|
||||
private void submit() {
|
||||
okPressed(new File(list.cd(), name.getValue()).toPath().toAbsolutePath().toFile());
|
||||
}
|
||||
|
||||
private int headerHeight() {
|
||||
return theme.get("padding-m") * 2 + theme.fontSize();
|
||||
}
|
||||
private int footerHeight() {
|
||||
return (theme.get("padding-m") + theme.get("padding-s")) * 2 + theme.fontSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
int padl = theme.get("padding-l");
|
||||
int padm = theme.get("padding-m");
|
||||
int pads = theme.get("padding-s");
|
||||
|
||||
int btnw = 50;
|
||||
int btnh = pads * 2 + theme.fontSize();
|
||||
int btny = height - padm - btnh;
|
||||
int inputw = width - 100 - padl * 4;
|
||||
|
||||
list.setRect(padl, headerHeight(), width - padl * 2, height - headerHeight() - footerHeight());
|
||||
ok.setRect(padl, btny, btnw, btnh);
|
||||
cancel.setRect(padl + 50 + padl, btny, btnw, btnh);
|
||||
name.setPos(padl + 100 + padl * 2, btny).setWidth(inputw);
|
||||
addDrawableChild(list);
|
||||
addDrawableChild(ok);
|
||||
addDrawableChild(cancel);
|
||||
addDrawableChild(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
fill(mat, 0, 0, width, height, theme.get("bg-1"));
|
||||
list.render(mat, mx, my, delta);
|
||||
fill(mat, list.x, 0, list.w + list.x, list.y - 1, theme.get("bg-1"));
|
||||
fill(mat, list.x, list.y + list.h + 1, list.w + list.x, height, theme.get("bg-1"));
|
||||
theme.font.draw(mat, title, theme.get("padding-l"), theme.get("padding-m"), theme.get("text"));
|
||||
ok.render(mat, mx, my, delta);
|
||||
cancel.render(mat, mx, my, delta);
|
||||
name.render(mat, mx, my, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
client.setScreen(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER) {
|
||||
submit();
|
||||
return true;
|
||||
}
|
||||
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
protected FileDialogScreen(Screen parent, Theme theme, File root, Text title) {
|
||||
super(title);
|
||||
this.parent = parent;
|
||||
this.theme = theme;
|
||||
list = new FileListWidget(theme, root, this::selected);
|
||||
name = new TextBoxWidget(theme);
|
||||
ok = new ButtonWidget(theme, okButtonText(), this::submit);
|
||||
cancel = new ButtonWidget(theme, "Cancel", this::close);
|
||||
}
|
||||
}
|
146
src/java/me/topchetoeu/mcscript/gui/FileListWidget.java
Executable file
146
src/java/me/topchetoeu/mcscript/gui/FileListWidget.java
Executable file
@ -0,0 +1,146 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public class FileListWidget extends Widget {
|
||||
public interface SelectHandler {
|
||||
void selected(File f);
|
||||
}
|
||||
|
||||
public final SelectHandler handler;
|
||||
|
||||
private File res = null;
|
||||
private File currFile;
|
||||
private List<String> entries = new ArrayList<>();
|
||||
|
||||
private float scroll = 0;
|
||||
|
||||
|
||||
private void setEntries() {
|
||||
if (currFile == null) {
|
||||
entries.clear();
|
||||
for (var root : File.listRoots()) {
|
||||
entries.add(root.toString());
|
||||
}
|
||||
}
|
||||
else if (currFile.isFile() || currFile.listFiles() == null) {
|
||||
res = currFile;
|
||||
handler.selected(currFile);
|
||||
currFile = currFile.getParentFile();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
this.entries.clear();
|
||||
this.entries.add("(drives)");
|
||||
this.entries.add("..");
|
||||
for (var el : currFile.listFiles()) {
|
||||
if (el.isDirectory()) this.entries.add(el.getName() + "/");
|
||||
}
|
||||
for (var el : currFile.listFiles()) {
|
||||
if (el.isFile()) this.entries.add(el.getName());
|
||||
}
|
||||
}
|
||||
|
||||
updateScroll();
|
||||
}
|
||||
private void updateScroll() {
|
||||
float _h = entries.size() * (theme.fontSize() + 4) - h;
|
||||
if (scroll > _h) scroll = _h;
|
||||
if (scroll < 0) scroll = 0;
|
||||
}
|
||||
private int entryHeight() {
|
||||
return theme.fontSize() + 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return true; }
|
||||
|
||||
public File result() {
|
||||
return res.toPath().toAbsolutePath().toFile();
|
||||
}
|
||||
public File cd() {
|
||||
return currFile.toPath().toAbsolutePath().toFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
renderSetup();
|
||||
|
||||
mat.push();
|
||||
mat.translate(x, y, 0);
|
||||
mx -= x; my -= y;
|
||||
|
||||
fill(mat, 0, 0, w, h, theme.get("bg-1"));
|
||||
|
||||
mat.push();
|
||||
mat.translate(0, -scroll, 0);
|
||||
my += scroll;
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
int x1 = 0, y1 = i * entryHeight(), x2 = w, y2 = (i + 1) * entryHeight();
|
||||
if (mx >= x1 && mx < x2 && my >= y1 && my < y2) {
|
||||
fill(mat, x1, y1, x2, y2, theme.get("bg-3"));
|
||||
}
|
||||
else if (i % 2 == 0) {
|
||||
fill(mat, x1, y1, x2, y2, theme.get("bg-2"));
|
||||
}
|
||||
theme.font.draw(mat, entries.get(i), theme.get("padding-l"), y1 + 3, theme.get("text"));
|
||||
}
|
||||
|
||||
mat.pop();
|
||||
mat.pop();
|
||||
|
||||
renderFinalize();
|
||||
|
||||
super.render(mat, mx, my, delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mx, double my, int button) {
|
||||
if (button != 0 || !isMouseOver(mx, my)) return false;
|
||||
|
||||
mx -= x; my -= y - scroll;
|
||||
|
||||
int i = (int)(my / entryHeight());
|
||||
|
||||
if (i < 0 || i >= entries.size()) return false;
|
||||
|
||||
if (currFile == null) {
|
||||
currFile = new File(entries.get(i));
|
||||
}
|
||||
else {
|
||||
if (i == 0) currFile = null;
|
||||
else if (i == 1) currFile = currFile.getParentFile();
|
||||
else currFile = new File(currFile, entries.get(i));
|
||||
}
|
||||
|
||||
setEntries();
|
||||
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean mouseScrolled(double mx, double my, double amount) {
|
||||
if (isMouseOver(mx, my)) {
|
||||
scroll -= amount * 10;
|
||||
updateScroll();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public FileListWidget(Theme theme, File root, SelectHandler handler) {
|
||||
super(theme);
|
||||
this.handler = handler;
|
||||
this.currFile = root.toPath().toAbsolutePath().toFile();
|
||||
if (this.currFile.isFile()) throw new RuntimeException("wtf");
|
||||
setEntries();
|
||||
}
|
||||
}
|
65
src/java/me/topchetoeu/mcscript/gui/FileTracker.java
Executable file
65
src/java/me/topchetoeu/mcscript/gui/FileTracker.java
Executable file
@ -0,0 +1,65 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class FileTracker {
|
||||
public final File file;
|
||||
|
||||
private long lastChange = 0;
|
||||
private boolean exists = false;
|
||||
private boolean created = false;
|
||||
private boolean deleted = false;
|
||||
private boolean changed = false;
|
||||
|
||||
public void update() {
|
||||
if (file.exists()) {
|
||||
if (!exists) created = changed = true;
|
||||
exists = true;
|
||||
|
||||
if (lastChange < file.lastModified()) {
|
||||
changed = true;
|
||||
lastChange = file.lastModified();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (exists) changed = deleted = true;
|
||||
exists = created = false;
|
||||
lastChange = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
update();
|
||||
return exists;
|
||||
}
|
||||
public boolean wasChanged() {
|
||||
update();
|
||||
if (changed) {
|
||||
changed = false;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
public boolean wasCreated() {
|
||||
update();
|
||||
if (created) {
|
||||
created = false;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
public boolean wasDeleted() {
|
||||
update();
|
||||
if (deleted) {
|
||||
deleted = false;
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
public FileTracker(File file) {
|
||||
this.file = file;
|
||||
if (exists = file.exists()) lastChange = file.lastModified();
|
||||
else lastChange = 0;
|
||||
}
|
||||
}
|
33
src/java/me/topchetoeu/mcscript/gui/OpenFileScreen.java
Executable file
33
src/java/me/topchetoeu/mcscript/gui/OpenFileScreen.java
Executable file
@ -0,0 +1,33 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class OpenFileScreen extends FileDialogScreen {
|
||||
public interface OpenHandler {
|
||||
void fileOpened(File file);
|
||||
}
|
||||
|
||||
public final OpenHandler handler;
|
||||
|
||||
@Override
|
||||
protected String okButtonText() { return "Open"; }
|
||||
|
||||
@Override
|
||||
protected void okPressed(File file) {
|
||||
handler.fileOpened(file);
|
||||
close();
|
||||
}
|
||||
@Override
|
||||
protected void selected(File file) {
|
||||
handler.fileOpened(file);
|
||||
close();
|
||||
}
|
||||
|
||||
protected OpenFileScreen(Screen parent, Theme theme, File root, Text title, OpenHandler handler) {
|
||||
super(parent, theme, root, title);
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
33
src/java/me/topchetoeu/mcscript/gui/SaveFileScreen.java
Executable file
33
src/java/me/topchetoeu/mcscript/gui/SaveFileScreen.java
Executable file
@ -0,0 +1,33 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
public class SaveFileScreen extends FileDialogScreen {
|
||||
public interface SaveHandler {
|
||||
void fileSaved(File file);
|
||||
}
|
||||
|
||||
public final SaveHandler handler;
|
||||
|
||||
@Override
|
||||
protected String okButtonText() { return "Save"; }
|
||||
|
||||
@Override
|
||||
protected void okPressed(File file) {
|
||||
handler.fileSaved(file);
|
||||
close();
|
||||
}
|
||||
@Override
|
||||
protected void selected(File file) {
|
||||
handler.fileSaved(file);
|
||||
close();
|
||||
}
|
||||
|
||||
protected SaveFileScreen(Screen parent, Theme theme, File root, Text title, SaveHandler handler) {
|
||||
super(parent, theme, root, title);
|
||||
this.handler = handler;
|
||||
}
|
||||
}
|
425
src/java/me/topchetoeu/mcscript/gui/TextBoxWidget.java
Executable file
425
src/java/me/topchetoeu/mcscript/gui/TextBoxWidget.java
Executable file
@ -0,0 +1,425 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||
import net.minecraft.client.gui.screen.narration.NarrationPart;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.ColorHelper.Argb;
|
||||
|
||||
public class TextBoxWidget extends Widget {
|
||||
private boolean multiline = false;
|
||||
private ArrayList<ArrayList<Character>> lines = new ArrayList<>();
|
||||
private String value;
|
||||
|
||||
private int xPos = 0, yPos = 0;
|
||||
private float xScroll = 0, yScroll = 0;
|
||||
private int maxLineLen = 0;
|
||||
|
||||
private int fontWidth() {
|
||||
return 6;
|
||||
}
|
||||
private int fontHeight() {
|
||||
return theme.fontSize();
|
||||
}
|
||||
|
||||
private void updateValue() {
|
||||
var res = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (i != 0) res.append('\n');
|
||||
for (var c : lines.get(i)) {
|
||||
res.append(c);
|
||||
}
|
||||
if (maxLineLen < lines.get(i).size()) maxLineLen = lines.get(i).size();
|
||||
}
|
||||
|
||||
value = res.toString();
|
||||
}
|
||||
private void updatePos() {
|
||||
int realX = xPos;
|
||||
if (yPos >= lines.size()) yPos = lines.size() - 1;
|
||||
if (yPos < 0) yPos = 0;
|
||||
|
||||
if (realX > lines.get(yPos).size()) realX = lines.get(yPos).size();
|
||||
if (xPos < 0) xPos = 0;
|
||||
|
||||
xScroll = Math.min(xScroll, (maxLineLen) * fontWidth() - fontWidth());
|
||||
yScroll = Math.min(yScroll, (lines.size()) * fontHeight() - fontHeight());
|
||||
|
||||
if (xScroll < 0) xScroll = 0;
|
||||
if (yScroll < 0) yScroll = 0;
|
||||
}
|
||||
private void updateScroll() {
|
||||
updatePos();
|
||||
|
||||
int realX = getCursorX();
|
||||
|
||||
yScroll = Math.min(yScroll, yPos * fontHeight());
|
||||
yScroll = Math.max(yScroll, (yPos + 1) * fontHeight() - h + theme.get("padding-s") * 2);
|
||||
|
||||
xScroll = Math.min(xScroll, realX * fontWidth());
|
||||
xScroll = Math.max(xScroll, realX * fontWidth() - w + theme.get("padding-s") * 2);
|
||||
}
|
||||
|
||||
private List<Character> getLine() {
|
||||
updatePos();
|
||||
return lines.get(yPos);
|
||||
}
|
||||
|
||||
public String getValue() { return value; }
|
||||
public TextBoxWidget setValue(String val) {
|
||||
lines.clear();
|
||||
for (var line : val.split("\n")) {
|
||||
var chars = new ArrayList<Character>();
|
||||
|
||||
for (var c : line.toCharArray()) {
|
||||
if (c == '\r') continue;
|
||||
chars.add(c);
|
||||
}
|
||||
|
||||
lines.add(chars);
|
||||
}
|
||||
|
||||
value = val;
|
||||
|
||||
updatePos();
|
||||
textChanged();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getCursorX() {
|
||||
updatePos();
|
||||
if (xPos > getLine().size()) return getLine().size();
|
||||
else return xPos;
|
||||
}
|
||||
public void setCursorX(int val) {
|
||||
xPos = val;
|
||||
|
||||
if (xPos < 0) xPos = 0;
|
||||
if (xPos > getLine().size()) xPos = getLine().size();
|
||||
|
||||
updateScroll();
|
||||
}
|
||||
public void changeCursorX(int delta) {
|
||||
setCursorX(getCursorX() + delta);
|
||||
}
|
||||
|
||||
public int getCursorY() {
|
||||
updatePos();
|
||||
return yPos;
|
||||
}
|
||||
public void setCursorY(int val) {
|
||||
yPos = val;
|
||||
|
||||
if (yPos < 0) yPos = 0;
|
||||
if (yPos >= lines.size()) yPos = lines.size() - 1;
|
||||
|
||||
updateScroll();
|
||||
}
|
||||
public void changeCursorY(int delta) {
|
||||
setCursorY(yPos + delta);
|
||||
}
|
||||
|
||||
public float getScrollX() {
|
||||
updatePos();
|
||||
|
||||
return xScroll;
|
||||
}
|
||||
public void setScrollX(float val) {
|
||||
xScroll = val;
|
||||
updatePos();
|
||||
}
|
||||
public void changeScrollX(float delta) {
|
||||
setScrollX(getScrollX() + delta);
|
||||
}
|
||||
|
||||
public float getScrollY() {
|
||||
updatePos();
|
||||
return yScroll;
|
||||
}
|
||||
public void setScrollY(float val) {
|
||||
yScroll = val;
|
||||
updatePos();
|
||||
}
|
||||
public void changeScrollY(float delta) {
|
||||
setScrollY(getScrollY() + delta);
|
||||
}
|
||||
|
||||
public boolean isMultiline() { return multiline; }
|
||||
public TextBoxWidget setMultiline(boolean value) {
|
||||
if (value == multiline) return this;
|
||||
|
||||
if (value) {
|
||||
setHeight(theme.get("padding-s") * 2 + theme.fontSize());
|
||||
var first = lines.get(0);
|
||||
lines.clear();
|
||||
lines.add(first);
|
||||
textChanged();
|
||||
}
|
||||
|
||||
multiline = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasBorders() { return true; }
|
||||
|
||||
public void input(char c) {
|
||||
updatePos();
|
||||
xPos = getCursorX();
|
||||
getLine().add(xPos, c);
|
||||
updateValue();
|
||||
xPos++;
|
||||
updateScroll();
|
||||
textChanged();
|
||||
}
|
||||
public void newLine() {
|
||||
if (!multiline) return;
|
||||
updatePos();
|
||||
|
||||
var newLine = new ArrayList<Character>();
|
||||
var currLine = getLine();
|
||||
|
||||
while (currLine.size() > xPos) {
|
||||
newLine.add(currLine.remove(xPos));
|
||||
}
|
||||
|
||||
lines.add(yPos + 1, newLine);
|
||||
|
||||
changeCursorY(1);
|
||||
setCursorX(0);
|
||||
|
||||
updateScroll();
|
||||
updateValue();
|
||||
textChanged();
|
||||
}
|
||||
public void backspace() {
|
||||
updatePos();
|
||||
|
||||
if (xPos == 0) {
|
||||
if (yPos == 0) return;
|
||||
var line = lines.remove(yPos);
|
||||
changeCursorY(-1);
|
||||
setCursorX(getLine().size());
|
||||
getLine().addAll(line);
|
||||
}
|
||||
else {
|
||||
changeCursorX(-1);
|
||||
getLine().remove(xPos);
|
||||
}
|
||||
|
||||
updateScroll();
|
||||
updateValue();
|
||||
textChanged();
|
||||
}
|
||||
public void delete() {
|
||||
updatePos();
|
||||
|
||||
if (xPos == getLine().size()) {
|
||||
if (yPos == lines.size() - 1) return;
|
||||
getLine().addAll(lines.remove(yPos + 1));
|
||||
}
|
||||
else {
|
||||
getLine().remove(xPos);
|
||||
}
|
||||
|
||||
updateScroll();
|
||||
updateValue();
|
||||
textChanged();
|
||||
}
|
||||
public void home() {
|
||||
setCursorX(0);
|
||||
updateScroll();
|
||||
}
|
||||
public void end() {
|
||||
setCursorX(getLine().size());
|
||||
updateScroll();
|
||||
}
|
||||
public void tab() {
|
||||
for (int i = getCursorX() % 4; i < 4; i++) {
|
||||
input(' ');
|
||||
}
|
||||
}
|
||||
public void right(boolean words) {
|
||||
if (words) {
|
||||
var line = getLine();
|
||||
|
||||
if (getCursorX() >= getLine().size()) {
|
||||
if (getCursorY() == lines.size() - 1) return;
|
||||
changeCursorY(1);
|
||||
setCursorX(0);
|
||||
}
|
||||
else {
|
||||
if (line.get(getCursorX()) == ' ') {
|
||||
for (; getCursorX() < getLine().size(); changeCursorX(1)) {
|
||||
if (line.get(getCursorX()) != ' ') break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; getCursorX() < getLine().size(); changeCursorX(1)) {
|
||||
if (line.get(getCursorX()) == ' ') break;
|
||||
}
|
||||
for (; getCursorX() < getLine().size(); changeCursorX(1)) {
|
||||
if (line.get(getCursorX()) != ' ') break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (getCursorX() >= getLine().size()) {
|
||||
if (getCursorY() == lines.size() - 1) return;
|
||||
changeCursorY(1);
|
||||
setCursorX(0);
|
||||
}
|
||||
else changeCursorX(1);
|
||||
updateScroll();
|
||||
}
|
||||
public void left(boolean words) {
|
||||
if (getCursorX() == 0) {
|
||||
if (getCursorY() == 0) return;
|
||||
changeCursorY(-1);
|
||||
setCursorX(getLine().size());
|
||||
}
|
||||
else if (words) {
|
||||
var line = getLine();
|
||||
|
||||
if (line.get(getCursorX() - 1) == ' ') {
|
||||
for (; getCursorX() > 0; changeCursorX(-1)) {
|
||||
if (line.get(getCursorX() - 1) != ' ') break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (; getCursorX() > 0; changeCursorX(-1)) {
|
||||
if (line.get(getCursorX() - 1) == ' ') break;
|
||||
}
|
||||
for (; getCursorX() > 0; changeCursorX(-1)) {
|
||||
if (line.get(getCursorX() - 1) != ' ') break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else changeCursorX(-1);
|
||||
updateScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Widget setRect(int x, int y, int w, int h) {
|
||||
super.setRect(x, y, w, h);
|
||||
updateScroll();
|
||||
return this;
|
||||
}
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||
try {
|
||||
boolean ctrl = (modifiers & GLFW.GLFW_MOD_CONTROL) != 0;
|
||||
|
||||
switch (keyCode) {
|
||||
case GLFW.GLFW_KEY_BACKSPACE: backspace(); return true;
|
||||
case GLFW.GLFW_KEY_DELETE: delete(); return true;
|
||||
case GLFW.GLFW_KEY_ENTER: newLine(); return true;
|
||||
case GLFW.GLFW_KEY_TAB: tab(); return true;
|
||||
|
||||
case GLFW.GLFW_KEY_UP: changeCursorY(-1); return true;
|
||||
case GLFW.GLFW_KEY_DOWN: changeCursorY(1); return true;
|
||||
case GLFW.GLFW_KEY_LEFT: left(ctrl); return true;
|
||||
case GLFW.GLFW_KEY_RIGHT: right(ctrl); return true;
|
||||
|
||||
case GLFW.GLFW_KEY_END: end(); return true;
|
||||
case GLFW.GLFW_KEY_HOME: home(); return true;
|
||||
|
||||
case GLFW.GLFW_KEY_PAGE_DOWN: {
|
||||
if (ctrl) changeScrollX(w / 2);
|
||||
else changeScrollY(h / 2);
|
||||
return true;
|
||||
}
|
||||
case GLFW.GLFW_KEY_PAGE_UP: {
|
||||
if (ctrl) changeScrollX(-w / 2);
|
||||
else changeScrollY(-h / 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean charTyped(char c, int modifiers) {
|
||||
if (c == '\n') newLine();
|
||||
input(c);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean mouseClicked(double mx, double my, int button) {
|
||||
if (!isMouseOver(mx, my)) return false;
|
||||
mx -= x - xScroll + theme.get("padding-s");
|
||||
my -= y - yScroll + theme.get("padding-s");
|
||||
|
||||
setCursorY((int)Math.floor(my / fontHeight()));
|
||||
setCursorX((int)Math.round(mx / fontWidth()));
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean mouseScrolled(double mx, double my, double amount) {
|
||||
if (!isMouseOver(mx, my)) return false;
|
||||
changeScrollY(-(float)amount * 10);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mouseX, int mouseY, float delta) {
|
||||
renderSetup();
|
||||
|
||||
mat.push();
|
||||
mat.translate(x, y, 0);
|
||||
|
||||
var width = 6;
|
||||
var height = theme.fontSize();
|
||||
|
||||
fill(mat, 0, 0, this.w, this.h, theme.get("bg-1"));
|
||||
|
||||
mat.push();
|
||||
mat.translate(theme.get("padding-s") - xScroll, theme.get("padding-s") - yScroll, 0);
|
||||
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
var line = lines.get(i);
|
||||
|
||||
for (int j = 0; j < line.size(); j++) {
|
||||
var c = line.get(j);
|
||||
float offX = (width - theme.font.getWidth(c + "")) / 2f;
|
||||
theme.font.draw(mat, c + "", j * width + offX, i * height, theme.get("text"));
|
||||
}
|
||||
}
|
||||
|
||||
drawVerticalLine(mat, xPos * width, yPos * height - 1, (yPos + 1) * height, Argb.getArgb(255, 255, 0, 0));
|
||||
|
||||
mat.pop();
|
||||
mat.pop();
|
||||
|
||||
renderFinalize();
|
||||
|
||||
super.render(mat, mouseX, mouseY, delta);
|
||||
}
|
||||
|
||||
protected void textChanged() { }
|
||||
|
||||
@Override
|
||||
public void appendNarrations(NarrationMessageBuilder nmb) {
|
||||
nmb.put(NarrationPart.USAGE, "Text box");
|
||||
}
|
||||
@Override
|
||||
public SelectionType getType() {
|
||||
return SelectionType.NONE;
|
||||
}
|
||||
|
||||
public TextBoxWidget(Theme theme) {
|
||||
super(theme);
|
||||
this.h = theme.fontSize() + theme.get("padding-s") * 2;
|
||||
this.setValue("");
|
||||
updateScroll();
|
||||
}
|
||||
}
|
53
src/java/me/topchetoeu/mcscript/gui/Theme.java
Executable file
53
src/java/me/topchetoeu/mcscript/gui/Theme.java
Executable file
@ -0,0 +1,53 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.util.math.ColorHelper.Argb;
|
||||
|
||||
public class Theme {
|
||||
public final Map<String, Integer> colors = new HashMap<>();
|
||||
public TextRenderer font;
|
||||
public int fontSize() { return font.fontHeight; }
|
||||
|
||||
public Theme add(String name, int col) {
|
||||
colors.put(name, col);
|
||||
return this;
|
||||
}
|
||||
public Theme add(String name, int r, int g, int b, int a) {
|
||||
colors.put(name, Argb.getArgb(a, r, g, b));
|
||||
return this;
|
||||
}
|
||||
public int get(String name) {
|
||||
var res = colors.get(name);
|
||||
if (res == null) return 0;
|
||||
else return res;
|
||||
}
|
||||
|
||||
public Theme setTheme(Theme t) {
|
||||
if (t == this) return this;
|
||||
colors.clear();
|
||||
colors.putAll(colors);
|
||||
return this;
|
||||
}
|
||||
public Theme setFont(TextRenderer font) {
|
||||
this.font = font;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public static Theme dark(TextRenderer font) {
|
||||
return new Theme()
|
||||
.setFont(font)
|
||||
.add("padding-s", 2)
|
||||
.add("padding-m", 3)
|
||||
.add("padding-l", 5)
|
||||
.add("bg-1", 0, 0, 0, 255)
|
||||
.add("bg-2", 40, 40, 40, 255)
|
||||
.add("bg-3", 80, 80, 80, 255)
|
||||
.add("bg-4", 100, 100, 100, 255)
|
||||
.add("border", 255, 255, 255, 255)
|
||||
.add("text", 255, 255, 255, 255);
|
||||
}
|
||||
}
|
101
src/java/me/topchetoeu/mcscript/gui/Widget.java
Executable file
101
src/java/me/topchetoeu/mcscript/gui/Widget.java
Executable file
@ -0,0 +1,101 @@
|
||||
package me.topchetoeu.mcscript.gui;
|
||||
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.Drawable;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.Element;
|
||||
import net.minecraft.client.gui.Selectable;
|
||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
||||
public abstract class Widget extends DrawableHelper implements Element, Drawable, Selectable {
|
||||
public final Theme theme;
|
||||
protected int x, y, w, h;
|
||||
|
||||
protected abstract boolean hasBorders();
|
||||
|
||||
public final int getX() { return x; }
|
||||
public final Widget setX(int val) { return setPos(val, y); }
|
||||
|
||||
public final int getY() { return y; }
|
||||
public final Widget setY(int val) { return setPos(x, val); }
|
||||
|
||||
public final int getWidth() { return w; }
|
||||
public final Widget setWidth(int value) { return setSize(value, h); }
|
||||
|
||||
public final int getHeight() { return h; }
|
||||
public final Widget setHeight(int value) { return setSize(w, value); }
|
||||
|
||||
public final Widget setPos(int x, int y) {
|
||||
return setRect(x, y, w, h);
|
||||
}
|
||||
public final Widget setSize(int w, int h) {
|
||||
return setRect(x, y, w, h);
|
||||
}
|
||||
public Widget setRect(int x, int y, int w, int h) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(boolean focused) {
|
||||
}
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMouseOver(double mx, double my) {
|
||||
return mx >= x && mx < x + w && my >= y && my < y + h;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendNarrations(NarrationMessageBuilder var1) {
|
||||
}
|
||||
@Override
|
||||
public SelectionType getType() {
|
||||
return SelectionType.NONE;
|
||||
}
|
||||
|
||||
protected void renderSetup() {
|
||||
var m = RenderSystem.getProjectionMatrix();
|
||||
var pos = m.transform(new Vector4f(x, y, 0, 1));
|
||||
var scale = m.transform(new Vector4f(w, h, 0, 0));
|
||||
|
||||
int wndw = MinecraftClient.getInstance().getWindow().getWidth();
|
||||
int wndh = MinecraftClient.getInstance().getWindow().getHeight();
|
||||
|
||||
int x = (int)Math.round((pos.x + 1) / 2 * wndw);
|
||||
int y = (int)Math.round((-pos.y + 1) / 2 * wndh);
|
||||
int w = (int)Math.round(scale.x / 2 * wndw);
|
||||
int h = (int)Math.round(-scale.y / 2 * wndh);
|
||||
|
||||
y = wndh - y - h;
|
||||
|
||||
RenderSystem.enableScissor(x, y, w, h);
|
||||
}
|
||||
protected void renderFinalize() {
|
||||
RenderSystem.disableScissor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack mat, int mx, int my, float delta) {
|
||||
int col = theme.get("border");
|
||||
drawHorizontalLine(mat, x - 1, x + w, y - 1, col);
|
||||
drawHorizontalLine(mat, x - 1, x + w, y + h, col);
|
||||
drawVerticalLine(mat, x - 1, y - 1, y + h, col);
|
||||
drawVerticalLine(mat, x + w, y - 1, y + h, col);
|
||||
}
|
||||
|
||||
public Widget(Theme theme) {
|
||||
this.theme = theme;
|
||||
}
|
||||
}
|
5
src/java/me/topchetoeu/mcscript/loader/ModLoader.java
Normal file
5
src/java/me/topchetoeu/mcscript/loader/ModLoader.java
Normal file
@ -0,0 +1,5 @@
|
||||
package me.topchetoeu.mcscript.loader;
|
||||
|
||||
public interface ModLoader {
|
||||
|
||||
}
|
37
src/java/me/topchetoeu/mcscript/mixin/ChatScreenMixin.java
Executable file
37
src/java/me/topchetoeu/mcscript/mixin/ChatScreenMixin.java
Executable file
@ -0,0 +1,37 @@
|
||||
package me.topchetoeu.mcscript.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import me.topchetoeu.mcscript.events.ChatMessageCallback;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ChatScreen;
|
||||
|
||||
@Mixin(ChatScreen.class)
|
||||
public abstract class ChatScreenMixin {
|
||||
|
||||
@Inject(method = "sendMessage", at = @At(value = "INVOKE", target = "Ljava/lang/String;startsWith(Ljava/lang/String;)Z"), cancellable = true)
|
||||
private void onSendMessage(String chatText, boolean addToHistory, CallbackInfoReturnable<Boolean> cbi) {
|
||||
var client = MinecraftClient.getInstance();
|
||||
|
||||
var args = new ChatMessageCallback.ChatArgs();
|
||||
args.message = chatText;
|
||||
args.cancelled = false;
|
||||
ChatMessageCallback.EVENT.invoker().execute(args);
|
||||
|
||||
if (!args.cancelled) {
|
||||
chatText = args.message;
|
||||
|
||||
if (chatText.startsWith("/")) {
|
||||
client.player.networkHandler.sendChatCommand(chatText.substring(1));
|
||||
} else {
|
||||
client.player.networkHandler.sendChatMessage(chatText);
|
||||
}
|
||||
}
|
||||
|
||||
cbi.setReturnValue(true);
|
||||
cbi.cancel();
|
||||
}
|
||||
}
|
22
src/java/me/topchetoeu/mcscript/mixin/KeyboardMixin.java
Executable file
22
src/java/me/topchetoeu/mcscript/mixin/KeyboardMixin.java
Executable file
@ -0,0 +1,22 @@
|
||||
package me.topchetoeu.mcscript.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.Keyboard;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
@Mixin(Keyboard.class)
|
||||
public class KeyboardMixin {
|
||||
@Inject(method = "onChar", at = @At("HEAD"))
|
||||
private void onChar(long window, int codePoint, int modifiers, CallbackInfo cbi) {
|
||||
var client = MinecraftClient.getInstance();
|
||||
for (var ch : Character.toChars(codePoint)) {
|
||||
if (client.currentScreen == null && client.getOverlay() == null && ch == '#') {
|
||||
((MinecraftClientMixin)client).invokeOpenChatScreen("");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
src/java/me/topchetoeu/mcscript/mixin/MinecraftClientMixin.java
Executable file
12
src/java/me/topchetoeu/mcscript/mixin/MinecraftClientMixin.java
Executable file
@ -0,0 +1,12 @@
|
||||
package me.topchetoeu.mcscript.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public interface MinecraftClientMixin {
|
||||
@Invoker
|
||||
void invokeOpenChatScreen(String text);
|
||||
}
|
Loading…
Reference in New Issue
Block a user