Advertisement
PierrotLL

Nape 1009 reproducible (as3)

Nov 30th, 2017
367
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package {
  2.  
  3. import flash.display.Sprite;
  4. import flash.events.Event;
  5. import flash.text.TextField;
  6. import flash.utils.getTimer;
  7. import flash.utils.setTimeout;
  8. import nape.Config;
  9. import nape.callbacks.CbType;
  10. import nape.callbacks.InteractionType;
  11. import nape.callbacks.PreCallback;
  12. import nape.callbacks.PreFlag;
  13. import nape.callbacks.PreListener;
  14. import nape.phys.Body;
  15. import nape.phys.BodyList;
  16. import nape.phys.BodyType;
  17. import nape.phys.Material;
  18. import nape.shape.Circle;
  19. import nape.shape.Polygon;
  20. import nape.shape.Shape;
  21. import nape.space.Space;
  22. import nape.util.BitmapDebug;
  23.  
  24. public class Main extends Sprite {
  25.    
  26.     /**
  27.      * README
  28.      * There is two ways to use this sample:
  29.      * - To quickly reproduce the error: call play(json) with one of the jsons given as examples.
  30.      * - 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)
  31.      * Do not call play(json) AND bruteforce() in the same instance.
  32.      *
  33.      * The preCollisionListener seems to be essential to get the error, even if it always returns ACCEPT.
  34.      *
  35.      * The crash is from zpp_nape/Space.cx line 2251: callbackset.remove_arb(arb);
  36.      * It is a TypeError #1009 (callbackset is null).
  37.      * It seems to always happen on a very slow collision, when some bodies overlap in the initial state.
  38.      */
  39.    
  40.     public var space:Space;
  41.     public var balls:Vector.<Body>;
  42.    
  43.     public var state:Object;
  44.     public var iterations:int;
  45.    
  46.    
  47.     public function Main() {
  48.         super();
  49.         if (stage != null) init(null);
  50.         else addEventListener(Event.ADDED_TO_STAGE, init);
  51.     }
  52.    
  53.     private function init(e:Event) : void {
  54.         removeEventListener(Event.ADDED_TO_STAGE, init);
  55.        
  56.         Config.linearSleepThreshold = 300 * 0.2;
  57.         Config.angularSleepThreshold = 100 * 0.4;
  58.        
  59.         space = createSpace();
  60.        
  61.         var field:Body = createField();
  62.         field.space = space;
  63.        
  64.         balls = new Vector.<Body>();
  65.         for (var i:int = 0 ; i < 10 ; i++) {
  66.             balls[i] = createBall();
  67.             balls[i].space = space;
  68.         }
  69.        
  70.         /*
  71.          * Each json describe one case that makes nape crash
  72.          */
  73.        
  74.         /* AS3 with nape-dev.swc or nape-release.swc from napephys.com */
  75.         //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}]};
  76.         //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}]};
  77.         //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}]};
  78.         //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}]};
  79.        
  80.         /* Haxe with nape 2.0.20 from haxelib (also crashes in AS3 with self-build nape-release-2.0.20.swc) */
  81.         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}]};
  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":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}]};
  84.        
  85.         play(json);
  86.        
  87.        
  88.         /*
  89.          * Method used ot find a new test case.
  90.          * To use, comment "play(json)" and uncomment "bruteforce()"
  91.          * It runs iterations in background until the error happens,
  92.          * then displays the initial state needed to reproduce the case with play().
  93.          * Some cases found with bruteforce() doesn't make nape crash again in play(), don't know why.
  94.          */
  95.         //bruteforce();
  96.     }
  97.    
  98.     public function play(state:Object) : void {
  99.         applyState(state);
  100.         testOverlap();
  101.         var debug:BitmapDebug = new BitmapDebug(stage.stageWidth, stage.stageHeight);
  102.         addChild(debug.display);
  103.         addEventListener(Event.ENTER_FRAME, function(e:Event) : void {
  104.             space.step(0.016);
  105.             debug.clear();
  106.             debug.draw(space);
  107.             debug.flush();
  108.         });
  109.     }
  110.    
  111.     public function bruteforce() : void {
  112.         var start:int = getTimer();
  113.         while (getTimer() - start < 1000) {
  114.             if (isSleeping()) {
  115.                 state = randomState();
  116.                 applyState(state);
  117.                 iterations++;
  118.             }
  119.             try {
  120.                 space.step(0.016);
  121.             } catch (e:Error) {
  122.                 print(JSON.stringify(state), 0xff0000);
  123.                 return;
  124.             }
  125.         }
  126.         print(iterations + "");
  127.         setTimeout(bruteforce, 0);
  128.     }
  129.    
  130.    
  131.    
  132.     private function createSpace() : Space {
  133.         var space:Space = new Space();
  134.         space.worldAngularDrag = 50 * 0.015;
  135.         // preCollisionListener always return ACCEPT, but is essentiel to makes nape crash.
  136.         // Without this useless listener, nape doesn't crash.
  137.         space.listeners.add(new PreListener(InteractionType.COLLISION, CbType.ANY_BODY, CbType.ANY_BODY, preCollisionListener, 0, true));
  138.         return space;
  139.     }
  140.    
  141.     private function createField() : Body {
  142.         var w:int = 800;
  143.         var h:int = 600;
  144.         var t:int = 50;
  145.         var material:Material = new Material();
  146.         material.elasticity = 1;
  147.         material.density = 50;
  148.         var body:Body = new Body(BodyType.STATIC);
  149.         body.shapes.add(new Polygon(Polygon.rect(0, 0, w, t), material));
  150.         body.shapes.add(new Polygon(Polygon.rect(0, h - t, w, t), material));
  151.         body.shapes.add(new Polygon(Polygon.rect(0, t, t, h - 2 * t), material));
  152.         body.shapes.add(new Polygon(Polygon.rect(w - t, t, t, h - 2 * t), material));
  153.         var fluid:Shape = new Polygon(Polygon.rect(0, 0, w, h));
  154.         fluid.fluidEnabled = true;
  155.         fluid.fluidProperties.viscosity = 0.57;
  156.         body.shapes.add(fluid);
  157.         return body;
  158.     }
  159.    
  160.     private var nextBallId:int;
  161.     private function createBall() : Body {
  162.         var material:Material = new Material();
  163.         material.elasticity = 1;
  164.         material.density = 5;
  165.         var body:Body = new Body(BodyType.DYNAMIC);
  166.         body.isBullet = true;
  167.         body.shapes.add(new Circle(40, null, material));
  168.         body.userData.id = nextBallId++;
  169.         return body;
  170.     }
  171.    
  172.     private function isSleeping() : Boolean {
  173.         return space.liveBodies.length == 0;
  174.     }
  175.    
  176.     private function preCollisionListener(c:PreCallback) : PreFlag {
  177.         return PreFlag.ACCEPT;
  178.     }
  179.    
  180.     private function randomState() : Object {
  181.         var state:Object = {balls:[]};
  182.         for (var i:int in balls) {
  183.             state.balls[i] = {};
  184.             state.balls[i].x = Math.random() * (800 - 200) + 100;
  185.             state.balls[i].y = Math.random() * (600 - 200) + 100;
  186.             state.balls[i].r = Math.random() * Math.PI * 2;
  187.             state.balls[i].dx = 1000 * Math.cos(balls[i].rotation);
  188.             state.balls[i].dy = 1000 * Math.sin(balls[i].rotation);
  189.         }
  190.         return state;
  191.     }
  192.    
  193.     private function applyState(state:Object) : void {
  194.         for (var i:int in state.balls) {
  195.             balls[i].position.x = state.balls[i].x;
  196.             balls[i].position.y = state.balls[i].y;
  197.             balls[i].rotation   = state.balls[i].r;
  198.             balls[i].velocity.x = state.balls[i].dx;
  199.             balls[i].velocity.y = state.balls[i].dy;
  200.         }
  201.     }
  202.    
  203.     private function testOverlap() : void {
  204.         for (var i:int in balls) {
  205.             var list:BodyList = space.bodiesInBody(balls[i]);
  206.             for (var j:int = 0 ; j < list.length ; j++) {
  207.                 if (list.at(j) != balls[i] && list.at(j).userData.id != null) {
  208.                     trace(balls[i].userData.id + " overlaps " + list.at(j).userData.id);
  209.                 }
  210.             }
  211.         }
  212.     }
  213.    
  214.     private var textfield:TextField;
  215.     private function print(text:String, color:uint = 0) : void {
  216.         if (textfield == null) {
  217.             textfield = new TextField();
  218.             textfield.width = stage.stageWidth;
  219.             textfield.height = stage.stageHeight;
  220.             textfield.wordWrap = true;
  221.             addChild(textfield);
  222.         }
  223.         textfield.text = text;
  224.         textfield.textColor = color;
  225.     }
  226.    
  227. }
  228.    
  229. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement