2015-09-10 16:22:07 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
|
|
|
|
* (the "License"); you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
|
|
|
|
* Unless required by applicable law or agreed to in writing, software distributed under
|
|
|
|
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
|
|
|
|
* ANY KIND, either express or implied. See the License for the specific language
|
|
|
|
* governing permissions and limitations under the License.
|
|
|
|
*/
|
2014-03-25 05:01:01 +00:00
|
|
|
package org.badvision.outlaweditor;
|
|
|
|
|
2014-04-04 04:19:59 +00:00
|
|
|
import java.io.ByteArrayInputStream;
|
2014-03-25 05:01:01 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.StringWriter;
|
2015-06-22 07:14:12 +00:00
|
|
|
import java.util.ArrayList;
|
2015-06-02 01:42:52 +00:00
|
|
|
import java.util.List;
|
2015-09-12 23:40:08 +00:00
|
|
|
import java.util.Set;
|
2016-07-04 17:37:39 +00:00
|
|
|
import java.util.function.Consumer;
|
2014-03-25 05:01:01 +00:00
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
2017-07-03 15:41:36 +00:00
|
|
|
import java.util.regex.Pattern;
|
2015-06-22 06:40:07 +00:00
|
|
|
import java.util.stream.Collectors;
|
2015-06-23 22:07:19 +00:00
|
|
|
import java.util.stream.Stream;
|
2023-09-09 01:59:23 +00:00
|
|
|
|
2014-04-13 05:19:50 +00:00
|
|
|
import javax.xml.namespace.QName;
|
2014-04-04 04:19:59 +00:00
|
|
|
import javax.xml.parsers.DocumentBuilder;
|
|
|
|
import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
import javax.xml.parsers.ParserConfigurationException;
|
2023-09-09 01:59:23 +00:00
|
|
|
|
2016-07-03 06:00:44 +00:00
|
|
|
import org.badvision.outlaweditor.api.ApplicationState;
|
2016-07-04 17:37:39 +00:00
|
|
|
import static org.badvision.outlaweditor.data.DataUtilities.extract;
|
|
|
|
import static org.badvision.outlaweditor.data.DataUtilities.extractFirst;
|
2016-07-05 07:53:49 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Arg;
|
2014-03-25 05:01:01 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Block;
|
2015-06-29 04:19:29 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Global;
|
2015-06-23 06:37:39 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Mutation;
|
2015-06-23 21:31:37 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Scope;
|
2014-03-25 05:01:01 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Script;
|
2016-07-04 17:37:39 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.Statement;
|
2015-06-23 21:31:37 +00:00
|
|
|
import org.badvision.outlaweditor.data.xml.UserType;
|
|
|
|
import org.badvision.outlaweditor.data.xml.Variable;
|
2015-09-12 23:40:08 +00:00
|
|
|
import org.badvision.outlaweditor.spelling.SpellChecker;
|
|
|
|
import org.badvision.outlaweditor.spelling.SpellResponse;
|
|
|
|
import org.badvision.outlaweditor.spelling.Suggestion;
|
2014-05-25 05:22:26 +00:00
|
|
|
import org.badvision.outlaweditor.ui.ApplicationUIController;
|
|
|
|
import org.badvision.outlaweditor.ui.MythosScriptEditorController;
|
2014-04-04 04:19:59 +00:00
|
|
|
import org.w3c.dom.Document;
|
|
|
|
import org.xml.sax.SAXException;
|
2014-03-25 05:01:01 +00:00
|
|
|
|
2023-09-09 01:59:23 +00:00
|
|
|
import jakarta.xml.bind.JAXBContext;
|
|
|
|
import jakarta.xml.bind.JAXBElement;
|
|
|
|
import jakarta.xml.bind.JAXBException;
|
|
|
|
import jakarta.xml.bind.Unmarshaller;
|
|
|
|
import javafx.fxml.FXMLLoader;
|
|
|
|
import javafx.scene.Scene;
|
|
|
|
import javafx.scene.layout.AnchorPane;
|
|
|
|
import javafx.stage.Stage;
|
|
|
|
import javafx.stage.WindowEvent;
|
|
|
|
|
2014-03-25 05:01:01 +00:00
|
|
|
/**
|
|
|
|
* Mythos Scripting Editor
|
2014-04-04 04:19:59 +00:00
|
|
|
*
|
2014-03-25 05:01:01 +00:00
|
|
|
* @author blurry
|
|
|
|
*/
|
|
|
|
public class MythosEditor {
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2015-06-23 21:31:37 +00:00
|
|
|
Scope scope;
|
2014-03-25 05:01:01 +00:00
|
|
|
Script script;
|
|
|
|
Stage primaryStage;
|
|
|
|
MythosScriptEditorController controller;
|
2014-04-04 04:19:59 +00:00
|
|
|
public static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
|
2015-09-12 23:40:08 +00:00
|
|
|
SpellChecker spellChecker;
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2015-06-23 21:31:37 +00:00
|
|
|
public MythosEditor(Script theScript, Scope theScope) {
|
2014-03-25 05:01:01 +00:00
|
|
|
script = theScript;
|
2015-06-23 21:31:37 +00:00
|
|
|
scope = theScope;
|
2015-09-12 23:40:08 +00:00
|
|
|
spellChecker = new SpellChecker();
|
2016-07-05 07:53:49 +00:00
|
|
|
fixMutators(script.getBlock());
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2014-03-25 05:01:01 +00:00
|
|
|
public void show() {
|
|
|
|
primaryStage = new Stage();
|
|
|
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/MythosScriptEditor.fxml"));
|
|
|
|
try {
|
|
|
|
AnchorPane node = (AnchorPane) fxmlLoader.load();
|
|
|
|
controller = fxmlLoader.getController();
|
|
|
|
controller.setEditor(this);
|
|
|
|
Scene s = new Scene(node);
|
|
|
|
primaryStage.setScene(s);
|
|
|
|
} catch (IOException exception) {
|
|
|
|
throw new RuntimeException(exception);
|
|
|
|
}
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2014-09-28 06:54:49 +00:00
|
|
|
primaryStage.setOnCloseRequest((final WindowEvent t) -> {
|
|
|
|
t.consume();
|
2014-03-25 05:01:01 +00:00
|
|
|
});
|
|
|
|
primaryStage.show();
|
2014-04-13 03:36:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void close() {
|
2014-09-28 06:54:49 +00:00
|
|
|
javafx.application.Platform.runLater(() -> {
|
|
|
|
primaryStage.getScene().getRoot().setDisable(true);
|
|
|
|
primaryStage.close();
|
2014-04-04 04:19:59 +00:00
|
|
|
});
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2014-03-25 05:01:01 +00:00
|
|
|
public void applyChanges() {
|
|
|
|
try {
|
2017-07-03 15:41:36 +00:00
|
|
|
String xml = controller.getScriptXml()
|
|
|
|
.replaceFirst(Pattern.quote("<block"), "<block xmlns=\"outlaw\"");
|
2014-04-04 04:19:59 +00:00
|
|
|
JAXBContext context = JAXBContext.newInstance("org.badvision.outlaweditor.data.xml");
|
|
|
|
Unmarshaller unmarshaller = context.createUnmarshaller();
|
|
|
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
|
|
|
dbf.setNamespaceAware(true);
|
|
|
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
|
|
|
Document doc = db.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
|
|
|
|
JAXBElement<Block> b = unmarshaller.unmarshal(doc, Block.class);
|
|
|
|
script.setBlock(b.getValue());
|
|
|
|
} catch (JAXBException | ParserConfigurationException | SAXException | IOException ex) {
|
2014-03-25 05:01:01 +00:00
|
|
|
Logger.getLogger(MythosEditor.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
|
|
|
}
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2014-04-13 03:36:25 +00:00
|
|
|
public String generateLoadScript() {
|
2014-03-25 05:01:01 +00:00
|
|
|
if (script == null || script.getBlock() == null) {
|
2014-04-13 03:36:25 +00:00
|
|
|
return generateLoadScript(getDefaultBlockMarkup());
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
JAXBContext context = JAXBContext.newInstance(Block.class);
|
|
|
|
StringWriter buffer = new StringWriter();
|
2014-05-25 05:29:58 +00:00
|
|
|
QName qName = new QName("outlaw", "block");
|
|
|
|
JAXBElement<Block> root = new JAXBElement<>(qName, Block.class, script.getBlock());
|
2014-04-13 05:19:50 +00:00
|
|
|
context.createMarshaller().marshal(root, buffer);
|
2014-04-13 03:36:25 +00:00
|
|
|
String xml = buffer.toString();
|
2014-07-06 21:49:13 +00:00
|
|
|
xml = xml.replaceAll("'", "'");
|
2014-05-25 05:29:58 +00:00
|
|
|
xml = xml.replace("?>", "?><xml>");
|
2014-04-13 05:19:50 +00:00
|
|
|
xml += "</xml>";
|
2014-04-13 03:36:25 +00:00
|
|
|
return generateLoadScript(xml);
|
|
|
|
} catch (JAXBException ex) {
|
|
|
|
Logger.getLogger(MythosEditor.class.getName()).log(Level.SEVERE, null, ex);
|
|
|
|
}
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
2014-04-13 03:36:25 +00:00
|
|
|
return null;
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
2014-04-04 04:19:59 +00:00
|
|
|
|
2014-04-13 03:36:25 +00:00
|
|
|
public String generateLoadScript(String xml) {
|
2014-04-04 04:19:59 +00:00
|
|
|
xml = xml.replaceAll("'", "\\'");
|
|
|
|
xml = xml.replaceAll("\n", "");
|
2015-06-02 01:42:52 +00:00
|
|
|
String loadScript = "Mythos.initCustomDefinitions();";
|
|
|
|
loadScript += "Mythos.setScriptXml('" + xml + "');";
|
2014-04-13 03:36:25 +00:00
|
|
|
return loadScript;
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
|
|
|
|
2014-04-13 03:36:25 +00:00
|
|
|
private String getDefaultBlockMarkup() {
|
2014-05-25 05:29:58 +00:00
|
|
|
return XML_HEADER + "<xml><block type=\"procedures_defreturn\" id=\"1\" inline=\"false\" x=\"5\" y=\"5\"><mutation></mutation><field name=\"NAME\">NewScript</field></block></xml>";
|
2014-04-13 03:36:25 +00:00
|
|
|
}
|
2014-05-25 05:29:58 +00:00
|
|
|
|
2014-04-13 03:36:25 +00:00
|
|
|
// Called when the name of the root block is changed in the JS editor
|
|
|
|
public void setFunctionName(String name) {
|
2014-04-13 05:19:50 +00:00
|
|
|
if (script == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
script.setName(name);
|
2014-05-25 05:22:26 +00:00
|
|
|
ApplicationUIController.getController().redrawScripts();
|
2014-03-25 05:01:01 +00:00
|
|
|
}
|
2015-06-22 06:40:07 +00:00
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
public List<UserType> getUserTypes() {
|
2015-06-29 04:19:29 +00:00
|
|
|
Global global = (Global) getGlobalScope();
|
|
|
|
if (global.getUserTypes() == null) {
|
2015-06-23 22:07:19 +00:00
|
|
|
return new ArrayList<>();
|
|
|
|
} else {
|
2015-06-29 04:19:29 +00:00
|
|
|
return global.getUserTypes().getUserType();
|
2015-06-23 22:07:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-23 06:37:39 +00:00
|
|
|
public List<Script> getGlobalFunctions() {
|
2015-06-29 04:19:29 +00:00
|
|
|
return getFunctions(getGlobalScope());
|
2015-06-23 22:07:19 +00:00
|
|
|
}
|
2015-09-12 23:40:08 +00:00
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
public List<Script> getLocalFunctions() {
|
|
|
|
return getFunctions(scope);
|
|
|
|
}
|
2015-09-12 23:40:08 +00:00
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
private List<Script> getFunctions(Scope scriptScope) {
|
|
|
|
if (scriptScope.getScripts() == null) {
|
2015-06-22 07:14:12 +00:00
|
|
|
return new ArrayList<>();
|
2015-06-22 06:40:07 +00:00
|
|
|
} else {
|
2015-06-23 22:07:19 +00:00
|
|
|
List<Script> scripts = scriptScope.getScripts().getScript();
|
2016-07-05 07:53:49 +00:00
|
|
|
List<Script> filteredList = scripts.stream()
|
|
|
|
.filter(s -> s.getName() != null)
|
|
|
|
.collect(Collectors.toList());
|
2015-06-22 06:40:07 +00:00
|
|
|
return filteredList;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
public List<Variable> getGlobalVariables() {
|
2015-06-29 04:19:29 +00:00
|
|
|
return getVariables(getGlobalScope());
|
2015-06-22 06:40:07 +00:00
|
|
|
}
|
|
|
|
|
2015-06-29 04:19:29 +00:00
|
|
|
public static Scope getGlobalScope() {
|
2016-07-03 06:00:44 +00:00
|
|
|
return ApplicationState.getInstance().getGameData().getGlobal();
|
2015-06-29 04:19:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isGlobalScope() {
|
|
|
|
return scope.equals(getGlobalScope());
|
|
|
|
}
|
2015-09-12 23:40:08 +00:00
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
public List<Variable> getLocalVariables() {
|
|
|
|
return getVariables(scope);
|
|
|
|
}
|
2015-09-12 23:40:08 +00:00
|
|
|
|
2015-06-23 22:07:19 +00:00
|
|
|
private List<Variable> getVariables(Scope scriptScope) {
|
|
|
|
if (scriptScope.getVariables() == null) {
|
2015-06-22 07:14:12 +00:00
|
|
|
return new ArrayList<>();
|
2015-06-22 06:40:07 +00:00
|
|
|
} else {
|
2015-06-23 22:07:19 +00:00
|
|
|
return scriptScope.getVariables().getVariable();
|
2015-09-12 23:40:08 +00:00
|
|
|
}
|
2015-06-22 06:40:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<Variable> getVariablesByType(String type) {
|
2015-06-29 04:19:29 +00:00
|
|
|
Stream<Variable> allGlobals = Stream.empty();
|
|
|
|
if (!isGlobalScope()) {
|
|
|
|
allGlobals = getGlobalVariables().stream();
|
|
|
|
}
|
2015-06-23 22:07:19 +00:00
|
|
|
Stream<Variable> allLocals = getLocalVariables().stream();
|
2016-07-05 07:53:49 +00:00
|
|
|
return Stream.concat(allGlobals, allLocals)
|
|
|
|
.filter((v) -> v.getType().equals(type))
|
|
|
|
.collect(Collectors.toList());
|
2015-06-22 06:40:07 +00:00
|
|
|
}
|
2015-06-23 06:37:39 +00:00
|
|
|
|
|
|
|
public List<String> getParametersForScript(Script script) {
|
|
|
|
List<String> allArgs = new ArrayList();
|
2016-07-04 17:37:39 +00:00
|
|
|
if (script.getBlock() != null) {
|
2016-07-05 07:53:49 +00:00
|
|
|
extractFirst(script.getBlock(), Mutation.class)
|
|
|
|
.ifPresent((m) -> m.getArg().stream().map(Arg::getName).forEach(allArgs::add));
|
2015-06-23 22:07:19 +00:00
|
|
|
}
|
2015-06-23 06:37:39 +00:00
|
|
|
return allArgs;
|
|
|
|
}
|
|
|
|
|
2015-09-12 23:40:08 +00:00
|
|
|
public String checkSpelling(String value) {
|
|
|
|
SpellResponse result = spellChecker.check(value);
|
|
|
|
if (result.getErrors() == 0) {
|
|
|
|
return null;
|
|
|
|
} else {
|
|
|
|
StringBuilder message = new StringBuilder();
|
|
|
|
result.getCorrections().forEach((SpellResponse.Source source, Set<Suggestion> suggestions) -> {
|
|
|
|
message
|
|
|
|
.append(source.word)
|
2015-09-13 04:22:15 +00:00
|
|
|
.append(": ")
|
|
|
|
.append(suggestions.stream().map(Suggestion::getWord).limit(5).collect(Collectors.joining(",")))
|
2015-09-12 23:40:08 +00:00
|
|
|
.append("\n");
|
|
|
|
});
|
|
|
|
return message.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-22 06:40:07 +00:00
|
|
|
public void log(String message) {
|
2015-09-12 23:40:08 +00:00
|
|
|
Logger.getLogger(getClass().getName()).warning(message);
|
2015-06-22 06:40:07 +00:00
|
|
|
System.out.println(message);
|
2015-06-02 01:42:52 +00:00
|
|
|
}
|
2016-07-04 17:37:39 +00:00
|
|
|
|
|
|
|
public static enum MutationType {
|
|
|
|
controls_if(MythosEditor::fixIfStatement);
|
2016-07-05 07:53:49 +00:00
|
|
|
|
2016-07-04 17:37:39 +00:00
|
|
|
Consumer<Block> rebuildMutation;
|
2016-07-05 07:53:49 +00:00
|
|
|
|
2016-07-04 17:37:39 +00:00
|
|
|
MutationType(Consumer<Block> rebuilder) {
|
|
|
|
rebuildMutation = rebuilder;
|
2016-07-05 07:53:49 +00:00
|
|
|
}
|
2016-07-04 17:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void fixMutators(Block block) {
|
2016-07-05 07:53:49 +00:00
|
|
|
extractFirst(block, Mutation.class).ifPresent((mutation) -> {
|
2016-07-04 17:37:39 +00:00
|
|
|
if (mutation.getOtherAttributes().isEmpty()) {
|
|
|
|
try {
|
|
|
|
MutationType type = MutationType.valueOf(block.getType());
|
|
|
|
type.rebuildMutation.accept(block);
|
|
|
|
} catch (IllegalArgumentException ex) {
|
|
|
|
// No big deal, it just doesn't have a mutation we know how to handle
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-07-05 07:53:49 +00:00
|
|
|
extract(block, Statement.class).map(Statement::getBlock).flatMap(List::stream).forEach(this::fixMutators);
|
|
|
|
if (block != null && block.getNext() != null && block.getNext().getBlock() != null) {
|
2016-07-04 17:37:39 +00:00
|
|
|
fixMutators(block.getNext().getBlock());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void fixIfStatement(Block block) {
|
|
|
|
Mutation mutation = extractFirst(block, Mutation.class).get();
|
2016-07-05 07:53:49 +00:00
|
|
|
long doCount = extract(block, Statement.class).filter((s) -> s.getName().startsWith("DO")).collect(Collectors.counting());
|
|
|
|
long elseCount = extract(block, Statement.class).filter((s) -> s.getName().startsWith("ELSE")).collect(Collectors.counting());
|
2016-07-04 17:37:39 +00:00
|
|
|
if (doCount > 1) {
|
|
|
|
mutation.getOtherAttributes().put(new QName("elseif"), String.valueOf(doCount - 1));
|
|
|
|
}
|
|
|
|
if (elseCount > 0) {
|
|
|
|
mutation.getOtherAttributes().put(new QName("else"), String.valueOf(elseCount));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-23 06:37:39 +00:00
|
|
|
}
|