21 Commits

Author SHA1 Message Date
828cf88518 Merge pull request 'Change Language to Lua' (#1) from lua into main
Reviewed-on: https://steamwar.de/devlabs/SteamWar/AdvancedScripts/pulls/1
2023-07-17 16:41:20 +02:00
279042b987 Add Copyright & Rename Package 2023-07-17 15:55:06 +02:00
2d1c320792 Remove AWT 2023-06-10 16:37:14 +02:00
a9d3fa0bbb Add Icon 2023-06-06 23:24:38 +02:00
743ec5d565 Fixes 2023-06-06 23:12:21 +02:00
e5df33c19a Adjust Color 2023-06-06 23:02:58 +02:00
28856d8bd5 Remove Debug 2023-06-06 22:46:45 +02:00
126ac736ae Add Lua Support 2023-06-06 22:36:58 +02:00
b74cb2e053 Fix AdvancedScripts 2022-12-28 21:08:16 +01:00
d10dd665f5 Merge branch 'ScriptEditor'
# Conflicts:
#	src/main/resources/advancedscripts.mixins.json
2022-12-28 14:27:24 +01:00
2cbf095826 Add autoscroll 2022-12-28 11:48:45 +01:00
118b258244 Fix selection errors 2022-12-28 11:35:35 +01:00
36151e3a46 Add selection and copy, paste and cut 2022-12-28 11:30:12 +01:00
a6e2fa7fc5 Add button to go to Book form 2022-12-25 17:51:08 +01:00
fe037aa766 Fix save book 2022-12-25 15:38:10 +01:00
ec973e3104 Fix save book 2022-12-25 15:24:55 +01:00
06b46966b8 Add scrolling via mouse 2022-12-25 14:53:08 +01:00
702865eba1 Finalize basic editor 2022-12-25 14:38:05 +01:00
22939d42e0 Add basic editor and move cursor 2022-12-25 10:11:40 +01:00
909bce4092 Finalize ExpressionColorizer 2022-12-25 09:50:44 +01:00
cf06c30b54 Add basic Script visualization and colorization 2022-12-25 00:12:55 +01:00
14 changed files with 964 additions and 48 deletions

View File

@ -11,6 +11,7 @@ version = project.mod_version
group = project.maven_group
repositories {
mavenCentral()
}
dependencies {

View File

@ -9,6 +9,6 @@ org.gradle.parallel=true
loader_version=0.14.11
# Mod Properties
mod_version = 1.0.0
mod_version = 2.0.0
maven_group = de.zonlykroks
archives_base_name = AdvancedScripts

View File

@ -0,0 +1,29 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts;
import net.fabricmc.api.ClientModInitializer;
public class AdvancedScripts implements ClientModInitializer {
@Override
public void onInitializeClient() {
}
}

View File

@ -0,0 +1,131 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.lexer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class ScriptColorizer {
private static final Set<String> KEYWORDS = Set.of(
"and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "until", "while"
);
private ScriptColorizer() {
throw new IllegalStateException("Utility class██");
}
public static List<Token> colorize(String line) {
List<Token> tokens = colorizeComment(line);
if (tokens != null) return tokens;
return colorizeLine(line);
}
private static List<Token> colorizeComment(String line) {
if (!line.startsWith("--")) return null;
return List.of(new Token(line, TokenTypeColors.COMMENT));
}
private static List<Token> colorizeLine(String line) {
List<Token> tokens = new ArrayList<>();
StringBuilder currentToken = new StringBuilder();
boolean inString = false;
boolean doubleQuoteString = false;
for (char c : line.toCharArray()) {
switch (c) {
case '"' -> {
if (inString) {
currentToken.append(c);
if (doubleQuoteString) {
tokens.add(new Token(currentToken.toString(), TokenTypeColors.STRING));
currentToken = new StringBuilder();
inString = false;
doubleQuoteString = false;
}
} else {
inString = true;
doubleQuoteString = true;
if (currentToken.length() > 0) {
tokens.add(toToken(currentToken.toString()));
currentToken = new StringBuilder();
}
currentToken.append(c);
}
}
case '\'' -> {
if (inString) {
currentToken.append(c);
if (!doubleQuoteString) {
tokens.add(new Token(currentToken.toString(), TokenTypeColors.STRING));
currentToken = new StringBuilder();
inString = false;
}
} else {
inString = true;
doubleQuoteString = false;
if (currentToken.length() > 0) {
tokens.add(toToken(currentToken.toString()));
currentToken = new StringBuilder();
}
currentToken.append(c);
}
}
case '-', ';', '(', ')', ',', ' ', '{', '\t' -> {
if (inString) {
currentToken.append(c);
} else {
if(currentToken.length() > 0) {
tokens.add(toToken(currentToken.toString()));
}
tokens.add(new Token(String.valueOf(c), TokenTypeColors.OTHER));
currentToken = new StringBuilder();
}
}
default -> currentToken.append(c);
}
}
if (currentToken.length() > 0) {
tokens.add(toToken(currentToken.toString()));
}
return tokens;
}
private static Token toToken(String text) {
if (text.length() > 0) {
if (KEYWORDS.contains(text)) {
return new Token(text, TokenTypeColors.CONSTANT);
} else if ("true".contentEquals(text) || "false".contentEquals(text)) {
return new Token(text, TokenTypeColors.BOOLEAN);
} else if (text.matches("[0-9]+")) {
return new Token(text, TokenTypeColors.NUMBER);
} else {
return new Token(text, TokenTypeColors.OTHER);
}
} else {
return Token.SPACE;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.lexer;
public class Token {
public static final Token SPACE = new Token(" ", 0xFFFFFFFF);
public final String text;
public final int color;
public Token(String text, int color) {
this.text = text;
this.color = color;
}
@Override
public String toString() {
return "Token{" +
"text='" + text + '\'' +
", color=" + color +
'}';
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.lexer;
public class TokenTypeColors {
private TokenTypeColors() {
throw new IllegalStateException("Utility class");
}
public static final int BACKGROUND = 0xFF1E1F22;
public static final int SELECTION = 0xFF23437F;
public static final int OTHER = 0xFFFFFFFF;
public static final int ERROR = 0xFFAA0000;
public static final int VARIABLE = 0xFFFFFFFF;
public static final int COMMENT = 0xFF656565;
public static final int CONSTANT = 0x3F6EC6;
public static final int NUMBER = 0xFF61839F;
public static final int BOOLEAN = 0xFF925F35;
public static final int STRING = 0x6a8759;
}

View File

@ -0,0 +1,47 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.mixin;
import de.steamwar.advancedscripts.screen.ScriptEditScreen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.Hand;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ClientPlayerEntity.class)
public class ClientPlayerEntityMixin {
@Shadow @Final protected MinecraftClient client;
@Inject(method = "useBook", at = @At("HEAD"), cancellable = true)
public void useBookMixin(ItemStack book, Hand hand, CallbackInfo ci) {
if (book.isOf(Items.WRITABLE_BOOK)) {
this.client.setScreen(new ScriptEditScreen(((ClientPlayerEntity)(Object)this), book, hand));
ci.cancel();
}
}
}

View File

@ -1,20 +1,23 @@
/*
This file is a part of the SteamWar software.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.zonlykroks.advancedscripts.mixin;
package de.steamwar.advancedscripts.mixin;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Keyboard;

View File

@ -0,0 +1,647 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.advancedscripts.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import de.steamwar.advancedscripts.lexer.TokenTypeColors;
import de.steamwar.advancedscripts.lexer.ScriptColorizer;
import de.steamwar.advancedscripts.lexer.Token;
import net.minecraft.client.font.TextHandler;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.BookEditScreen;
import net.minecraft.client.gui.screen.ingame.BookScreen;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.client.gui.widget.PressableWidget;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.client.util.NarratorManager;
import net.minecraft.client.util.SelectionManager;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.network.packet.c2s.play.BookUpdateC2SPacket;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Hand;
import org.apache.commons.lang3.mutable.MutableInt;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ScriptEditScreen extends Screen {
private PlayerEntity player;
private ItemStack itemStack;
private Hand hand;
private List<String> lines = new ArrayList<>();
private int scroll = 0;
private int cursorY = 0;
private int cursorX = 0;
private int savedCursorY = -1;
private int savedCursorX = -1;
private int tickCounter;
private int keyCode = -1;
private long time;
public ScriptEditScreen(PlayerEntity player, ItemStack itemStack, Hand hand) {
super(NarratorManager.EMPTY);
this.player = player;
this.itemStack = itemStack;
this.hand = hand;
NbtCompound nbtCompound = itemStack.getNbt();
if (nbtCompound != null) {
BookScreen.filterPages(nbtCompound, s -> {
String[] split = s.split("\n");
for (String s1 : split) {
if (s1.equals(" ")) {
lines.add("");
} else {
lines.add(s1);
}
}
});
}
if (lines.isEmpty()) {
lines.add("");
}
}
@Override
protected void init() {
this.addDrawableChild(
new Button(CANCEL, this.width / 2 - 100, height - 55, () -> this.client.setScreen(null))
);
this.addDrawableChild(
new Button(DONE, this.width / 2 + 2, height - 55, () -> {
this.client.setScreen(null);
finalizeBook();
})
);
this.addDrawableChild(
new Button(BOOK, this.width - 98 - 5, height - 20 - 5, () -> {
finalizeBook();
this.client.setScreen(new BookEditScreen(player, itemStack, hand));
})
);
}
public static final Text DONE = Text.translatable("gui.done");
public static final Text CANCEL = Text.translatable("gui.cancel");
public static final Text BOOK = Text.translatable("item.minecraft.book");
private static class Button extends PressableWidget {
private Runnable onPress;
public Button(Text text, int x, int y, Runnable onPress) {
super(x, y, 98, 20, text);
visible = true;
this.onPress = onPress;
}
@Override
public void onPress() {
onPress.run();
}
@Override
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
}
@Override
public boolean isNarratable() {
return false;
}
}
private void setClipboard(String clipboard) {
if (this.client != null) {
SelectionManager.setClipboard(this.client, clipboard);
}
}
private String getClipboard() {
return this.client != null ? SelectionManager.getClipboard(this.client) : "";
}
@Override
public void tick() {
super.tick();
++this.tickCounter;
if (keyCode != -1 && System.currentTimeMillis() - time > 500) {
key(keyCode);
}
}
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
setFocused(null);
this.renderBackground(matrices);
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
fill(matrices, 23, 23, this.width - 23, this.height - 63, TokenTypeColors.BACKGROUND);
int lineNumberLength = textRenderer.getWidth(lines.size() + "");
boolean hasSelection = savedCursorY != -1 && savedCursorX != -1;
int minSelectionY = Math.min(cursorY, savedCursorY);
int maxSelectionY = Math.max(cursorY, savedCursorY);
int minSelectionX = (minSelectionY == maxSelectionY ? Math.min(cursorX, savedCursorX) : (minSelectionY == cursorY ? cursorX : savedCursorX));
int maxSelectionX = (minSelectionY == maxSelectionY ? Math.max(cursorX, savedCursorX) : (maxSelectionY == cursorY ? cursorX : savedCursorX));
int lineNumberText = scroll + 1;
MutableInt lineNumber = new MutableInt();
TextHandler textHandler = this.textRenderer.getTextHandler();
for (int i = scroll; i < lines.size(); i++) {
String s = lines.get(i);
if (lineNumber.getValue() * 9 + 25 > this.height - 66) {
break;
}
if (s.isEmpty() && i == cursorY) {
drawCursor(matrices, 25 + lineNumberLength + 5, lineNumber.getValue() * 9 + 25, true);
}
// Line number
int height = this.textRenderer.getWrappedLinesHeight(s, this.width - 50 - lineNumberLength - 5);
if (lineTooLong(s)) {
fill(matrices, 25 + lineNumberLength + 2, 25 + lineNumber.getValue() * 9, 25 + lineNumberLength + 3, 25 + lineNumber.getValue() * 9 + height, TokenTypeColors.ERROR);
}
this.textRenderer.draw(matrices, String.valueOf(lineNumberText), 25f + lineNumberLength - textRenderer.getWidth(String.valueOf(lineNumberText)), 25f + lineNumber.getValue() * 9f, 0xFFFFFF);
lineNumberText++;
// Line text
List<Token> tokens = ScriptColorizer.colorize(s);
AtomicInteger x = new AtomicInteger(25 + lineNumberLength + 5);
AtomicInteger currentXIndex = new AtomicInteger(0);
for (Token token : tokens) {
int finalI = i;
textHandler.wrapLines(token.text, this.width - x.get() - 25, Style.EMPTY, true, (style, start, end) -> {
int y = lineNumber.getValue() * 9;
if (y + 25 > this.height - 66) {
return;
}
String line = token.text.substring(start, end);
int previousXIndex = currentXIndex.get();
currentXIndex.addAndGet(line.length());
if (hasSelection) {
int x1 = x.get();
int x2 = x.get() + textRenderer.getWidth(line);
if (finalI == minSelectionY) {
if (minSelectionX > currentXIndex.get()) {
x2 = 0;
} else if (minSelectionX <= currentXIndex.get() && minSelectionX >= previousXIndex) {
int startInLine = minSelectionX - previousXIndex;
x1 += textRenderer.getWidth(line.substring(0, startInLine));
}
}
if (finalI == maxSelectionY) {
if (maxSelectionX < previousXIndex) {
x2 = 0;
} else if (maxSelectionX <= currentXIndex.get()) {
int endInLine = maxSelectionX - previousXIndex;
x2 = x.get() + textRenderer.getWidth(line.substring(0, endInLine));
}
}
if (finalI >= minSelectionY && finalI <= maxSelectionY && x2 > x1) {
fill(matrices, x1, y + 25, x2, y + 25 + 9, TokenTypeColors.SELECTION);
}
}
if (finalI == cursorY && currentXIndex.get() >= cursorX && previousXIndex <= cursorX) {
drawCursor(matrices, x.get() + textRenderer.getWidth(line.substring(0, cursorX - previousXIndex)) - 1, 25 + y, isAtEndOfLine());
}
this.textRenderer.draw(matrices, line, x.get(), 25 + y, token.color);
x.addAndGet(textRenderer.getWidth(line));
if (x.get() > this.width - 50 - lineNumberLength - 5) {
x.set(25 + lineNumberLength + 5);
lineNumber.increment();
}
});
}
lineNumber.increment();
}
super.render(matrices, mouseX, mouseY, delta);
}
private boolean lineTooLong(String s) {
if (s.length() >= 1024) {
return true;
}
return textRenderer.getWrappedLinesHeight(s, 114) > 128;
}
private void drawCursor(MatrixStack matrices, int x, int y, boolean atEnd) {
if (this.tickCounter / 6 % 2 == 0) {
if (!atEnd) {
Objects.requireNonNull(this.textRenderer);
DrawableHelper.fill(matrices, x, y - 1, x + 1, y + 9, 0xFFFFFFFF);
} else {
this.textRenderer.draw(matrices, "_", (float) x, (float) y, 0xFFFFFFFF);
}
}
}
private void key(int keyCode) {
setFocused(null);
if (Screen.isSelectAll(keyCode)) {
this.cursorX = 0;
this.cursorY = 0;
this.savedCursorX = lines.get(lines.size() - 1).length();
this.savedCursorY = lines.size() - 1;
return;
} else if (Screen.isCopy(keyCode)) {
String copied = selection(false);
if (copied != null) {
setClipboard(copied);
}
return;
} else if (Screen.isPaste(keyCode)) {
String copied = getClipboard();
if (copied != null) {
insert(copied);
}
return;
} else if (Screen.isCut(keyCode)) {
String copied = selection(true);
if (copied != null) {
setClipboard(copied);
}
return;
}
SelectionManager.SelectionType selectionType = Screen.hasControlDown() ? SelectionManager.SelectionType.WORD : SelectionManager.SelectionType.CHARACTER;
boolean valid = true;
int previousCursorX = cursorX;
int previousCursorY = cursorY;
switch (keyCode) {
case 258 -> {
insert(" ");
return;
}
case 257, 335 -> {
selection(true);
newLine();
valid = false;
}
case 259 -> {
if (selection(true) == null) backspace(selectionType);
valid = false;
}
case 261 -> {
if (selection(true) == null) delete(selectionType);
valid = false;
}
case 262 -> {
moveCursor(1, selectionType);
valid = Screen.hasShiftDown();
}
case 263 -> {
moveCursor(-1, selectionType);
valid = Screen.hasShiftDown();
}
case 264 -> {
moveDown();
valid = Screen.hasShiftDown();
}
case 265 -> {
moveUp();
valid = Screen.hasShiftDown();
}
case 268 -> {
cursorX = 0;
valid = Screen.hasShiftDown();
}
case 269 -> {
cursorX = lines.get(cursorY).length();
valid = Screen.hasShiftDown();
}
default -> {
}
}
if (valid) {
if (Screen.hasShiftDown() && savedCursorX == -1 && savedCursorY == -1) {
savedCursorX = previousCursorX;
savedCursorY = previousCursorY;
}
} else {
savedCursorY = -1;
savedCursorX = -1;
}
autoScroll();
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
setFocused(null);
if (super.keyPressed(keyCode, scanCode, modifiers)) {
return true;
}
key(keyCode);
this.keyCode = keyCode;
this.time = System.currentTimeMillis();
return true;
}
@Override
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
setFocused(null);
this.keyCode = -1;
return super.keyReleased(keyCode, scanCode, modifiers);
}
@Override
public boolean charTyped(char chr, int modifiers) {
setFocused(null);
if (super.charTyped(chr, modifiers)) {
return true;
}
selection(true);
boolean valid = insert(String.valueOf(chr));
savedCursorY = -1;
savedCursorX = -1;
autoScroll();
return valid;
}
private String selection(boolean remove) {
if (savedCursorX == -1 || savedCursorY == -1) {
return null;
}
int minSelectionY = Math.min(savedCursorY, cursorY);
int maxSelectionY = Math.max(savedCursorY, cursorY);
int minSelectionX = (minSelectionY == maxSelectionY ? Math.min(cursorX, savedCursorX) : (minSelectionY == cursorY ? cursorX : savedCursorX));
int maxSelectionX = (minSelectionY == maxSelectionY ? Math.max(cursorX, savedCursorX) : (maxSelectionY == cursorY ? cursorX : savedCursorX));
StringBuilder builder = new StringBuilder();
for (int i = minSelectionY; i <= maxSelectionY; i++) {
String line = lines.get(i);
if (i == minSelectionY && i == maxSelectionY) {
builder.append(line, minSelectionX, maxSelectionX);
} else if (i == minSelectionY) {
builder.append(line, minSelectionX, line.length());
} else if (i == maxSelectionY) {
builder.append(line, 0, Math.min(maxSelectionX, line.length()));
} else {
builder.append(line);
}
if (i != maxSelectionY) {
builder.append("\n");
}
}
if (remove) {
for (int i = maxSelectionY; i >= minSelectionY; i--) {
String line = lines.get(i);
if (i == minSelectionY && i == maxSelectionY) {
lines.set(i, line.substring(0, minSelectionX) + line.substring(maxSelectionX));
} else if (i == minSelectionY) {
lines.set(i, line.substring(0, minSelectionX));
} else if (i == maxSelectionY) {
lines.set(i, line.substring(Math.min(maxSelectionX, line.length())));
} else {
lines.remove(i);
}
}
if (minSelectionY != maxSelectionY) {
lines.set(minSelectionY, lines.get(minSelectionY) + lines.get(minSelectionY + 1));
lines.remove(minSelectionY + 1);
}
cursorX = minSelectionX;
cursorY = minSelectionY;
savedCursorX = -1;
savedCursorY = -1;
}
return builder.toString();
}
private boolean insert(String s) {
String[] split = s.split("\n");
for (int i = 0; i < split.length; i++) {
String line = lines.get(cursorY);
if (cursorX == line.length()) {
line += split[i];
} else {
line = line.substring(0, cursorX) + split[i] + line.substring(cursorX);
}
lines.set(cursorY, line);
cursorX += split[i].length();
if (i != split.length - 1) {
newLine();
}
}
return true;
}
private boolean newLine() {
String line = lines.get(cursorY);
String newLine = line.substring(cursorX);
line = line.substring(0, cursorX);
lines.set(cursorY, line);
lines.add(cursorY + 1, newLine);
cursorY++;
cursorX = 0;
return true;
}
private boolean backspace(SelectionManager.SelectionType selectionType) {
if (cursorX == 0) {
if (cursorY == 0) {
return true;
}
String previousLine = lines.get(cursorY - 1);
lines.set(cursorY - 1, lines.get(cursorY - 1) + lines.remove(cursorY));
cursorY--;
cursorX = previousLine.length();
} else {
String line = lines.get(cursorY);
int remove = selectionType == SelectionManager.SelectionType.CHARACTER ? 1 : getWordLength(line, cursorX, -1);
line = line.substring(0, cursorX - remove) + line.substring(cursorX);
lines.set(cursorY, line);
cursorX -= remove;
}
return true;
}
private boolean delete(SelectionManager.SelectionType selectionType) {
if (cursorX == lines.get(cursorY).length()) {
if (cursorY == lines.size() - 1) {
return true;
}
String nextLine = lines.get(cursorY + 1);
lines.remove(cursorY);
lines.set(cursorY, lines.get(cursorY) + nextLine);
} else {
String line = lines.get(cursorY);
int remove = selectionType == SelectionManager.SelectionType.CHARACTER ? 1 : getWordLength(line, cursorX, 1);
line = line.substring(0, cursorX) + line.substring(cursorX + remove);
lines.set(cursorY, line);
}
return true;
}
private int getWordLength(String line, int cursorX, int direction) {
int i = cursorX;
while (i >= 0 && i < line.length()) {
char c = line.charAt(i);
if (Character.isLetterOrDigit(c)) {
i += direction;
} else {
break;
}
}
return Math.abs(i - cursorX);
}
private boolean moveCursor(int offset, SelectionManager.SelectionType selectionType) {
if (offset == 0) {
return true;
}
String line = lines.get(cursorY);
if (offset > 0) {
if (cursorX == line.length()) {
if (cursorY == lines.size() - 1) {
return true;
}
cursorY++;
cursorX = 0;
} else {
cursorX += selectionType == SelectionManager.SelectionType.CHARACTER ? 1 : getWordLength(line, cursorX, 1);
}
} else {
if (cursorX == 0) {
if (cursorY == 0) {
return true;
}
cursorY--;
cursorX = lines.get(cursorY).length();
} else {
cursorX -= selectionType == SelectionManager.SelectionType.CHARACTER ? 1 : getWordLength(line, cursorX, -1);
}
}
return true;
}
private boolean moveDown() {
if (cursorY == lines.size() - 1) {
cursorX = lines.get(cursorY).length();
return true;
}
cursorY++;
cursorX = Math.min(cursorX, lines.get(cursorY).length());
return true;
}
private boolean moveUp() {
if (cursorY == 0) {
cursorX = 0;
return true;
}
cursorY--;
cursorX = Math.min(cursorX, lines.get(cursorY).length());
return true;
}
private void autoScroll() {
if (cursorY < scroll) {
scroll = cursorY;
} else if (cursorY >= scroll + ((this.height - 25 - 66) / 9)) {
scroll = cursorY - ((this.height - 25 - 66) / 9);
}
}
private boolean isAtEndOfLine() {
return cursorX == lines.get(cursorY).length();
}
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
scroll -= Math.signum(amount);
if (scroll > lines.size() - 1) {
scroll = lines.size() - 1;
}
if (scroll < 0) {
scroll = 0;
}
return true;
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
return super.mouseClicked(mouseX, mouseY, button);
}
private List<String> toPages() {
List<String> pages = new ArrayList<>();
StringBuilder page = new StringBuilder();
for (String line : lines) {
if (!page.isEmpty()) {
page.append("\n");
}
if (page.length() + line.length() > 1024) {
pages.add(page.toString());
page = new StringBuilder();
}
String temp = page + line;
if (textRenderer.getWrappedLinesHeight(temp, 114) > 128) {
pages.add(page.toString());
page = new StringBuilder();
}
if (line.isEmpty()) {
page.append(" ");
} else {
page.append(line);
}
}
if (!page.isEmpty()) {
pages.add(page.toString());
}
return pages;
}
private void finalizeBook() {
List<String> pages = toPages();
this.writeNbtData(pages);
int i = this.hand == Hand.MAIN_HAND ? this.player.getInventory().selectedSlot : 40;
this.client.getNetworkHandler().sendPacket(new BookUpdateC2SPacket(i, pages, Optional.empty()));
}
private void writeNbtData(List<String> pages) {
NbtList nbtList = new NbtList();
pages.stream().map(NbtString::of).forEach(nbtList::add);
if (!pages.isEmpty()) {
this.itemStack.setSubNbt("pages", nbtList);
}
}
}

View File

@ -1,26 +0,0 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.zonlykroks.advancedscripts;
import net.fabricmc.api.ClientModInitializer;
public class AdvancedScripts implements ClientModInitializer {
@Override
public void onInitializeClient() {
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -1,12 +1,13 @@
{
"required": true,
"minVersion": "0.8",
"package": "de.zonlykroks.advancedscripts.mixin",
"package": "de.steamwar.advancedscripts.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
],
"client": [
"KeyboardMixin"
"KeyboardMixin",
"ClientPlayerEntityMixin"
],
"injectors": {
"defaultRequire": 1

View File

@ -6,13 +6,15 @@
"name": "Advanced Scripts",
"description": "An addition to the Steamwar script system!",
"authors": [
"zOnlyKroks"
"zOnlyKroks",
"Chaoscaot"
],
"icon": "advanced-scripts-icon.png",
"license": "AGPL-3.0",
"environment": "client",
"entrypoints": {
"client": [
"de.zonlykroks.advancedscripts.AdvancedScripts"
"de.steamwar.advancedscripts.AdvancedScripts"
]
},
"mixins": [
@ -20,7 +22,7 @@
],
"depends": {
"fabricloader": ">=0.14.11",
"minecraft": ">=1.19.2",
"minecraft": ">=1.19.3",
"java": ">=17"
},
"accessWidener" : "advancedscripts.accesswidener"

View File

@ -2,4 +2,4 @@ build:
- "./gradlew remapJar"
artifacts:
"/binarys/AdvancedScripts.jar": "build/libs/AdvancedScripts-1.0.0.jar"
"/binarys/AdvancedScripts.jar": "build/libs/AdvancedScripts-2.0.0.jar"