pl.kotcrab.jdialogue.parser.impl.JDOMDialogueParser.java Source code

Java tutorial

Introduction

Here is the source code for pl.kotcrab.jdialogue.parser.impl.JDOMDialogueParser.java

Source

/*******************************************************************************
 * Copyright 2014 Pawel Pastuszak
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.
 ******************************************************************************/

package pl.kotcrab.jdialogue.parser.impl;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import pl.kotcrab.jdialogue.loader.DialogueLoader;
import pl.kotcrab.jdialogue.parser.CallbackListener;
import pl.kotcrab.jdialogue.parser.ComponentType;
import pl.kotcrab.jdialogue.parser.DialogueParser;
import pl.kotcrab.jdialogue.parser.DialogueParserException;
import pl.kotcrab.jdialogue.parser.PCallback;
import pl.kotcrab.jdialogue.parser.PCharacter;
import pl.kotcrab.jdialogue.parser.Project;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.zip.GZIPInputStream;

public class JDOMDialogueParser extends DialogueParser {
    private Random random = new Random();

    private ArrayList<CallbackListener> listeners = new ArrayList<>();

    private Project project;
    private String projectPath;

    private List<Element> elementList;
    private Element currentElement;

    private ComponentType currentComponentType;
    private int target = -1;

    private PCharacter currentCharacterData;
    private boolean lastCallbackCheckResult;

    private String[] msgText;
    private int currentMsg;

    public JDOMDialogueParser(DialogueLoader projectFile, int maxChars) {
        super(projectFile, maxChars);

        project = loadProject(projectFile);
        projectPath = projectFile.getFile().getParent() + File.separator;
    }

    @Override
    public void startSequence(String name) {
        try {
            SAXBuilder builder = new SAXBuilder();
            Document document;

            if (project.isGzipExport())
                document = builder
                        .build(new GZIPInputStream(new FileInputStream(new File(projectPath + name + ".xml"))));
            else
                document = builder.build(new File(projectPath + name + ".xml"));

            Element rootNode = document.getRootElement();

            elementList = rootNode.getChildren();

            Element startNode = rootNode.getChildren("dStart").get(0);
            target = Integer.valueOf(startNode.getChildText("target0"));
        } catch (JDOMException | IOException e) {
            if (e.getMessage().contains("Invalid byte 1 of 1-byte UTF-8 sequence."))
                throw new DialogueParserException("Error decoding file.");

            e.printStackTrace();
        }
    }

    @Override
    public ComponentType processNextComponent() {
        if (target == -1)
            throw new DialogueParserException(
                    "target == -1. Did you call startSequence(String sequenceName) before calling processNextComponent()?");

        currentElement = elementList.get(target);

        String name = currentElement.getName();

        if (name.equals("dEnd"))
            currentComponentType = ComponentType.END;
        if (name.equals("dChoice")) {
            currentComponentType = ComponentType.CHOICE;
            msgText = new String[1];
            msgText[0] = currentElement.getChildText("text");

        }
        if (name.equals("dRandom"))
            currentComponentType = ComponentType.RANDOM;
        if (name.equals("dRelay"))
            currentComponentType = ComponentType.RELAY;

        if (name.equals("dText")) {
            int id = Integer.parseInt(currentElement.getChildText("character"));
            currentCharacterData = project.getCharacterList().get(project.getCharacterMap().get(id));

            if (maxChars > 0)
                msgText = splitIntoLines(currentElement.getChildText("text"));
            else {
                msgText = new String[1];
                msgText[0] = currentElement.getChildText("text");
            }
            currentMsg = 0;

            currentComponentType = ComponentType.TEXT;

        }
        if (name.startsWith("dCallback")) {
            int id = Integer.parseInt(currentElement.getChildText("callback"));
            String callbackText = project.getCallbackList().get(project.getCallbackMap().get(id)).getName();

            if (name.equals("dCallback")) {
                for (CallbackListener lis : listeners)
                    lis.handleCallback(callbackText);

                currentComponentType = ComponentType.CALLBACK;
            }

            if (name.equals("dCallbackCheck")) {
                for (CallbackListener lis : listeners)
                    lastCallbackCheckResult = lis.handleCallbackCheck(callbackText);

                currentComponentType = ComponentType.CBCHECK;
            }
        }

        return currentComponentType;
    }

    @Override
    public void moveToNextComponent(int target) {
        if (currentComponentType == ComponentType.RANDOM) {
            List<Element> randomList = currentElement.getChildren();
            this.target = Integer.parseInt(randomList.get(1 + random.nextInt(randomList.size() - 1)).getText());

            return;
        }

        if (currentComponentType != ComponentType.END)
            this.target = Integer.valueOf(currentElement.getChildText("target" + target));
    }

    @Override
    public void moveToNextComponent() {
        if (currentComponentType == ComponentType.CBCHECK) {
            if (lastCallbackCheckResult == true)
                moveToNextComponent(0);
            else
                moveToNextComponent(1);

            return;
        }

        moveToNextComponent(0);
    }

    @Override
    public String getMsg() {
        if (maxChars > 0 && currentMsg < msgText.length) {
            String text = msgText[currentMsg];
            currentMsg++;
            return text;
        } else
            return msgText[0];
    }

    @Override
    public boolean isCurrentMsgFinished() {
        return currentMsg == msgText.length;
    }

    @Override
    public int getId() {
        return Integer.parseInt(currentElement.getChildText("id"));
    }

    @Override
    public String[] getChoiceData() {
        List<Element> choiceList = currentElement.getChildren("choiceData").get(0).getChildren("string");
        String[] choiceData = new String[choiceList.size()];

        for (int i = 0; i < choiceData.length; i++)
            choiceData[i] = choiceList.get(i).getText();

        return choiceData;
    }

    @Override
    public PCharacter getCharacterData() {
        return currentCharacterData;
    }

    @Override
    public void addCallbackListener(CallbackListener listener) {
        listeners.add(listener);
    }

    @Override
    public boolean removeCallbackListener(CallbackListener listener) {
        return listeners.remove(listener);
    }

    private String[] splitIntoLines(String input) {
        StringTokenizer tok = new StringTokenizer(input, " ");
        StringBuilder output = new StringBuilder(input.length());
        int lineLen = 0;
        while (tok.hasMoreTokens()) {
            String word = tok.nextToken();

            while (word.length() > maxChars) {
                output.append(word.substring(0, maxChars - lineLen) + "\n");
                word = word.substring(maxChars - lineLen);
                lineLen = 0;
            }

            if (lineLen + word.length() > maxChars) {
                output.append("\n");
                lineLen = 0;
            }
            output.append(word + " ");

            lineLen += word.length() + 1;
        }

        return output.toString().split("\n");
    }

    // =====================================LOADING PROJECT========================================

    private Project loadProject(DialogueLoader projectFile) {
        String name = "";
        boolean gzipExport = false;
        ArrayList<PCharacter> characterList = new ArrayList<>();
        HashMap<Integer, Integer> characterMap = new HashMap<>();
        ArrayList<PCallback> callbackList = new ArrayList<>();
        HashMap<Integer, Integer> callbackMap = new HashMap<>();

        try {
            SAXBuilder builder = new SAXBuilder();
            Document document = builder.build(projectFile.getFile());
            Element rootNode = document.getRootElement();

            name = rootNode.getChildText("name");
            gzipExport = Boolean.valueOf(rootNode.getChildText("gzipExport"));

            List<Element> characterElementList = rootNode.getChild("characterList").getChildren();
            for (Element el : characterElementList)
                characterList.add(loadCharacter(el));

            List<Element> callbackElementList = rootNode.getChild("callbackList").getChildren();
            for (Element el : callbackElementList)
                callbackList.add(loadCallback(el));

            List<Element> characterHaspMapElementList = rootNode.getChild("characterMap").getChildren();
            for (Element el : characterHaspMapElementList)
                characterMap.put(Integer.valueOf(el.getChildren().get(0).getText()),
                        Integer.valueOf(el.getChildren().get(1).getText()));

            List<Element> callbackHaspMapElementList = rootNode.getChild("callbackMap").getChildren();
            for (Element el : callbackHaspMapElementList)
                callbackMap.put(Integer.valueOf(el.getChildren().get(0).getText()),
                        Integer.valueOf(el.getChildren().get(1).getText()));

        } catch (JDOMException | IOException e) {
            throw new DialogueParserException("Chould not load project! Is your project.xml file correct?");
        }

        return new Project(name, gzipExport, characterList, characterMap, callbackList, callbackMap);
    }

    private PCallback loadCallback(Element callbackElement) {
        int id = Integer.valueOf(callbackElement.getChildText("id"));
        String name = callbackElement.getChildText("name");

        return new PCallback(id, name);
    }

    private PCharacter loadCharacter(Element characterElement) {
        int id = Integer.valueOf(characterElement.getChildText("id"));
        String name = characterElement.getChildText("name");
        String textureName = characterElement.getChildText("textureName");

        return new PCharacter(id, name, textureName);
    }
}