public Processing(Box root) { super(null); Log.log("startup.processing", " processing plugin is starting up "); frame = new JFrame("Field/Processing"); __applet = new FieldProcessingApplet( sizeX, sizeY, queue, this, s -> { if (getLastErrorOutput() != null) getLastErrorOutput().accept(new Pair<>(-1, s)); }); __applet.init(); __applet.loop(); frame.add(__applet, BorderLayout.CENTER); frame.setSize(sizeX, sizeY); frame.setVisible(true); frame.validate(); applet = new FieldProcessingAppletDelgate(__applet); this.properties.put(P, applet); Log.log("startup.processing", " searching for boxes that need processing support "); Log.log("startup.processing", " processing plugin has finished starting up "); }
public static boolean isSpam(User poster, String body, String ip) { Date lastPost = poster.getLastPost(); Date curTime = new Date(); DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US); Date joinDate; if (poster.getIsMod()) return false; try { joinDate = formatter.parse(poster.getJoinDate()); } catch (Exception e) { joinDate = new Date(); } if (lastPost != null) { long diff = curTime.getTime() - lastPost.getTime(); long userLen = curTime.getTime() - joinDate.getTime(); long minInterval = (userLen < (Config.spamProbationPeriodDays * 1000 * 60 * 60 * 24)) ? Config.spamPostIntervalMinsProbation : Config.spamPostIntervalMinsStandard; minInterval *= 1000 * 60; if (diff < minInterval) { Log.log("Filtered post from " + poster.getUsername(), Log.DEBUG); return true; } } poster.setLastPost(curTime); return false; }
private static void endInterpreter(String contextId) throws EvalError { Interpreter i = interpreters.get(contextId); if (i == null) return; i.eval("clear();"); // can't hurt to tell bsh to clean up internally interpreters.remove(contextId); // now wait for GC Log.log("Destroyed context: " + contextId + " (" + i + ")"); }
void runTask() { status(su, StatusUpdate.LEVEL_GENERIC, GRI18n.getString(MODULE, "newAlbm", new Object[] { album.getName(), g.toString() })); try { List<NameValuePair> formparams = new ArrayList<NameValuePair>(); JSONObject jsonEntity = new JSONObject(); jsonEntity.put("type", "album"); if (album.getName() != null) jsonEntity.put("name", album.getName()); if (album.getTitle() != null) jsonEntity.put("title", album.getTitle()); if (album.getDescription() != null) jsonEntity.put("description", album.getDescription()); formparams.add(new BasicNameValuePair("entity", jsonEntity.toJSONString())); BufferedReader entityReader = sendRequest(album.getParentAlbum().getUrl(), "post", formparams); String url = ((JSONObject) JSONValue.parse(entityReader)).get("url").toString(); status(su, StatusUpdate.LEVEL_GENERIC, GRI18n.getString(MODULE, "crateAlbmOk")); album.setUrl(url); Log.log(Log.LEVEL_INFO, "Created album " + album.toString()); } catch (IOException ioe) { Log.logException(Log.LEVEL_ERROR, MODULE, ioe); Object[] params2 = {ioe.toString()}; error(su, GRI18n.getString(MODULE, "error", params2)); } }
private void jMenuItemLoadLSAResultsActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_jMenuItemLoadLSAResultsActionPerformed JFileChooser jfc = new JFileChooser(); int fileDialogReturnVal = jfc.showOpenDialog(this); if (fileDialogReturnVal == JFileChooser.APPROVE_OPTION) { try { File inputFile = jfc.getSelectedFile(); FileInputStream fis = new FileInputStream(inputFile); ObjectInputStream ois = new ObjectInputStream(fis); this.currentResults = (LSAResults) ois.readObject(); } catch (IOException e) { log.log(Log.ERROR, "Failed to load LSA results\n" + e.getMessage()); } catch (ClassNotFoundException e) { log.log(Log.ERROR, "Class not found : Error loading LSA results due to version mismatch"); } System.out.println(currentResults == null); } } // GEN-LAST:event_jMenuItemLoadLSAResultsActionPerformed
void runTask() { su.startProgress(StatusUpdate.LEVEL_BACKGROUND, 0, 10, GRI18n.getString(MODULE, "albmFtchng", new Object[] {g.toString()}), true); long startTime = System.currentTimeMillis(); try { list(); } catch (IOException e) { Log.logException(Log.LEVEL_CRITICAL, MODULE, e); } // tell the tree to reload g.reload(); Log.log(Log.LEVEL_INFO, MODULE, "execution time for AlbumList: " + (System.currentTimeMillis() - startTime)); su.stopProgress(StatusUpdate.LEVEL_BACKGROUND, GRI18n.getString(MODULE, "fetchComplete")); }
private void jMenuItemSaveProjectActionPerformed( java.awt.event.ActionEvent evt) // GEN-FIRST:event_jMenuItemSaveProjectActionPerformed { // GEN-HEADEREND:event_jMenuItemSaveProjectActionPerformed if (this.theProject != null) { JFileChooser jfc = new JFileChooser(); int fileDialogReturnVal = jfc.showSaveDialog(this); if (fileDialogReturnVal == JFileChooser.APPROVE_OPTION) { try { File outputFile = jfc.getSelectedFile(); FileOutputStream fos = new FileOutputStream(outputFile); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(this.theProject); if (this.currentResults != null) { oos.writeObject(this.currentResults); } } catch (IOException e) { log.log(Log.ERROR, "Failed to save file\n" + e.getMessage()); } } } } // GEN-LAST:event_jMenuItemSaveProjectActionPerformed
/** Replace path[index+1] by the zigzag point with the given angle */ private void addZigZag(List<Vector2> path, int index, int angleIndex) { Vector2 from = path.get(index); Vector2 to = path.get(index + 1); double angle = Utils.getAngleTo(from.getX(), from.getY(), to.getX(), to.getY()); angle += angles[angleIndex]; Vector2 zigV = null; // try to find a walkable target in the direction of the angle for (int i = 0; zigV == null && i <= 2; ++i) { Vector2 v = from.add(Utils.facingAngleToVector2(angle).scale(MyCommander.SMALL_DIST + i)); if (Tile.isValid((int) v.getX(), (int) v.getY())) { Tile zigTile = Tile.get(v); if (zigTile.isWalkable) { zigV = v; break; } } } if (zigV != null) { path.remove(index + 1); path.add(index + 1, zigV); } else { Log.log( "addZigZag: No walkable spot found, from = " + from + ", to = " + to + ", natural point: " + from.add(Utils.facingAngleToVector2(angle).scale(MyCommander.SMALL_DIST))); } zigZagAdded[index] = true; zigZagAdded[index + 1] = true; if (index + 2 < zigZagAdded.length) { zigZagAdded[index + 2] = true; } }
private void jMenuItemLoadProjectActionPerformed( java.awt.event.ActionEvent evt) // GEN-FIRST:event_jMenuItemLoadProjectActionPerformed { // GEN-HEADEREND:event_jMenuItemLoadProjectActionPerformed JFileChooser jfc = new JFileChooser(); if (lastPath != null) { jfc.setCurrentDirectory(lastPath); } int fileDialogReturnVal = jfc.showOpenDialog(this); if (fileDialogReturnVal == JFileChooser.APPROVE_OPTION) { try { File inputFile = jfc.getSelectedFile(); FileInputStream fis = new FileInputStream(inputFile); ObjectInputStream ois = new ObjectInputStream(fis); this.theProject = (Project) ois.readObject(); this.currentResults = (LSAResults) ois.readObject(); lastPath = new File(jfc.getSelectedFile().getPath()); } catch (IOException e) { if (this.theProject == null) { log.log(Log.ERROR, "Failed to load project"); } if (this.currentResults == null) { log.log(Log.WARNING, "Failed to load results"); } log.log(Log.WARNING, e.getMessage()); } catch (ClassNotFoundException e) { log.log(Log.ERROR, "Class not found error, version mismatch"); } } if (this.theProject != null) { jMenuItemViewDocuments.setEnabled(true); jMenuItemSaveProject.setEnabled(true); this.setTitle(theProject.getProjectName()); log.log(Log.INFO, "Project Loaded"); } if (this.currentResults != null) { log.log(Log.INFO, "Results loaded"); } } // GEN-LAST:event_jMenuItemLoadProjectActionPerformed
public BufferedReader sendRequest(String url, String verb, HttpEntity entity) throws IOException { HttpPost post = new HttpPost(url); Log.log(Log.LEVEL_TRACE, "Sending request: " + post.getRequestLine().toString()); if (entity != null) { post.setEntity(entity); if (!(entity instanceof MultipartEntity)) { Log.log(Log.LEVEL_TRACE, "Parameters: " + EntityUtils.toString(entity)); } } post.setHeader("X-Gallery-Request-Method", verb); boolean usedCachedKey = true; if (url.endsWith(api)) { // we're trying to get the key already usedCachedKey = false; } else { String key = g.getKey(); if (key == null || key.length() == 0) { // no cached key, perform login key = getKey(); usedCachedKey = false; } post.setHeader("X-Gallery-Request-Key", key); } HttpResponse response = httpclient.execute(post); int status = response.getStatusLine().getStatusCode(); Log.log(Log.LEVEL_TRACE, "HTTP status: " + status); HttpEntity responseEntity = response.getEntity(); responseEntity = new BufferedHttpEntity(responseEntity); Log.log(Log.LEVEL_TRACE, "HTTP response: " + EntityUtils.toString(responseEntity)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseEntity.getContent())); switch (status) { case 200: // everything cool return bufferedReader; case 403: // security exception responseEntity.consumeContent(); if (usedCachedKey) { // assume they key was stale, reset it g.setKey(null); return sendRequest(url, verb, entity); } else { g.logOut(); throw new GR2Exception("Security exception"); } default: throw new GR2Exception("Unknown return HTTP status: " + status); } }
private static Interpreter getInterpreter(String contextId) throws EvalError { // Get the appropriate interpreter Interpreter i = null; boolean createdInterp = false; synchronized (interpreters) { // serialize two gets of the same name i = interpreters.get(contextId); if (i == null) { i = new Interpreter(); interpreters.put(contextId, i); createdInterp = true; } } if (createdInterp) { Log.log("Created context: " + contextId + " (" + i + ")"); // Now configure stdin and stdout to capture 10k of content // Store references to the circular buffers within the interpreter itself. // This provides a nice place to store them plus theoretically allows // advanced use from within the bsh environment. // On Windows print() outputs \r\n but in XQuery that's normalized to \n // so the 10k of Java buffer may produce less than 10k of content in XQuery! OutputStream circularOutput = new CircularByteArrayOutputStream(10240); PrintStream printOutput = new PrintStream(circularOutput); i.setOut(printOutput); i.set("mljamout", circularOutput); OutputStream circularError = new CircularByteArrayOutputStream(10240); PrintStream printError = new PrintStream(circularError); i.setErr(printError); i.set("mljamerr", circularError); // Capture the built-in System.out and System.err also. // (Commented out since System appears global, can't do per interpreter.) // i.set("mljamprintout", printOutput); // i.set("mljamprinterr", printError); // i.eval("System.setOut(mljamprintout);"); // i.eval("System.setErr(mljamprinterr);"); // Need to expose hexdecode() and base64decode() built-in functions i.eval("hexdecode(String s) { return com.xqdev.jam.MLJAM.hexDecode(s); }"); i.eval("base64decode(String s) { return com.xqdev.jam.MLJAM.base64Decode(s); }"); // Let's tell the context what its id is i.set("mljamid", contextId); } // Update the last accessed time, used for cleaning i.set("mljamlast", System.currentTimeMillis()); // If it's been long enough, go snooping for stale contexts if (System.currentTimeMillis() > lastClean + CLEAN_INTERVAL) { Log.log("Initiated periodic scan for stale context objects"); lastClean = System.currentTimeMillis(); Iterator<Interpreter> itr = interpreters.values().iterator(); while (itr.hasNext()) { Interpreter interp = itr.next(); Long last = (Long) interp.get("mljamlast"); if (System.currentTimeMillis() > last + STALE_TIMEOUT) { itr.remove(); Log.log("Staled context: " + interp.get("mljamid") + " (" + interp + ")"); } else if ((System.currentTimeMillis() > last + TEMP_STALE_TIMEOUT) && ("" + interp.get("mljamid")).startsWith("temp:")) { itr.remove(); Log.log("Staled temp context: " + interp.get("mljamid") + " (" + interp + ")"); } } } return i; }
void trace(String message) { Log.log(Log.LEVEL_TRACE, MODULE, message); }
void status(StatusUpdate su, int level, String message) { Log.log(Log.LEVEL_INFO, MODULE, message); su.updateProgressStatus(level, message); }
boolean uploadPicture(Picture p) { try { //transferListener.currentFile = p.toString(); status(su, StatusUpdate.LEVEL_UPLOAD_ONE, GRI18n.getString(MODULE, "upPrep")); MultipartEntity entity = new MultipartEntity(); Charset utf8 = Charset.forName("UTF-8"); JSONObject jsonEntity = new JSONObject(); jsonEntity.put("type", "photo"); if (p.getName() != null) jsonEntity.put("name", p.getName()); if (p.getTitle() != null) jsonEntity.put("title", p.getTitle()); if (p.getDescription() != null) jsonEntity.put("description", p.getDescription()); entity.addPart("entity", new StringBody(jsonEntity.toJSONString(), utf8)); ContentBody body = new FileBody(p.getUploadSource()); entity.addPart("file", body); BufferedReader entityReader = sendRequest(p.getParentAlbum().getUrl(), "post", entity); String url = ((JSONObject) JSONValue.parse(entityReader)).get("url").toString(); status(su, StatusUpdate.LEVEL_UPLOAD_ONE, GRI18n.getString(MODULE, "upSucc")); p.setUrl(url); Log.log(Log.LEVEL_INFO, "Uploaded " + p.getUploadSource().toString() + " to " + url); return true; // set auto-rotate only if we do the rotation in GR, otherwise we'd be overriding the server setting // if (p.getAngle() != 0) { // opts[5] = new NVPair("auto_rotate", "no"); // } // set up extra fields // if (p.getExtraFieldsMap() != null && p.getExtraFieldsMap().size() > 0) { // ArrayList optsList = new ArrayList(Arrays.asList(opts)); // // Iterator it = p.getExtraFieldsMap().keySet().iterator(); // while (it.hasNext()) { // String name = (String) it.next(); // String value = p.getExtraField(name); // // optsList.add(new NVPair("extrafield." + name, value, utf8?"UTF-8":null)); // } // } // // opts = (NVPair[]) optsList.toArray(opts); // } // load and validate the response // Properties props = requestResponse(hdrs, data, g.getGalleryUrl(scriptName), true, su, this, transferListener); // if (props.getProperty("status").equals(GR_STAT_SUCCESS)) { // status(su, StatusUpdate.LEVEL_UPLOAD_ONE, GRI18n.getString(MODULE, "upSucc")); // String newItemName = props.getProperty("item_name"); // if (newItemName != null) { // su.doneUploading(newItemName, picture); // } // return true; // } else { // Object[] params = {props.getProperty("status_text")}; // error(su, GRI18n.getString(MODULE, "upErr", params)); // return false; // } } catch (GR2Exception gr2e) { Log.logException(Log.LEVEL_ERROR, MODULE, gr2e); Object[] params = {gr2e.getMessage()}; error(su, p.toString() + ": " + GRI18n.getString(MODULE, "error", params)); } catch (IOException ioe) { Log.logException(Log.LEVEL_ERROR, MODULE, ioe); Object[] params = {ioe.toString()}; error(su, p.toString() + ": " + GRI18n.getString(MODULE, "error", params)); } return false; }
private void list() throws IOException { List<NameValuePair> formparams = new ArrayList<NameValuePair>(); formparams.add(new BasicNameValuePair("type", "album")); formparams.add(new BasicNameValuePair("scope", "all")); BufferedReader entityReader = sendRequest(g.getUrlString() + api + "item/1", "get", formparams); JSONParser parser = new JSONParser(); ListContentHandler lch = new ListContentHandler(); HashMap<String,String> url2parentUrl = new HashMap<String,String>(); HashMap<String,Album> url2album = new HashMap<String,Album>(); ArrayList<Album> albums = new ArrayList<Album>(); try { Album rootAlbum = g.createRootAlbum(); rootAlbum.setUrl(g.getUrlString() + api + "item/1"); rootAlbum.setSuppressEvents(true); lch.setAlbum(rootAlbum); parser.parse(entityReader, lch, true); rootAlbum.setSuppressEvents(false); // map album names to albums url2album.put(rootAlbum.getUrl(), rootAlbum); url2parentUrl.put(rootAlbum.getUrl(), lch.getParentUrl()); while (!lch.isEnd()) { Album a = g.newAlbum(); a.setSuppressEvents(true); lch.setAlbum(a); parser.parse(entityReader, lch, true); a.setSuppressEvents(false); albums.add(a); // map album names to albums url2album.put(a.getUrl(), a); url2parentUrl.put(a.getUrl(), lch.getParentUrl()); } } catch (ParseException e) { Log.logException(Log.LEVEL_CRITICAL, MODULE, e); } Log.log(Log.LEVEL_TRACE, MODULE, "Created " + albums.size() + " albums"); // link albums to parents for (Object o : url2parentUrl.keySet()) { String name = (String) o; String parentName = url2parentUrl.get(name); Album child = url2album.get(name); Album parent = url2album.get(parentName); if (child != null && parent != null) { parent.add(child); } } Log.log(Log.LEVEL_TRACE, MODULE, "Linked " + url2parentUrl.size() + " albums to their parents"); // reorder Collections.sort(albums, new NaturalOrderComparator<Album>()); Collections.reverse(albums); ArrayList<Album> orderedAlbums = new ArrayList<Album>(); int depth = 0; while (!albums.isEmpty()) { Iterator<Album> it = albums.iterator(); while (it.hasNext()) { Album a = it.next(); try { if (a.getAlbumDepth() == depth) { it.remove(); a.sortSubAlbums(); Album parentAlbum = a.getParentAlbum(); if (parentAlbum == null) { orderedAlbums.add(0, a); } else { int i = orderedAlbums.indexOf(parentAlbum); orderedAlbums.add(i + 1, a); } } } catch (IllegalArgumentException e) { it.remove(); Log.log(Log.LEVEL_TRACE, MODULE, "Gallery server album list is corrupted: " + "album " + a.getName() + " has a bad containment hierarchy."); } } depth++; } Log.log(Log.LEVEL_TRACE, MODULE, "Ordered " + orderedAlbums.size() + " albums"); status(su, StatusUpdate.LEVEL_BACKGROUND, GRI18n.getString(MODULE, "ftchdAlbms")); }
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { try { // A good request looks like /mljam/contextid/verb?name=varname // The extra path info includes the context id and verb String extra = req.getPathInfo(); // "/contextid/verb" if (extra == null || extra.equals("")) { throw new ClientProblemException( "Request requires a context id and verb in its extra path info"); } String[] parts = extra.split("/"); // { "", "contextid", "verb" } if (parts.length < 2) { throw new ClientProblemException( "Request requires a context id and verb in its extra path info"); } else if (parts.length < 3) { throw new ClientProblemException("Request requires a verb in its extra path info"); } String contextId = parts[1]; String verb = parts[2]; String method = req.getMethod(); if (method.equalsIgnoreCase("get")) { // We have three GET verbs: get, get-stdout, get-stderr. // These are all idempotent, while the POST verbs aren't. The get // verb accept a "name" query string parameter. The get verb returns // either XQuery to evaluate (indicated by x-marklogic/xquery content type) // or a raw binary (indicated by an application/binary-encoded content type). if (verb.equalsIgnoreCase("get")) { String name = req.getParameter("name"); if (name == null || name.equals("")) { throw new ClientProblemException("The get verb requires a name parameter"); } Interpreter i = getInterpreter(contextId); Object o = i.get(name); if (o instanceof byte[]) { sendBinaryResponse(res, (byte[]) o); } else if (o instanceof String) { sendStringResponse(res, (String) o); } else { sendXQueryResponse(res, o); } } else if (verb.equalsIgnoreCase("get-stdout")) { Interpreter i = getInterpreter(contextId); i.getOut().flush(); CircularByteArrayOutputStream circ = (CircularByteArrayOutputStream) i.get("mljamout"); if (circ != null) { sendStringResponse(res, circ.toString()); circ.reset(); } else { throw new ServerProblemException("Could not fetch mljamout from interpreter context"); } } else if (verb.equalsIgnoreCase("get-stderr")) { Interpreter i = getInterpreter(contextId); i.getErr().flush(); CircularByteArrayOutputStream circ = (CircularByteArrayOutputStream) i.get("mljamerr"); if (circ != null) { sendStringResponse(res, circ.toString()); circ.reset(); } else { throw new ServerProblemException("Could not fetch mljamerr from interpreter context"); } } else { throw new ClientProblemException("Unrecognized GET verb: " + verb); } } else if (method.equalsIgnoreCase("post")) { // We have six POST verbs: eval, unset, end, source, set-string, and set-binary. // These are POST verbs because they aren't idempotent. // The set-string, set-binary, unset, and source verbs accept a "name" // query string parameter. The set-string and set-binary verbs accept // a value in their post body. The eval verb accepts code in its post body. if (verb.equalsIgnoreCase("set-string")) { String name = req.getParameter("name"); if (name == null || name.equals("")) { throw new ClientProblemException("The set-string verb requires a name parameter"); } String body = getBody(req); // a value of "" is legit Interpreter i = getInterpreter(contextId); i.unset(name); i.set(name, body); sendNoResponse(res); } else if (verb.equalsIgnoreCase("set-binary")) { String name = req.getParameter("name"); if (name == null || name.equals("")) { throw new ClientProblemException("The set-binary verb requires a name parameter"); } String body = getBody(req); // a value of "" is legit byte[] bodyBytes = hexDecode(body); // later could do this streaming for speed Interpreter i = getInterpreter(contextId); i.unset(name); i.set(name, bodyBytes); sendNoResponse(res); } else if (verb.equalsIgnoreCase("eval")) { String body = getBody(req); if (body == null || body.equals("")) { throw new ClientProblemException( "The eval verb requires a post body containing code to eval"); } Interpreter i = getInterpreter(contextId); i.eval(body); sendNoResponse(res); } else if (verb.equalsIgnoreCase("eval-get")) { String body = getBody(req); if (body == null || body.equals("")) { throw new ClientProblemException( "The eval-get verb requires a post body containing code to eval"); } Interpreter i = getInterpreter(contextId); Object o = i.eval(body); if (o instanceof byte[]) { sendBinaryResponse(res, (byte[]) o); } else if (o instanceof String) { sendStringResponse(res, (String) o); } else { sendXQueryResponse(res, o); } } else if (verb.equalsIgnoreCase("unset")) { String name = req.getParameter("name"); if (name == null || name.equals("")) { throw new ClientProblemException("The unset verb requires a name parameter"); } Interpreter i = getInterpreter(contextId); i.unset(name); sendNoResponse(res); } else if (verb.equalsIgnoreCase("end")) { endInterpreter(contextId); sendNoResponse(res); } else if (verb.equalsIgnoreCase("source")) { String name = req.getParameter("name"); if (name == null || name.equals("")) { throw new ClientProblemException("The source verb requires a name parameter"); } Interpreter i = getInterpreter(contextId); i.source(name); sendNoResponse(res); } else { throw new ClientProblemException("Unrecognized POST verb: " + verb); } } } catch (TargetError e) { Throwable target = e.getTarget(); Log.log(e); Log.log("Target: " + target); sendServerProblemResponse( res, target.getClass().getName() + ": " + target.getMessage() + " when executing Java code: " + e.getErrorText()); // include full trace? } catch (EvalError e) { Log.log(e); sendServerProblemResponse( res, e.getClass().getName() + ": " + e.getMessage()); // include full trace? } catch (ClientProblemException e) { Log.log(e); sendClientProblemResponse(res, e.getMessage()); } catch (ServerProblemException e) { Log.log(e); sendServerProblemResponse(res, e.getMessage()); } }
protected void log(String tag, Object obj) { Log.log(obj); }
public void addZigZag( final List<Vector2> path, final double fovAngle, final int[][] squareValue) { if (path.size() < 2) { return; } Log.log("addZigZag <- " + Utils.vector2ListToString(path) + ", size: " + path.size()); attackedTiles.clear(); zigZagAdded = new boolean[path.size()]; extraValue = new int[angles.length][path.size()]; // Calculate which tiles we will see when walking the // unzigzagged path, put result in attackedTiles for (int i = 0; i < path.size() - 1; ++i) { Vector2 from = path.get(i); Vector2 to = path.get(i + 1); double angle = Utils.getAngleTo(from.getX(), from.getY(), to.getX(), to.getY()); Tile t = Tile.get(from); t.visitAttackedTiles( angle, fovAngle, new TileVisitor() { @Override public boolean visit(Tile t) { attackedTiles.add(t); return true; } }); } // calculate at each square/each angle how much value we would add // by adding a zigzag; put result in extraValue ValueCalculatingVisitor visitor = new ValueCalculatingVisitor(); visitor.squareValue = squareValue; for (int a = 0; a < angles.length; ++a) { for (int i = 0; i < path.size() - 1; ++i) { Vector2 from = path.get(i); Vector2 to = path.get(i + 1); Tile fromTile = Tile.get(from); Tile toTile = Tile.get(to); if (toTile.isWalkable) { double angle = Utils.getAngleTo(from.getX(), from.getY(), to.getX(), to.getY()); angle += angles[a]; visitor.clear(); fromTile.visitAttackedTiles(angle, fovAngle, visitor); extraValue[a][i] = visitor.value; } else { extraValue[a][i] = -1; } } } boolean stop = false; while (!stop) { // find best zigzag on the path int bestIndex = -1; int bestAngle = 0; int bestValue = 10; for (int i = 0; i < path.size() - 1; ++i) { if (!zigZagAdded[i] && !zigZagAdded[i + 1]) { for (int a = 0; a < angles.length; ++a) { if (extraValue[a][i] > bestValue) { bestIndex = i; bestAngle = a; bestValue = extraValue[a][i]; } } } } if (bestIndex >= 0) { addZigZag(path, bestIndex, bestAngle); } else { // no more zigzag added stop = true; } } Log.log("addZigZag -> " + Utils.vector2ListToString(path) + ", size: " + path.size()); }