package ragefist.core.environment.bindings; import java.util.ArrayDeque; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Queue; import java.util.logging.Level; import java.util.logging.Logger; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; import static org.luaj.vm2.LuaValue.NIL; import org.luaj.vm2.Varargs; import org.luaj.vm2.lib.OneArgFunction; import org.luaj.vm2.lib.TwoArgFunction; import org.luaj.vm2.lib.ZeroArgFunction; import ragefist.core.environment.EnvironmentCallTask; import ragefist.core.environment.EnvironmentProcessor.EnvironmentBindingAPI; import ragefist.core.util.FormatTools; /* * Created by Andrey Cherkashin (acherkashin) * http://acherkashin.me * * License * Copyright (c) 2015 Andrey Cherkashin * The project released under the MIT license: http://opensource.org/licenses/MIT */ /** * * @author acherkashin */ public class LuaProcessor extends TwoArgFunction { public static class LuaProcessorTask { private static int _nextId; private final int _id; private LuaValue _coroutine; private boolean _isPaused = false; private LuaValue _args; public LuaProcessorTask() { _id = ++_nextId; if (_nextId == Integer.MAX_VALUE) { _nextId = 1; } } } private Queue<LuaProcessorTask> _tasks = new ArrayDeque<>(); private Map<LuaValue,LuaProcessorTask> _tasksByCoroutineMap = new HashMap<>(); private Map<Integer,LuaProcessorTask> _tasksByIdMap = new HashMap<>(); private final EnvironmentBindingAPI _environment; // ---------------------------------------------------------------------- // // PUBLIC // ---------------------------------------------------------------------- // public LuaProcessor(EnvironmentBindingAPI environment) { _environment = environment; } public void processTasks() { LuaValue coroutine = _environment.getGlobals().get("coroutine"); // processing tasks Iterator<LuaProcessorTask> it = _tasks.iterator(); while(it.hasNext()) { LuaProcessorTask task = it.next(); if (task._isPaused) { continue; } String status = coroutine.get("status").call(task._coroutine).tojstring(); if ("suspended".equals(status)) { Varargs result; if (task._args != null) { result = coroutine.get("resume").invoke(task._coroutine, task._args); task._args = null; } else { result = coroutine.get("resume").invoke(task._coroutine); } if (result.toboolean(1) == false) { Logger.getGlobal().severe("LUA PROCESS TASK ERROR: "+result.tojstring(1)+", "+result.tojstring(2)); } else { status = coroutine.get("status").call(task._coroutine).tojstring(); if ("dead".equals(status)) { it.remove(); _tasksByCoroutineMap.remove(task._coroutine); _tasksByIdMap.remove(task._id); } } } } } @Override public LuaValue call(LuaValue modname, LuaValue env) { LuaTable table = LuaValue.tableOf(); table.set("addTask", lua_addTask); table.set("onTaskFinish", lua_onTaskFinish); table.set("pauseCurrent", lua_pauseCurrent); table.set("unpauseTask", lua_unpauseTask); table.set("yield", lua_yield); env.set("Processor", table); return table; } ZeroArgFunction lua_yield = new ZeroArgFunction() { @Override public LuaValue call() { return _environment.getGlobals().get("coroutine").get("yield").call(); } }; ZeroArgFunction lua_pauseCurrent = new ZeroArgFunction() { @Override public LuaValue call() { LuaValue coroutine = _environment.getGlobals().get("coroutine").get("running").call(); if (!_tasksByCoroutineMap.containsKey(coroutine)) { Logger.getLogger(LuaProcessor.class.getName()).log(Level.WARNING, "Failed to pause current coroutine cause it does not exist"); return NIL; } LuaProcessorTask task = _tasksByCoroutineMap.get(coroutine); task._isPaused = true; return LuaValue.valueOf(task._id); } }; TwoArgFunction lua_unpauseTask = new TwoArgFunction() { @Override public LuaValue call(LuaValue lv1, LuaValue lv2) { Integer taskId = lv1.toint(); LuaProcessorTask task = _tasksByIdMap.get(taskId); task._isPaused = false; if (lv2.isnil() == false) { task._args = lv2; } return NIL; } }; OneArgFunction lua_addTask = new OneArgFunction() { @Override public LuaValue call(LuaValue lv) { LuaProcessorTask task = new LuaProcessorTask(); task._coroutine = (LuaValue) _environment.getGlobals().get("coroutine").get("create").call(lv); _tasks.add(task); _tasksByCoroutineMap.put(task._coroutine, task); _tasksByIdMap.put(task._id, task); return NIL; } }; TwoArgFunction lua_onTaskFinish = new TwoArgFunction() { @Override public LuaValue call(LuaValue lv, LuaValue lv1) { EnvironmentCallTask task = (EnvironmentCallTask)lv.touserdata(); Object data = FormatTools.fromLuaToJUniformObject(lv1); task.completeWithData(data); return NIL; } }; }