Package com.isteinvids.untrusted.level

Source Code of com.isteinvids.untrusted.level.LevelManager$Event

package com.isteinvids.untrusted.level;

import com.isteinvids.untrusted.LevelRenderPanel;
import com.isteinvids.untrusted.UntrustedLua;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import static java.lang.String.valueOf;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.JOptionPane;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
import org.luaj.vm2.lib.jse.JsePlatform;

/**
*
* @author EmirRhouni
*/
public final class LevelManager {

    public static final String[] levels = new String[]{
        "level_0",
        "level_1",
        "level_2",
        "level_3"
    };
    //If there's any of these words in the editable area, the script won't run
    public static final String[] blacklistWords = new String[]{
        "validateAtLeastXObjects", "validateExactlyXManyObjects"
    };
    private final Globals globals;
    private final int width = 32, height = 32;
    public int backgroundColour = 0x111111;
    public Player player = new Player(new Position(0, 0));
    public Map<String, Tile> blockMapping = new ConcurrentHashMap();
    public Map<Position, Integer> squareColours = new ConcurrentHashMap();
    public Map<Position, String> tiles = new ConcurrentHashMap();
    public Map<String, Entity> entities = new ConcurrentHashMap();
    public List<String> playerInventory = new CopyOnWriteArrayList<String>();
    public String[] prevPlayerInventory = new String[]{};
    public Map<String, Item> itemMapping = new ConcurrentHashMap();
    //evemts. ex: tickevent, playerontile
    public Map<Event, String> events = new ConcurrentHashMap();
    public String lastSuccessfulScript;
    public String originalScript;
    public int levelIndex = 0;
    public String status = "";
    public String errorText = "";
    private boolean playerCodeRunning = false;
    private boolean input = true;
    public Runnable phoneCallback;

    public LevelManager() {
        this.globals = JsePlatform.standardGlobals();
        this.globals.get("math").set("rand", new TwoArgFunction() {

            @Override
            public LuaValue call(LuaValue arg1, LuaValue arg2) {
                int min = arg1.toint();
                int max = arg2.toint();
                Random rand = new Random();
                int randomNum = rand.nextInt((max - min) + 1) + min;
                return LuaValue.valueOf(randomNum);
            }
        });
        this.globals.get("string").set("char", new OneArgFunction() {

            @Override
            public LuaValue call(LuaValue arg1) {
                int charint = arg1.toint();
                return LuaValue.valueOf(Character.toString((char) charint));
            }
        });
//        UntrustedLua.showComputerPane(false);

        prevPlayerInventory = new String[]{"computer"};
        levelIndex++;//for testing purposes
        loadLevel();
    }

    public void addEntityEvent(String event, String entity, Runnable runn) {
        events.put(new EntityEvent(entity, runn), event);
    }

    public void addTilePropertyEvent(String event, String tile, Runnable runn) {
        events.put(new TileEvent(tile, runn), event);
    }

    /**
     * TickEvent, PlayerOnTileEvent
     *
     * @param event
     */
    public void runEntityEvent(String event) {
        for (Map.Entry<Event, String> ent : events.entrySet()) {
            if (ent.getKey().getClass() == EntityEvent.class) {
                if (ent.getValue().equals(event)) {
                    ent.getKey().run();
                }
            }
        }
    }

    public boolean isPlayerCodeRunning() {
        return playerCodeRunning;
    }

    public void runTileEvent(String tile, String event) {
        for (Map.Entry<Event, String> ent : events.entrySet()) {
            if (ent.getKey().getClass() == TileEvent.class) {
                if (((TileEvent) ent.getKey()).tileName.equals(tile)) {
                    if (ent.getValue().equals(event)) {
                        ent.getKey().run();
                    }
                }
            }
        }
    }

    public void loadLevel() {
        lastSuccessfulScript = originalScript = loadLevelFile(levels[levelIndex]);
        UntrustedLua.textArea.setText(originalScript);
        UntrustedLua.textArea.setCaretPosition(0);
        initLevelProperties();
        runScript(originalScript, true);
    }

    private String loadLevelFile(String level) {
        try {
            String res = "/levels/" + level + ".lua";
            String ret = "";
            String line;
            InputStream levelStream = UntrustedLua.class.getResourceAsStream(res);
            if (levelStream == null) {
                return "";
            }
            BufferedReader br = new BufferedReader(new InputStreamReader(levelStream));
            while ((line = br.readLine()) != null) {
                ret += line + "\n";
            }
            br.close();
            return ret;
        } catch (IOException ex) {
        }
        return "";
    }

    public void setInput(boolean input) {
        this.input = input;
    }

    public Entity createEntity(String name, Entity entity) {
        if (!entities.containsKey(name)) {
            entities.put(name, entity);
            return entity;
        }
        return null;
    }

    public Entity getEntity(String name) {
        return entities.get(name);
    }

    public void resetLevelProperties() {
        input = true;
        status = "";
        errorText = "";
        phoneCallback = null;
        playerInventory.clear();
        playerInventory.addAll(Arrays.asList(prevPlayerInventory));
        itemMapping.clear();
        squareColours.clear();
        blockMapping.clear();
        entities.clear();
        tiles.clear();
        events.clear();
        backgroundColour = 0x111111;
        player = null;
    }

    private void initLevelProperties() {
        resetLevelProperties();

        blockMapping.put("air", new Tile(' ', 0x000000, false));
        blockMapping.put("block", new Tile('#', 0xFFFFFF, true));
        blockMapping.put("exit", new Tile('k', 0xFFFF00, false));

        addItemMapping("computer", new Item('\u2318', 0xFFFFFF));
        addItemMapping("phone", new Item('\u260E', 0xFFFFFF));

//        if (levelIndex != 0) {
//            addItemToInventory("computer");
//        }
        UntrustedLua.showComputerPane(playerInventory.contains("computer"));

        addTilePropertyEvent("onTileCollision", "exit", new Runnable() {
            @Override
            public void run() {
                LuaValue exitRet = callScriptFunc(LuaMain.functions.EXIT);
                if (exitRet.isboolean() && exitRet.toboolean()) {
                    prevPlayerInventory = playerInventory.toArray(new String[0]);
                    levelIndex++;
                    loadLevel();
                }
            }
        });

        for (int i = 0; i <= getWidth(); i++) {
            for (int j = 0; j <= getHeight(); j++) {
                setTile(i, j, "air");
            }
        }
    }
    //TODO: validate method

    public boolean isTileAlsoAnItem(String name) {
        if (blockMapping.containsKey(name) && playerInventory.contains(name)) {
            return true;
        }
        return false;
    }

    public void addItemMapping(final String name, final Item item) {
        if (!itemMapping.containsKey(name)) {
            itemMapping.put(name, item);
        }
        if (!blockMapping.containsKey(name)) {
            blockMapping.put(name, new Tile(item.symbol, item.colour, false));
        }
        addTilePropertyEvent("onTileCollision", name, new Runnable() {
            @Override
            public void run() {
                if (playerInventory.contains(name)) {
                    setLevelStatus("You already have " + name + "!");
                    return;
                }
                addItemToInventory(name);
//                playerInventory.put(status, null)
            }
        });
    }

    public void addItemToInventory(String name) {
        if (itemMapping.containsKey(name)) {
            if (!playerInventory.contains(name)) {
                playerInventory.add(name);
                if (name.equals("computer")) {
                    UntrustedLua.showComputerPane(true);
                }
            }
        }
    }

    public void removeItemFromInventory(String name) {
        if (playerInventory.contains(name)) {
            playerInventory.remove(name);
        }
        if (name.equals("computer")) {
            UntrustedLua.showComputerPane(false);
        }
    }

    private boolean scriptContainsBadWord(String script) {
        boolean insideEditable = false;
        for (String ln : script.split("\n")) {
            if (ln.contains(UntrustedLua.END)) {
                insideEditable = false;
            }
            if (ln.contains(UntrustedLua.START)) {
                insideEditable = true;
            }
            if (insideEditable) {
                for (String badWord : blacklistWords) {
                    if (ln.contains(badWord)) {
                        System.out.println(ln);
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private String[] getAllBadWords(String script) {
        List<String> badStrings = new ArrayList();
        boolean insideEditable = false;
        for (String ln : script.split("\n")) {
            if (ln.contains(UntrustedLua.END)) {
                insideEditable = false;
            }
            if (ln.contains(UntrustedLua.START)) {
                insideEditable = true;
            }
            if (insideEditable) {
                for (String badWord : blacklistWords) {
                    if (ln.contains(badWord)) {
                        badStrings.add(badWord);
                    }
                }
            }
        }
        return badStrings.toArray(new String[0]);
    }

    public void runScript(String script, boolean isOriginalScript) {
        try {
            initLevelProperties();
            if (!isOriginalScript) {
                if (scriptContainsBadWord(script)) {
                    resetLevelProperties();
                    setLevelStatus("Bad word");
                    String words = Arrays.toString(getAllBadWords(script));
                    JOptionPane.showMessageDialog(UntrustedLua.mainFrame, "Blacklisted word/s in script:\n" + words);
                    return;
                }
            }

            globals.load(new LuaLevel(this));
            globals.load(new LuaPlayer(this));
            globals.load(new LuaMain(this));
            globals.load(script).invoke();

            callScriptFunc(LuaMain.functions.INIT);

            globals.load(new LuaLevel(this));
            globals.load(new LuaPlayer(this));
            callScriptFunc(LuaMain.functions.VALIDATE);

            lastSuccessfulScript = script;
        } catch (LuaError ex) {
            ex.printStackTrace();
            if (lastSuccessfulScript != null) {
                runScript(lastSuccessfulScript, lastSuccessfulScript.equals(originalScript));
            }
            JOptionPane.showMessageDialog(UntrustedLua.mainFrame, ex.getMessage());
        }
    }

    public void setLevelStatus(String status) {
        this.status = status;
    }

    public void resetLevelStatus() {
        this.status = "";
    }

    public void setErrorText(String errorText) {
        this.errorText = errorText;
    }

    public void resetErrorText() {
        this.errorText = "";
    }

    public LuaValue callScriptFunc(LuaMain.functions func) {
        return globals.get("Main").get(func.functionName).invoke().arg(1);
    }

    public void update(LevelRenderPanel renderPanel) {
        String newpos = "";
        boolean tick = false;
        boolean playerMove = false;
        if (player != null) {
            if (input) {
                if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_W)) {
                    newpos = "up";
                    playerMove = true;
                }
                if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_S)) {
                    newpos = "down";
                    playerMove = true;
                }
                if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_A)) {
                    newpos = "left";
                    playerMove = true;
                }
                if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_D)) {
                    newpos = "right";
                    playerMove = true;
                }
            }
            tick = playerMove;
        }
        if (input) {
            if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_Q)) {
                if (playerInventory.contains("phone")) {
                    if (phoneCallback != null) {
                        phoneCallback.run();
                    }
                }
            }
            if (renderPanel.getInput().isKeyPressed(KeyEvent.VK_E)) {
                tick = true;
            }
        }
        if (tick) {
            runEntityEvent("behavior");
        }
        if (player != null) {
            if (playerMove) {
                movePosition(player.position, newpos, true);
            }
        }
    }

    private boolean movePosition(Position pos, String direction) {
        return this.movePosition(pos, direction, false);
    }

    private boolean movePosition(Position pos, String direction, boolean doEvents) {
        boolean success = false;
        int newx = pos.x, newy = pos.y;
        if (direction.equals("left")) {
            newx--;
        }
        if (direction.equals("right")) {
            newx++;
        }
        if (direction.equals("up")) {
            newy--;
        }
        if (direction.equals("down")) {
            newy++;
        }
        if (!getTile(newx, newy).equals("none")) {
            String ent = getEntity(newx, newy);
            Tile tile = blockMapping.get(getTile(newx, newy));
            boolean collide = tile.isCollidable();
            if (player != null) {
                if (newx == player.position.x && newy == player.position.y) {
                    collide = true;
                }
            }
            if (!ent.equals("none") && entities.containsKey(ent)) {
                if (entities.get(ent).collidable) {
                    collide = true;
                }
                if (doEvents) {
                    runEntityEvent("onEntityCollision");
                }
            }
            if (!collide) {
                pos.setPosition(newx, newy);
                success = true;
            }
            if (doEvents) {
                runTileEvent(getTile(newx, newy), "onTileCollision");
            }
            if (itemMapping.containsKey(getTile(newx, newy))) {
                tiles.put(new Position(newx, newy), "air");
            }
        }
        return success;
    }

    public void addTileProperty(String name, Tile tile) {
        if (!blockMapping.containsKey(name)) {
            blockMapping.put(name, tile);
        }
    }

    public void movePlayer(String direction) {
        if (player == null) {
            return;
        }
        movePosition(player.position, direction);
    }

    public void moveToward(Position from, Position to) {
//        var target = obj.findNearest(type);
        int leftDist = from.x - to.x;
        int upDist = from.y - to.y;

        String direction;
        if (upDist == 0 && leftDist == 0) {
            return;
        }
        if (upDist > 0 && upDist >= leftDist) {
            direction = "up";
        } else if (upDist < 0 && upDist < leftDist) {
            direction = "down";
        } else if (leftDist > 0 && leftDist >= upDist) {
            direction = "left";
        } else {
            direction = "right";
        }

        movePosition(from, direction);
    }

    public void moveEntity(String direction, String entName) {
        if (entities.containsKey(entName)) {
            Entity ent = entities.get(entName);
            movePosition(ent.position, direction);
        }
    }

    public void validateAtLeastXObjects(int num, String tile) {
        int i = 0;
        for (Map.Entry<Position, String> tls : tiles.entrySet()) {
            if (tls.getValue().equals(tile)) {
                i++;
            }
        }
        if (i >= num) {
            return;
        }
        System.out.println("ERROR ERROR, FOUND " + i + " TILES (" + tile + "), NEEDS AT LEAST " + num);
        resetLevelProperties();
        errorText = "FOUND " + i + " TILES (" + tile + "), NEEDS AT LEAST " + num;
    }

    public void validateExactlyXManyObjects(int num, String tile) {
        int i = 0;
        for (Map.Entry<Position, String> tls : tiles.entrySet()) {
            if (tls.getValue().equals(tile)) {
                i++;
            }
        }
        if (i == num) {
            return;
        }
        System.out.println("ERROR ERROR, FOUND " + i + " TILES (" + tile + "), NEEDS " + num);
        resetLevelProperties();
        errorText = "FOUND " + i + " TILES (" + tile + "), NEEDS " + num;
    }

    public String getTile(int x, int y) {
        Position pos = new Position(x, y);
        String ret = tiles.get(pos);
        return ret == null ? "none" : ret;
    }

    public String getEntity(int x, int y) {
        for (Map.Entry<String, Entity> ents : entities.entrySet()) {
            if (ents.getValue().position.equals(new Position(x, y))) {
                return ents.getKey();
            }
        }
        return "none";
    }

    public void setTile(int x, int y, String bl) {
        Position pos = new Position(x, y);
        if (blockMapping.containsKey(bl)) {
            if (!tiles.containsKey(pos) || tiles.get(pos).equals("air")) {
                tiles.put(pos, bl);
            }
        }
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    public Runnable luaFuncToRunnable(final LuaFunction func) {
        return this.luaFuncToRunnable(func, null);
    }

    public Runnable luaFuncToRunnable(final LuaFunction func, final Varargs args) {
        return new Runnable() {

            @Override
            public void run() {
                func.invoke(args == null ? LuaValue.NONE : args);
            }
        };
    }

    public static interface Event {

        public void run();
    }

    public static class EntityEvent implements Event {

        public String entityName;
        public Runnable runnable;

        public EntityEvent(String entityName, Runnable runnable) {
            this.entityName = entityName;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            runnable.run();
        }

    }

    public static class TileEvent implements Event {

        public Runnable runnable;
        public String tileName;

        public TileEvent(String tileName, Runnable runnable) {
            this.tileName = tileName;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            runnable.run();
        }

    }
}
TOP

Related Classes of com.isteinvids.untrusted.level.LevelManager$Event

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.