Botre Posted February 5, 2016 Share Posted February 5, 2016 (edited) onPaint caveats Description of onPaint: "called when the script should paint it's debug". We are generously going to assume the onPaint(Graph) method gets called 30 times per seconds. @Override public void onPaint(Graphics2D g2d) { super.onPaint(g2d); // Insert custom behavior here. } 1. The method's thread of execution should never be ceased or paused This will lead to inaccurate or lagged rendering, stuttering and an overall unpleasant experience for your end-user. @Deprecated @Override public void onPaint(Graphics2D g2d) { super.onPaint(g2d); /* * BAD CODE! */ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } If your IDE notifies you about an unhandled InterruptedException in your onPaint method, you're probably doing something wrong. 2. Calculate values at efficient intervals Always keep in mind that this method gets called 30 times per seconds however: - Accurate calculation of elapsed seconds requires only one or two calculations per second. - Other calculations (experience, profit, etc...) require even less than that. 3. ... and cache them where possible Avoid recalculation of values (such as elapsed time) used in other calculations, store and re-use where possible! Demonstration of caveats 2 and 3: @ScriptManifest(author = "Traum", info = "Tutorial", logo = "", name = "Tutorial - Paint", version = 0) public class TutorialPaint extends Script { // The String component that will be rendered. private String paintcomponentTime = "Time:"; // We store the starting system's clock time in milliseconds. private long startMilliseconds = System.currentTimeMillis(); // We store the elapsed amount of milliseconds (so we can reuse it instead of having to recalculate it when necessary. private long elapsedMilliseconds = 0; // We use this single thread executor to automatically recalculate / update the paint-required values (every 500 milliseconds). private ScheduledExecutorService paintValueExecutor = Executors.newSingleThreadScheduledExecutor(); // The runnable that will be executed by the executor. private Runnable paintValueRunnable = () -> { // We calculate the elapsed amount of milliseconds. elapsedMilliseconds = System.currentTimeMillis() - startMilliseconds; // We also build the string value of the component that our onPaint method is going to draw, doing this here will save the cost of rapid repeated concatenation. paintcomponentTime = "Time: " + elapsedMilliseconds; }; @Override public void onStart() throws InterruptedException { super.onStart(); paintValueExecutor.scheduleAtFixedRate(paintValueRunnable, 0, 500, TimeUnit.MILLISECONDS); } @Override public int onLoop() throws InterruptedException { // ... return 200; } @Override public void onPaint(Graphics2D g2d) { super.onPaint(g2d); // No object or value is being calculated or created here! (except for the mandatory pixel arrays and stuff like that of course). g2d.drawString(paintcomponentTime, 50, 50); } @Override public void onExit() throws InterruptedException { super.onExit(); paintValueExecutor.shutdown(); } } 4. Avoid transparency Avoid using transparency in your colors and images, your CPU and those of your end-users will thank me later. Only use transparency cleverly where it improves usability, don't use it just for the looks of it. More to come soon, feel free to suggest your best onPaint() tip(s)! Edited February 5, 2016 by Botre 1 Quote Link to comment Share on other sites More sharing options...
Eliot Posted February 5, 2016 Share Posted February 5, 2016 Botre. 2 Quote Link to comment Share on other sites More sharing options...
Vilius Posted February 5, 2016 Share Posted February 5, 2016 wew, you are quick, guessing its the same in bed with a girl? 1 Quote Link to comment Share on other sites More sharing options...
The Hero of Time Posted February 5, 2016 Share Posted February 5, 2016 He's back! 1 Quote Link to comment Share on other sites More sharing options...
bling ching chdr Posted February 5, 2016 Share Posted February 5, 2016 he stole my doritos -1 1 Quote Link to comment Share on other sites More sharing options...
Realist Posted February 5, 2016 Share Posted February 5, 2016 botre as in botrepreneur? what happened? why are you twc etc? 1 Quote Link to comment Share on other sites More sharing options...
Apaec Posted February 5, 2016 Share Posted February 5, 2016 Woooooooooo! 1 Quote Link to comment Share on other sites More sharing options...
Tom Posted February 7, 2016 Share Posted February 7, 2016 Caching the Strings isnt really necessary, since they are added to the String pool. In other words You aren't gaining any more efficiency by doing private String timeString = "Time:"; public void print(){ for(int i = 0; i < 5; i ++){ System.out.println(timeString); } } compared to public void print(){ for(int i = 0; i < 5; i ++){ System.out.println("Time"); } } However, it would still be better practice in my opinion, since if you wanted to change it, you would only have to change it in one place. Quote Link to comment Share on other sites More sharing options...
Botre Posted February 7, 2016 Author Share Posted February 7, 2016 (edited) Caching the Strings isnt really necessary, since they are added to the String pool. Thread A changes String X twice per second. Thread B reads String X 30 times per second. The reason I'm putting String X in a variable is so it's available to both thread A & thread B, not for caching purposes (since Strings are pretty much automatically cached internally (like you just pointed out :p)). Edited February 7, 2016 by Botre Quote Link to comment Share on other sites More sharing options...
Flamezzz Posted February 7, 2016 Share Posted February 7, 2016 Sooo scheduling an additional thread is not more expensive than some minor computations? Quote Link to comment Share on other sites More sharing options...
Botre Posted February 7, 2016 Author Share Posted February 7, 2016 Sooo scheduling an additional thread is not more expensive than some minor computations? You're asking me if: calculation_cost + constant_scheduling_overhead_cost < calculation_cost * 15 Well, that depends entirely on the cost of the calculations per call and how much the scheduling overhead actually is. Once the total cost of all calculations starts exceeding (constant_scheduling_overhead_cost / 14) it becomes worth using an additional thread from a performance POV. Quote Link to comment Share on other sites More sharing options...