# Conflicts: # src/main/resources/advancedscripts.mixins.json
Dieser Commit ist enthalten in:
Commit
d10dd665f5
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Command.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Command.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Command {
|
||||
public final boolean repeatable;
|
||||
public final List<List<TokenType>> arguments;
|
||||
|
||||
public Command(boolean repeatable, List<List<TokenType>> arguments) {
|
||||
this.repeatable = repeatable;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
}
|
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Commands.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Commands.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Commands {
|
||||
|
||||
private Commands() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static Map<String, Command> COMMANDS = new HashMap<>();
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ExpressionColorizer {
|
||||
|
||||
private ExpressionColorizer() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static List<Token> colorize(String expression) {
|
||||
List<String> parts = tokenize(expression);
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
String part = parts.get(i);
|
||||
if ("{".equals(part) || "}".equals(part)) {
|
||||
tokens.add(new Token(part, TokenTypeColors.OTHER));
|
||||
continue;
|
||||
}
|
||||
if ("true".equalsIgnoreCase(part) || "false".equalsIgnoreCase(part)) {
|
||||
tokens.add(new Token(part, TokenTypeColors.BOOLEAN));
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Double.parseDouble(part);
|
||||
tokens.add(new Token(part, TokenTypeColors.NUMBER));
|
||||
continue;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
try {
|
||||
Long.parseLong(part);
|
||||
tokens.add(new Token(part, TokenTypeColors.NUMBER));
|
||||
continue;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
if (part.contains(".")) {
|
||||
String[] split = part.split("\\.");
|
||||
if (split.length == 1) {
|
||||
tokens.add(new Token(part, TokenTypeColors.VARIABLE));
|
||||
continue;
|
||||
}
|
||||
if (VariablePrefixes.RPEFIXES.contains(split[0])) {
|
||||
tokens.add(new Token(split[0], TokenTypeColors.OTHER));
|
||||
tokens.add(new Token(".", TokenTypeColors.OTHER));
|
||||
split = Arrays.copyOfRange(split, 1, split.length);
|
||||
}
|
||||
tokens.add(new Token(split[0], TokenTypeColors.VARIABLE));
|
||||
for (int j = 1; j < split.length; j++) {
|
||||
String s = split[j];
|
||||
tokens.add(new Token(".", TokenTypeColors.OTHER));
|
||||
if (VariableSuffixes.SUFFIXES.contains(s)) {
|
||||
tokens.add(new Token(s, TokenTypeColors.OTHER));
|
||||
} else {
|
||||
tokens.add(new Token(s, TokenTypeColors.ERROR));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Operators.OPERATORS.contains(part)) {
|
||||
String previous = get(parts, i, -1);
|
||||
String next = get(parts, i, 1);
|
||||
if (previous == null || next == null) {
|
||||
tokens.add(new Token(part, TokenTypeColors.ERROR));
|
||||
continue;
|
||||
}
|
||||
if (Operators.OPERATORS.contains(previous) || Operators.OPERATORS.contains(next)) {
|
||||
tokens.add(new Token(part, TokenTypeColors.ERROR));
|
||||
continue;
|
||||
}
|
||||
if ("{".equals(previous) || "}".equals(next)) {
|
||||
tokens.add(new Token(part, TokenTypeColors.ERROR));
|
||||
continue;
|
||||
}
|
||||
tokens.add(new Token(part, TokenTypeColors.OTHER));
|
||||
continue;
|
||||
}
|
||||
if (part.matches("[+\\-*/%^&|<>=!]+")) {
|
||||
tokens.add(new Token(part, TokenTypeColors.ERROR));
|
||||
continue;
|
||||
}
|
||||
tokens.add(new Token(part, TokenTypeColors.VARIABLE));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static String get(List<String> parts, int index, int direction) {
|
||||
for (int i = index + direction; i >= 0 && i < parts.size(); i += direction) {
|
||||
String part = parts.get(i);
|
||||
if (!part.isBlank()) return part;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<String> tokenize(String s) {
|
||||
List<String> tokens = new ArrayList<>();
|
||||
StringBuilder token = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '{' || c == '}' || c == ' ') {
|
||||
if (token.length() > 0) {
|
||||
tokens.add(token.toString());
|
||||
token = new StringBuilder();
|
||||
}
|
||||
tokens.add(c + "");
|
||||
continue;
|
||||
}
|
||||
StringBuilder op = new StringBuilder();
|
||||
for (int j = i; j < s.length(); j++) {
|
||||
char k = s.charAt(j);
|
||||
if (k == '+' || k == '-' || k == '*' || k == '/' || k == '%' || k == '^' || k == '&' || k == '|' || k == '>' || k == '<' || k == '=' || k == '!') {
|
||||
op.append(k);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (op.length() > 0) {
|
||||
if (token.length() > 0) {
|
||||
tokens.add(token.toString());
|
||||
token = new StringBuilder();
|
||||
}
|
||||
tokens.add(op.toString());
|
||||
i += op.length() - 1;
|
||||
continue;
|
||||
}
|
||||
token.append(c);
|
||||
}
|
||||
if (token.length() > 0) {
|
||||
tokens.add(token.toString());
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Headers.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Headers.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Headers {
|
||||
|
||||
private Headers() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static final Set<String> HEADERS = new HashSet<>();
|
||||
}
|
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Operators.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Operators.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Operators {
|
||||
|
||||
private Operators() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static final Set<String> OPERATORS = new HashSet<>();
|
||||
}
|
278
src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java
Normale Datei
278
src/main/java/de/zonlykroks/advancedscripts/lexer/ScriptColorizer.java
Normale Datei
@ -0,0 +1,278 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ScriptColorizer {
|
||||
|
||||
private ScriptColorizer() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static List<Token> colorize(int lineNumber, String line) {
|
||||
if (lineNumber == 0) {
|
||||
List<Token> tokens = colorizeHeader(line);
|
||||
if (tokens != null) return tokens;
|
||||
}
|
||||
|
||||
List<Token> tokens;
|
||||
tokens = colorizeComment(line);
|
||||
if (tokens != null) return tokens;
|
||||
tokens = colorizeJumpPoint(line);
|
||||
if (tokens != null) return tokens;
|
||||
return colorizeLine(line);
|
||||
}
|
||||
|
||||
private static List<Token> colorizeHeader(String line) {
|
||||
if (!line.startsWith("#!")) return null;
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
tokens.add(new Token("#!", TokenTypeColors.COMMENT));
|
||||
String s = line.substring(2);
|
||||
|
||||
for (String pattern : Headers.HEADERS) {
|
||||
if (s.matches(pattern)) {
|
||||
tokens.add(new Token(s, TokenTypeColors.OTHER));
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
tokens.add(new Token(s, TokenTypeColors.ERROR));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static List<Token> colorizeComment(String line) {
|
||||
if (!line.startsWith("#")) return null;
|
||||
return List.of(new Token(line, TokenTypeColors.COMMENT));
|
||||
}
|
||||
|
||||
private static List<Token> colorizeJumpPoint(String line) {
|
||||
if (!line.startsWith(".")) return null;
|
||||
return List.of(new Token(line, TokenTypeColors.JUMP_POINT));
|
||||
}
|
||||
|
||||
private static List<Token> colorizeLine(String line) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
|
||||
String command = line;
|
||||
if (line.indexOf(' ') != -1) {
|
||||
command = line.substring(0, line.indexOf(' '));
|
||||
}
|
||||
boolean repeatable = false;
|
||||
List<List<TokenType>> argumentTypes = null;
|
||||
if (Commands.COMMANDS.containsKey(command)) {
|
||||
Command c = Commands.COMMANDS.get(command);
|
||||
repeatable = c.repeatable;
|
||||
argumentTypes = c.arguments;
|
||||
tokens.add(new Token(command, TokenTypeColors.LITERAL));
|
||||
} else {
|
||||
repeatable = true;
|
||||
argumentTypes = new ArrayList<>();
|
||||
argumentTypes.add(List.of(TokenType.any));
|
||||
tokens.add(new Token(command, TokenTypeColors.OTHER));
|
||||
}
|
||||
if (command.equals(line)) return tokens;
|
||||
tokens.add(Token.SPACE);
|
||||
|
||||
String args = line.substring(command.length() + 1);
|
||||
tokens.addAll(colorizeArgs(args, repeatable, argumentTypes));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static List<Token> colorizeArgs(String args, boolean repeatable, List<List<TokenType>> argumentTypes) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
|
||||
for (List<TokenType> tokenTypes : argumentTypes) {
|
||||
List<Token> temp = new ArrayList<>();
|
||||
int index = 0;
|
||||
int argIndex = 0;
|
||||
try {
|
||||
while (argIndex < args.length()) {
|
||||
if (args.charAt(argIndex) == ' ') {
|
||||
argIndex++;
|
||||
temp.add(Token.SPACE);
|
||||
continue;
|
||||
}
|
||||
List<Token> current = parse(tokenTypes.get(index), args.substring(argIndex));
|
||||
if (current.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
temp.addAll(current);
|
||||
argIndex += current.stream().mapToInt(t -> t.text.length()).sum();
|
||||
index++;
|
||||
if (repeatable && index == tokenTypes.size()) {
|
||||
index--;
|
||||
}
|
||||
if (index == tokenTypes.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (argIndex != args.length()) {
|
||||
continue;
|
||||
}
|
||||
if (index != tokenTypes.size() - (repeatable ? 1 : 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!temp.isEmpty()) {
|
||||
tokens.addAll(temp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.isEmpty()) {
|
||||
tokens.add(new Token(args, TokenTypeColors.OTHER));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static List<Token> parse(TokenType type, String current) {
|
||||
return switch (type) {
|
||||
case any -> parseAny(current);
|
||||
case expression -> parseExpression(current);
|
||||
case jump_point -> parseJumpPoint(current);
|
||||
case variable -> parseVariable(current);
|
||||
case text_type -> parseText(current);
|
||||
case number_type -> parseNumber(current);
|
||||
case floating_number_type -> parseFloatingNumber(current);
|
||||
case boolean_type -> parseBoolean(current);
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Token> parseAny(String current) {
|
||||
List<Token> tokens = parseExpression(current);
|
||||
if (!tokens.isEmpty()) return tokens;
|
||||
tokens = parseFloatingNumber(current);
|
||||
if (!tokens.isEmpty()) return tokens;
|
||||
tokens = parseNumber(current);
|
||||
if (!tokens.isEmpty()) return tokens;
|
||||
tokens = parseBoolean(current);
|
||||
if (!tokens.isEmpty()) return tokens;
|
||||
return parseText(current);
|
||||
}
|
||||
|
||||
private static List<Token> parseExpression(String current) {
|
||||
if (!current.startsWith("{")) return new ArrayList<>();
|
||||
int depth = 0;
|
||||
int index = 0;
|
||||
do {
|
||||
if (current.charAt(index) == '{') {
|
||||
depth++;
|
||||
} else if (current.charAt(index) == '}') {
|
||||
depth--;
|
||||
}
|
||||
index++;
|
||||
} while (depth != 0 && index < current.length());
|
||||
if (depth != 0) return List.of(new Token(current, TokenTypeColors.ERROR));
|
||||
return ExpressionColorizer.colorize(current.substring(0, index));
|
||||
}
|
||||
|
||||
private static List<Token> parseJumpPoint(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
if (index == -1) {
|
||||
return List.of(new Token(current, TokenTypeColors.JUMP_POINT));
|
||||
} else {
|
||||
return List.of(new Token(current.substring(0, index), TokenTypeColors.JUMP_POINT));
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Token> parseVariable(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
if (index == -1) {
|
||||
return List.of(new Token(current, TokenTypeColors.VARIABLE));
|
||||
} else {
|
||||
return List.of(new Token(current.substring(0, index), TokenTypeColors.VARIABLE));
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Token> parseText(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
if (index != -1) {
|
||||
current = current.substring(0, index);
|
||||
}
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < current.length(); i++) {
|
||||
char c = current.charAt(i);
|
||||
if (c == '&' && i + 1 < current.length()) {
|
||||
char color = current.charAt(i + 1);
|
||||
if (color >= '0' && color <= '9' || color >= 'a' && color <= 'f' || color >= 'A' && color <= 'F') {
|
||||
if (sb.length() > 0) {
|
||||
tokens.add(new Token(sb.toString(), TokenTypeColors.TEXT));
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
i++;
|
||||
switch (color) {
|
||||
case '0' -> tokens.add(new Token("&0", 0xFF000000));
|
||||
case '1' -> tokens.add(new Token("&1", 0xFF0000AA));
|
||||
case '2' -> tokens.add(new Token("&2", 0xFF00AA00));
|
||||
case '3' -> tokens.add(new Token("&3", 0xFF00AAAA));
|
||||
case '4' -> tokens.add(new Token("&4", 0xFFAA0000));
|
||||
case '5' -> tokens.add(new Token("&5", 0xFFAA00AA));
|
||||
case '6' -> tokens.add(new Token("&6", 0xFFFFAA00));
|
||||
case '7' -> tokens.add(new Token("&7", 0xFFAAAAAA));
|
||||
case '8' -> tokens.add(new Token("&8", 0xFF555555));
|
||||
case '9' -> tokens.add(new Token("&9", 0xFF5555FF));
|
||||
case 'a', 'A' -> tokens.add(new Token("&a", 0xFF55FF55));
|
||||
case 'b', 'B' -> tokens.add(new Token("&b", 0xFF55FFFF));
|
||||
case 'c', 'C' -> tokens.add(new Token("&c", 0xFFFF5555));
|
||||
case 'd', 'D' -> tokens.add(new Token("&d", 0xFFFF55FF));
|
||||
case 'e', 'E' -> tokens.add(new Token("&e", 0xFFFFFF55));
|
||||
case 'f', 'F' -> tokens.add(new Token("&f", 0xFFFFFFFF));
|
||||
default -> tokens.add(new Token("&" + color, TokenTypeColors.TEXT));
|
||||
}
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
tokens.add(new Token(sb.toString(), TokenTypeColors.TEXT));
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private static List<Token> parseNumber(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
String number = current;
|
||||
if (index != -1) {
|
||||
number = current.substring(0, index);
|
||||
}
|
||||
try {
|
||||
Long.parseLong(number);
|
||||
return List.of(new Token(number, TokenTypeColors.NUMBER));
|
||||
} catch (NumberFormatException e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Token> parseFloatingNumber(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
String number = current;
|
||||
if (index != -1) {
|
||||
number = current.substring(0, index);
|
||||
}
|
||||
try {
|
||||
Double.parseDouble(number);
|
||||
return List.of(new Token(number, TokenTypeColors.NUMBER));
|
||||
} catch (NumberFormatException e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Token> parseBoolean(String current) {
|
||||
int index = current.indexOf(' ');
|
||||
String bool = current;
|
||||
if (index != -1) {
|
||||
bool = current.substring(0, index);
|
||||
}
|
||||
if ("true".equalsIgnoreCase(bool) || "false".equalsIgnoreCase(bool)) {
|
||||
return List.of(new Token(bool, TokenTypeColors.BOOLEAN));
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ScriptSyntaxPacketParser {
|
||||
|
||||
private ScriptSyntaxPacketParser() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
private static final TokenType[] TOKEN_TYPES = TokenType.values();
|
||||
|
||||
private static void reset() {
|
||||
Operators.OPERATORS.clear();
|
||||
Headers.HEADERS.clear();
|
||||
VariablePrefixes.RPEFIXES.clear();
|
||||
VariableSuffixes.SUFFIXES.clear();
|
||||
Commands.COMMANDS.clear();
|
||||
}
|
||||
|
||||
public static synchronized void parse(String scriptSyntax) {
|
||||
reset();
|
||||
|
||||
JsonObject jsonObject = JsonParser.parseString(scriptSyntax).getAsJsonObject();
|
||||
for (String key : jsonObject.keySet()) {
|
||||
JsonArray jsonElements = jsonObject.get(key).getAsJsonArray();
|
||||
if (key.startsWith("@")) {
|
||||
parseSpecial(key, jsonElements);
|
||||
} else {
|
||||
parseCommand(key, jsonElements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseCommand(String key, JsonArray value) {
|
||||
boolean repeating = value.get(0).getAsBoolean();
|
||||
List<List<TokenType>> validArgumentTypes = new ArrayList<>();
|
||||
for (int i = 1; i < value.size(); i++) {
|
||||
JsonArray parameters = value.get(i).getAsJsonArray();
|
||||
List<TokenType> parameterTypes = new ArrayList<>();
|
||||
for (JsonElement parameter : parameters) {
|
||||
parameterTypes.add(TOKEN_TYPES[parameter.getAsInt()]);
|
||||
}
|
||||
validArgumentTypes.add(parameterTypes);
|
||||
}
|
||||
Commands.COMMANDS.put(key, new Command(repeating, validArgumentTypes));
|
||||
}
|
||||
|
||||
private static void parseSpecial(String key, JsonArray value) {
|
||||
Set<String> set;
|
||||
switch (key) {
|
||||
case "@operators":
|
||||
set = Operators.OPERATORS;
|
||||
break;
|
||||
case "@headers":
|
||||
set = Headers.HEADERS;
|
||||
break;
|
||||
case "@prefixes":
|
||||
set = VariablePrefixes.RPEFIXES;
|
||||
break;
|
||||
case "@suffixes":
|
||||
set = VariableSuffixes.SUFFIXES;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
for (JsonElement element : value) {
|
||||
set.add(element.getAsString());
|
||||
}
|
||||
}
|
||||
}
|
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Token.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/Token.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.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;
|
||||
}
|
||||
}
|
13
src/main/java/de/zonlykroks/advancedscripts/lexer/TokenType.java
Normale Datei
13
src/main/java/de/zonlykroks/advancedscripts/lexer/TokenType.java
Normale Datei
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
public enum TokenType { // This is copied from the BauSystem2.0 sources.
|
||||
any, // This does not include jump_point and variable
|
||||
expression,
|
||||
jump_point,
|
||||
variable,
|
||||
|
||||
text_type,
|
||||
number_type,
|
||||
floating_number_type,
|
||||
boolean_type,
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package de.zonlykroks.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 LITERAL = 0xFF925F35;
|
||||
public static final int COMMENT = 0xFF656565;
|
||||
public static final int JUMP_POINT = 0xFFFFa500;
|
||||
|
||||
public static final int NUMBER = 0xFF61839F;
|
||||
public static final int BOOLEAN = 0xFF925F35;
|
||||
public static final int TEXT = 0xFF6F855D;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class VariablePrefixes {
|
||||
|
||||
private VariablePrefixes() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static final Set<String> RPEFIXES = new HashSet<>();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package de.zonlykroks.advancedscripts.lexer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class VariableSuffixes {
|
||||
|
||||
private VariableSuffixes() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static final Set<String> SUFFIXES = new HashSet<>();
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package de.zonlykroks.advancedscripts.mixin;
|
||||
|
||||
import de.zonlykroks.advancedscripts.lexer.ScriptSyntaxPacketParser;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
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;
|
||||
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public class ClientPlayNetworkHandlerMixin {
|
||||
|
||||
private static final Identifier CHANNEL = new Identifier("sw:script_syntax");
|
||||
|
||||
@Inject(method = "onCustomPayload", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/CustomPayloadS2CPacket;getData()Lnet/minecraft/network/PacketByteBuf;"), cancellable = true)
|
||||
public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
|
||||
if (CHANNEL.equals(packet.getChannel())) {
|
||||
PacketByteBuf buf = packet.getData();
|
||||
int readableBytes = buf.readableBytes();
|
||||
StringBuilder st = new StringBuilder();
|
||||
for (int i = 0; i < readableBytes; i++) {
|
||||
st.append((char) buf.readByte());
|
||||
}
|
||||
ScriptSyntaxPacketParser.parse(st.toString());
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package de.zonlykroks.advancedscripts.mixin;
|
||||
|
||||
import de.zonlykroks.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();
|
||||
}
|
||||
}
|
||||
}
|
616
src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java
Normale Datei
616
src/main/java/de/zonlykroks/advancedscripts/screen/ScriptEditScreen.java
Normale Datei
@ -0,0 +1,616 @@
|
||||
package de.zonlykroks.advancedscripts.screen;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import de.zonlykroks.advancedscripts.lexer.ScriptColorizer;
|
||||
import de.zonlykroks.advancedscripts.lexer.Token;
|
||||
import de.zonlykroks.advancedscripts.lexer.TokenTypeColors;
|
||||
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(DONE, this.width / 2 - 98 / 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 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) {
|
||||
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, lineNumberText + "", 25 + lineNumberLength - textRenderer.getWidth(lineNumberText + ""), 25 + lineNumber.getValue() * 9, 0xFFFFFF);
|
||||
lineNumberText++;
|
||||
|
||||
// Line text
|
||||
List<Token> tokens = ScriptColorizer.colorize(lineNumber.getValue(), 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) {
|
||||
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 257:
|
||||
case 335:
|
||||
selection(true);
|
||||
newLine();
|
||||
valid = false;
|
||||
break;
|
||||
case 259:
|
||||
if (selection(true) == null) backspace(selectionType);
|
||||
valid = false;
|
||||
break;
|
||||
case 261:
|
||||
if (selection(true) == null) delete(selectionType);
|
||||
valid = false;
|
||||
break;
|
||||
case 262:
|
||||
moveCursor(1, selectionType);
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
case 263:
|
||||
moveCursor(-1, selectionType);
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
case 264:
|
||||
moveDown();
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
case 265:
|
||||
moveUp();
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
case 268:
|
||||
cursorX = 0;
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
case 269:
|
||||
cursorX = lines.get(cursorY).length();
|
||||
valid = Screen.hasShiftDown();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
this.keyCode = -1;
|
||||
return super.keyReleased(keyCode, scanCode, modifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char chr, int modifiers) {
|
||||
if (super.charTyped(chr, modifiers)) {
|
||||
return true;
|
||||
}
|
||||
selection(true);
|
||||
boolean valid = insert(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);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,9 @@
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"KeyboardMixin"
|
||||
"KeyboardMixin",
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren