Advertisement
PierrotLL

Nape 1009 reproducible (haxe)

Nov 30th, 2017
3,013
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 14.76 KB | None | 0 0
  1. package;
  2.  
  3. import flash.display.Sprite;
  4. import flash.events.Event;
  5. import flash.text.TextField;
  6. import flash.utils.JSON;
  7. import flash.utils.Object;
  8. import haxe.Timer;
  9. import nape.Config;
  10. import nape.callbacks.CbType;
  11. import nape.callbacks.InteractionType;
  12. import nape.callbacks.PreCallback;
  13. import nape.callbacks.PreFlag;
  14. import nape.callbacks.PreListener;
  15. import nape.phys.Body;
  16. import nape.phys.BodyList;
  17. import nape.phys.BodyType;
  18. import nape.phys.Material;
  19. import nape.shape.Circle;
  20. import nape.shape.Polygon;
  21. import nape.shape.Shape;
  22. import nape.space.Space;
  23. import nape.util.BitmapDebug;
  24.  
  25. class Main extends Sprite {
  26.    
  27.     /**
  28.      * README
  29.      * There is two ways to use this sample:
  30.      * - To quickly reproduce the error: call play(json) with one of the jsons given as examples.
  31.      * - To find a new case: comment play(json) and uncomment bruteforce() then be very patient until it displays a json in red. (sometimes more than 50000 iterations are needed)
  32.      * Do not call play(json) AND bruteforce() in the same instance.
  33.      *
  34.      * The preCollisionListener seems to be essential to get the error, even if it always returns ACCEPT.
  35.      *
  36.      * The crash is from zpp_nape/Space.cx line 2251: callbackset.remove_arb(arb);
  37.      * It is a TypeError #1009 (callbackset is null).
  38.      * It seems to always happen on a very slow collision, when some bodies overlap in the initial state.
  39.      */
  40.    
  41.     var space:Space;
  42.     var balls:Array<Body>;
  43.    
  44.     var state:Object;
  45.     var iterations:Int;
  46.    
  47.    
  48.     function new() {
  49.         super();
  50.         if (stage != null) init(null);
  51.         else addEventListener(Event.ADDED_TO_STAGE, init);
  52.     }
  53.    
  54.     function init(e:Event) {
  55.         removeEventListener(Event.ADDED_TO_STAGE, init);
  56.        
  57.         Config.linearSleepThreshold = 300 * 0.2;
  58.         Config.angularSleepThreshold = 100 * 0.4;
  59.        
  60.         space = createSpace();
  61.        
  62.         var field:Body = createField();
  63.         field.space = space;
  64.        
  65.         balls = new Array<Body>();
  66.         for (i in 0...10) {
  67.             balls[i] = createBall();
  68.             balls[i].space = space;
  69.         }
  70.        
  71.         /*
  72.          * Each json describe one case that makes nape crash
  73.          */
  74.        
  75.         /* AS3 with nape-dev.swc or nape-release.swc from napephys.com */
  76.         //var json:Object = {"balls":[{"r": -3.156528096282359, "x":462.2162040323019, "dy": -5.1896775057228925, "y":131.62446077913046, "dx":999.9865335330205}, {"r": -5.267932761744512, "x":343.6876875348389, "dy": -457.88791750451605, "y":414.27104007452726, "dx":889.0099296427331}, {"r":10.122915831505384, "x":122.46028548106551, "dy": -397.7241442465419, "y":429.7891780734062, "dx":917.5050436282932}, {"r": -1.7963113573382579, "x":484.34904934838414, "dy":962.1575397603133, "y":446.90443333238363, "dx":272.49379567685776}, {"r":6.134388216932091, "x":566.8670255690813, "dy": -924.1050666040219, "y":106.13426957279444, "dx": -382.138490441327}, {"r":3.7768165707699577, "x":685.1834611967206, "dy": -178.74010382284067, "y":439.2476936802268, "dx": -983.89632344338}, {"r": -0.6322812194278491, "x":631.6975560970604, "dy": -999.4881483239193, "y":240.43079614639282, "dx":31.991270059550207}, {"r":11.680096533966307, "x":489.84701903536916, "dy": -985.9390682201955, "y":416.1373497918248, "dx": -167.10521762378556}, {"r": -3.4340166680066133, "x":608.1786840222776, "dy": -228.72212909138187, "y":316.1457637324929, "dx": -973.49175017763}, {"r": -0.6969883272643331, "x":220.29011901468039, "dy": -213.2234088407065, "y":262.8941785544157, "dx":977.0034687360885}]};
  77.         //var json:Object = {"balls":[{"r":2.304954084555204,"dy":500.537749476724,"x":547.007760591805,"y":259.75943449884653,"dx":865.7147112928001},{"r":8.088982974357869,"dy":-962.0263189633062,"x":565.9635991789401,"y":225.4328766837716,"dx":272.9567028338216},{"r":3.0866010187846147,"dy":-767.3748407255088,"x":124.52481277287006,"y":497.5758083164692,"dx":641.1987631160092},{"r":-1.0848035447305087,"dy":-53.664278723848355,"x":160.42164023965597,"y":211.59836277365685,"dx":-998.5590344035995},{"r":10.42561051099377,"dy":-551.9065529686793,"x":374.8824402689934,"y":442.34102480113506,"dx":833.9059639972786},{"r":2.952367705188305,"dy":820.4765433256946,"x":411.82099217548966,"y":479.4938759878278,"dx":571.6801919362954},{"r":0.9324079656657958,"dy":-476.8062899506552,"x":573.981655947864,"y":121.27740476280451,"dx":-879.0083969243365},{"r":10.63930998816048,"dy":836.9045238846372,"x":336.5966519340873,"y":355.2835015580058,"dx":547.3488996073972},{"r":-0.7172337646709215,"dy":864.3553314794212,"x":279.87469462677836,"y":345.0612550601363,"dx":502.88155756907594},{"r":-0.2921149876017557,"dy":-509.9306906430794,"x":279.1422327980399,"y":481.0675488784909,"dx":-860.2154908743926}]};
  78.         //var json:Object = {"balls":[{"r":-0.6747614463169533,"dy":317.54634209645695,"x":130.14394538477063,"y":296.2216179817915,"dx":-948.2427540567658},{"r":8.158060570437016,"dy":-791.7863630553991,"x":426.2916679494083,"y":190.5905159190297,"dx":610.79812972823},{"r":-6.219030883941777,"dy":765.6887073971993,"x":374.8432073742151,"y":140.81931747496128,"dx":643.2113209236961},{"r":6.1072291223096435,"dy":808.5924706026161,"x":451.28654846921563,"y":475.62004663050175,"dx":588.36911584885},{"r":9.4009070992979,"dy":-556.3703267198126,"x":549.3600419722497,"y":346.18493784219027,"dx":830.9344496082041},{"r":6.811587619153979,"dy":313.0142280040542,"x":673.1301883235574,"y":473.5712569206953,"dx":949.7484367278663},{"r":-0.47474721960728683,"dy":-878.8746477057213,"x":160.73340568691492,"y":328.1808281317353,"dx":477.05277865257676},{"r":6.124891022981558,"dy":703.8825649807046,"x":538.7657119892538,"y":212.52992171794176,"dx":710.3163624162013},{"r":7.420271756377211,"dy":-487.1252801733692,"x":268.8964016735554,"y":328.4786669537425,"dx":873.3321025909999},{"r":4.229908275492413,"dy":-971.8425986030944,"x":448.76833418384194,"y":399.97291527688503,"dx":-235.63099019523023}]};
  79.         //var json:Object = {"balls":[{"r":11.223716572686193,"dy":891.2212267204964,"x":256.763063184917,"y":377.6177240535617,"dx":453.56887574304926},{"r":-3.251533126994658,"dy":-706.4366655058992,"x":360.82773292437196,"y":415.98646976053715,"dx":707.776262408472},{"r":-3.702958088187698,"dy":857.0360871793217,"x":620.6580780446529,"y":196.0784088820219,"dx":-515.256387900585},{"r":3.6798378207243267,"dy":-683.7836427642802,"x":382.37734641879797,"y":309.2748336493969,"dx":-729.6848154429495},{"r":0.5843887252218014,"dy":-98.408860959845,"x":464.29445473477244,"y":308.15525613725185,"dx":-995.1460677129694},{"r":7.170918443547993,"dy":-297.6251343384354,"x":543.0872270837426,"y":447.9411441832781,"dx":-954.6828161279683},{"r":6.797702460941407,"dy":810.8829184248893,"x":218.26762836426497,"y":472.6870821788907,"dx":-585.2084180928485},{"r":-4.751269592009655,"dy":490.83829792857006,"x":629.1461830027401,"y":303.79466488957405,"dx":871.2506902646243},{"r":-1.5131191342740316,"dy":321.74602584775624,"x":524.3183753453195,"y":332.4558276683092,"dx":946.826010865341},{"r":1.100517520240663,"dy":460.0385247108853,"x":115.91202924028039,"y":234.47336666285992,"dx":887.8989558400393}]};
  80.        
  81.         /* Haxe with nape 2.0.20 from haxelib (also crashes in AS3 with self-build nape-release-2.0.20.swc) */
  82.         var json:Object = {"balls":[{"r":12.510891459178243, "dx": -125.90689683682967, "x":294.8822371661663, "y":214.13405239582062, "dy":992.0420622780669}, {"r":7.809591052585731, "dx":592.8236784079118, "x":497.09897404536605, "y":465.5042951926589, "dy":805.3322831719295}, {"r": -5.83355820793757, "dx": -968.8109568592889, "x":327.84602576866746, "y":430.99390529096127, "dy": -247.8009884350523}, {"r":7.905704963498769, "dx":688.0244466057911, "x":343.6834901571274, "y":428.53208538144827, "dy":725.6875091062234}, {"r":3.141439459734368, "dx": -221.3440292212329, "x":489.5091576501727, "y":415.28559159487486, "dy": -975.1957858441094}, {"r":7.5085219413345, "dx":220.02215415022596, "x":372.4642732180655, "y":397.8513905778527, "dy": -975.4948752725943}, {"r": -5.797343647478622, "dx":316.64666290604777, "x":676.6619213856757, "y":237.54338398575783, "dy": -948.5435629798263}, {"r":12.394488899184388, "dx":987.0094761703454, "x":348.0925536714494, "y":431.52794260531664, "dy":160.6620488788202}, {"r":8.43956271057679, "dx": -949.4537783619918, "x":120.36441238597035, "y":121.07095532119274, "dy":313.9068695555066}, {"r":9.111144937472208, "dx":875.2132885498985, "x":637.3177004046738, "y":108.46717916429043, "dy":483.73722158385954}]};
  83.         //var json:Object = {"balls":[{"r":12.510891459178243,"dx":-125.90689683682967,"x":294.8822371661663,"y":214.13405239582062,"dy":992.0420622780669},{"r":7.809591052585731,"dx":592.8236784079118,"x":497.09897404536605,"y":465.5042951926589,"dy":805.3322831719295},{"r":-5.83355820793757,"dx":-968.8109568592889,"x":327.84602576866746,"y":430.99390529096127,"dy":-247.8009884350523},{"r":7.905704963498769,"dx":688.0244466057911,"x":343.6834901571274,"y":428.53208538144827,"dy":725.6875091062234},{"r":3.141439459734368,"dx":-221.3440292212329,"x":489.5091576501727,"y":415.28559159487486,"dy":-975.1957858441094},{"r":7.5085219413345,"dx":220.02215415022596,"x":372.4642732180655,"y":397.8513905778527,"dy":-975.4948752725943},{"r":-5.797343647478622,"dx":316.64666290604777,"x":676.6619213856757,"y":237.54338398575783,"dy":-948.5435629798263},{"r":12.394488899184388,"dx":987.0094761703454,"x":348.0925536714494,"y":431.52794260531664,"dy":160.6620488788202},{"r":8.43956271057679,"dx":-949.4537783619918,"x":120.36441238597035,"y":121.07095532119274,"dy":313.9068695555066},{"r":9.111144937472208,"dx":875.2132885498985,"x":637.3177004046738,"y":108.46717916429043,"dy":483.73722158385954}]};
  84.         //var json:Object = {"balls":[{"r":1.715299413082748,"x":646.9439085572958,"dx":-982.9024086918445,"y":448.87818917632103,"dy":184.12727931452858},{"r":0.15720247039960233,"x":240.8002683892846,"dx":221.59650677657768,"y":217.9318282753229,"dy":-975.1384456498565},{"r":1.0393383300532528,"x":609.6032074652612,"dx":601.1028557559986,"y":484.18885096907616,"dy":799.1716691687607},{"r":2.0531504921991526,"x":279.49916161596775,"dx":-919.3278313777674,"y":166.01293999701738,"dy":393.4924884343427},{"r":3.766813014058811,"x":597.1395275555551,"dx":-331.2455908302468,"y":299.5803773403168,"dy":-943.5445715786407},{"r":3.418674686231491,"x":686.2579471431673,"dx":876.766249298559,"y":262.03186213970184,"dy":480.9167745992407},{"r":2.9069704167233046,"x":225.76720546931028,"dx":159.74117771373304,"y":204.62767910212278,"dy":-987.15893155187},{"r":0.0011162416045147451,"x":360.61766454949975,"dx":-181.53909222860557,"y":400.4634788259864,"dy":983.3837287614707},{"r":3.2987872096025868,"x":224.49092408642173,"dx":-887.7377363095985,"y":199.2192141711712,"dy":-460.3495536349632},{"r":5.189076023513413,"x":608.2989612594247,"dx":-403.5892654771892,"y":127.91087795048952,"dy":-914.9402738931011}]};
  85.        
  86.         play(json);
  87.        
  88.        
  89.         /*
  90.          * Method used ot find a new test case.
  91.          * To use, comment "play(json)" and uncomment "bruteforce()"
  92.          * It runs iterations in background until the error happens,
  93.          * then displays the initial state needed to reproduce the case with play().
  94.          * Some cases found with bruteforce() doesn't make nape crash again in play(), don't know why.
  95.          */
  96.         //bruteforce();
  97.     }
  98.    
  99.     function play(state:Object) {
  100.         applyState(state);
  101.         testOverlap();
  102.         var debug:BitmapDebug = new BitmapDebug(stage.stageWidth, stage.stageHeight);
  103.         addChild(debug.display);
  104.         addEventListener(Event.ENTER_FRAME, function(e:Event) {
  105.             space.step(0.016);
  106.             debug.clear();
  107.             debug.draw(space);
  108.             debug.flush();
  109.         });
  110.     }
  111.    
  112.     function bruteforce() {
  113.         var start:Float = Timer.stamp();
  114.         while (Timer.stamp() - start < 1) {
  115.             if (isSleeping()) {
  116.                 state = randomState();
  117.                 applyState(state);
  118.                 iterations++;
  119.             }
  120.             try {
  121.                 space.step(0.016);
  122.             } catch (e:Dynamic) {
  123.                 print(JSON.stringify(state), 0xff0000);
  124.                 return;
  125.             }
  126.         }
  127.         print(iterations + "");
  128.         Timer.delay(bruteforce, 0);
  129.     }
  130.    
  131.    
  132.    
  133.     function createSpace() : Space {
  134.         var space:Space = new Space();
  135.         space.worldAngularDrag = 50 * 0.015;
  136.         // preCollisionListener always return ACCEPT, but is essentiel to makes nape crash.
  137.         // Without this useless listener, nape doesn't crash.
  138.         space.listeners.add(new PreListener(InteractionType.COLLISION, CbType.ANY_BODY, CbType.ANY_BODY, preCollisionListener, 0, true));
  139.         return space;
  140.     }
  141.    
  142.     function createField() : Body {
  143.         var w:Int = 800;
  144.         var h:Int = 600;
  145.         var t:Int = 50;
  146.         var material:Material = new Material();
  147.         material.elasticity = 1;
  148.         material.density = 50;
  149.         var body:Body = new Body(BodyType.STATIC);
  150.         body.shapes.add(new Polygon(Polygon.rect(0, 0, w, t), material));
  151.         body.shapes.add(new Polygon(Polygon.rect(0, h - t, w, t), material));
  152.         body.shapes.add(new Polygon(Polygon.rect(0, t, t, h - 2 * t), material));
  153.         body.shapes.add(new Polygon(Polygon.rect(w - t, t, t, h - 2 * t), material));
  154.         var fluid:Shape = new Polygon(Polygon.rect(0, 0, w, h));
  155.         fluid.fluidEnabled = true;
  156.         fluid.fluidProperties.viscosity = 0.57;
  157.         body.shapes.add(fluid);
  158.         return body;
  159.     }
  160.    
  161.     var nextBallId:Int;
  162.     function createBall() : Body {
  163.         var material:Material = new Material();
  164.         material.elasticity = 1;
  165.         material.density = 5;
  166.         var body:Body = new Body(BodyType.DYNAMIC);
  167.         body.isBullet = true;
  168.         body.shapes.add(new Circle(40, null, material));
  169.         body.userData.id = nextBallId++;
  170.         return body;
  171.     }
  172.    
  173.     function isSleeping() : Bool {
  174.         return space.liveBodies.length == 0;
  175.     }
  176.    
  177.     function preCollisionListener(c:PreCallback) : PreFlag {
  178.         return PreFlag.ACCEPT;
  179.     }
  180.    
  181.     function randomState() : Object {
  182.         var state:Object = {balls:[]};
  183.         for (i in 0 ... balls.length) {
  184.             state.balls[i] = {};
  185.             state.balls[i].x = Math.random() * (800 - 200) + 100;
  186.             state.balls[i].y = Math.random() * (600 - 200) + 100;
  187.             state.balls[i].r = Math.random() * Math.PI * 2;
  188.             state.balls[i].dx = 1000 * Math.cos(balls[i].rotation);
  189.             state.balls[i].dy = 1000 * Math.sin(balls[i].rotation);
  190.         }
  191.         return state;
  192.     }
  193.    
  194.     function applyState(state:Object) {
  195.         for (i in 0 ... balls.length) {
  196.             balls[i].position.x = state.balls[i].x;
  197.             balls[i].position.y = state.balls[i].y;
  198.             balls[i].rotation   = state.balls[i].r;
  199.             balls[i].velocity.x = state.balls[i].dx;
  200.             balls[i].velocity.y = state.balls[i].dy;
  201.         }
  202.     }
  203.    
  204.     function testOverlap() {
  205.         for (i in 0 ... balls.length) {
  206.             var list:BodyList = space.bodiesInBody(balls[i]);
  207.             for (j in 0 ... list.length) {
  208.                 if (list.at(j) != balls[i] && list.at(j).userData.id != null) {
  209.                     flash.Lib.trace(balls[i].userData.id + " overlaps " + list.at(j).userData.id);
  210.                 }
  211.             }
  212.         }
  213.     }
  214.    
  215.     var textfield:TextField;
  216.     function print(text:String, ?color:Int = 0) {
  217.         if (textfield == null) {
  218.             textfield = new TextField();
  219.             textfield.width = stage.stageWidth;
  220.             textfield.height = stage.stageHeight;
  221.             textfield.wordWrap = true;
  222.             addChild(textfield);
  223.         }
  224.         textfield.text = text;
  225.         textfield.textColor = color;
  226.     }
  227.  
  228.     static function main() {
  229.         flash.Lib.current.addChild(new Main());
  230.     }
  231.    
  232. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement