diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2e9dc9..e82aad72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,10 @@ ## 0.5.3 - unreleased - Fix INTERNAL ERROR in `FastLSolve.solveL1Straight()` caused by bug in `DLCP.solve1()`. [#133](https://github.com/tzaeschke/ode4j/issues/133) -- Fix formatting of degub/info/error message. +- Fix formatting of debug/info/error message. [#135](https://github.com/tzaeschke/ode4j/issues/135) +- QOL: allow calling destroy() multiple times. + [#139](https://github.com/tzaeschke/ode4j/pull/139) ## 0.5.2 - 2023-10-07 - Fix DVector3.cross() returning always 0. [#128](https://github.com/tzaeschke/ode4j/issues/128) diff --git a/core/src/main/java/org/ode4j/ode/internal/DDestructible.java b/core/src/main/java/org/ode4j/ode/internal/DDestructible.java index aa399a2b..5448d09a 100644 --- a/core/src/main/java/org/ode4j/ode/internal/DDestructible.java +++ b/core/src/main/java/org/ode4j/ode/internal/DDestructible.java @@ -65,11 +65,11 @@ protected DDestructible() { */ protected void DESTRUCTOR() { if (isDestructed) { - System.err.println("WARNING Object was already destructed."); - new RuntimeException().printStackTrace(); + // System.err.println("WARNING Object was already destructed."); + // new RuntimeException().printStackTrace(); + ErrorHdl.dMessage(0, "WARNING Object was already destructed."); } isDestructed = true; - //System.err.println("CCC"); } diff --git a/core/src/main/java/org/ode4j/ode/internal/DxBody.java b/core/src/main/java/org/ode4j/ode/internal/DxBody.java index 71ce8526..296205f0 100644 --- a/core/src/main/java/org/ode4j/ode/internal/DxBody.java +++ b/core/src/main/java/org/ode4j/ode/internal/DxBody.java @@ -197,6 +197,10 @@ public static DxBody dBodyCreate (DxWorld w) public void dBodyDestroy () { //dAASSERT (b); + // ode4j special: We set world=null, so we can check here + if (world == null) { + return; // already destroyed + } // all geoms that link to this body must be notified that the body is about // to disappear. note that the call to dGeomSetBody(geom,0) will result in @@ -223,6 +227,9 @@ public void dBodyDestroy () removeObjectFromList (); world.nb--; + // ode4j special: We set world=null, so we can check precondition in destroy() + world = null; + // delete the average buffers //TZ nothing to do // if(average_lvel_buffer!= null) diff --git a/core/src/test/java/org/ode4j/ode/TestIssue0139_MultiDestroy.java b/core/src/test/java/org/ode4j/ode/TestIssue0139_MultiDestroy.java new file mode 100644 index 00000000..e2f01438 --- /dev/null +++ b/core/src/test/java/org/ode4j/ode/TestIssue0139_MultiDestroy.java @@ -0,0 +1,77 @@ +/************************************************************************* + * * + * Open Dynamics Engine 4J, Copyright (C) 2009-2014 Tilmann Zaeschke * + * All rights reserved. Email: ode4j@gmx.de Web: www.ode4j.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file ODE-LICENSE-BSD.TXT and ODE4J-LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT, ODE-LICENSE-BSD.TXT and ODE4J-LICENSE-BSD.TXT for more * + * details. * + * * + *************************************************************************/ +package org.ode4j.ode; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Issue #133: ODE INTERNAL ERROR in FastLSolve.solveL1Straight(). + */ +public class TestIssue0139_MultiDestroy { + + private final DContactBuffer contacts = new DContactBuffer(4); + private DWorld world; + private DJointGroup contactGroup; + + @Before + public void beforeTest() { + OdeHelper.initODE2(0); + } + + @After + public void afterTest() { + OdeHelper.closeODE(); + } + + @Test + public void test() { + double ballRadius = 5.0; + double ballMass = 23.0; + contactGroup = OdeHelper.createJointGroup(); + world = OdeHelper.createWorld(); + world.setGravity(0, 0, -9.81); + DSpace space = OdeHelper.createSimpleSpace(); + DBody ballBody = OdeHelper.createBody(world); + DGeom ballGeom = OdeHelper.createSphere(space, ballRadius); + ballGeom.setBody(ballBody); + DMass m = OdeHelper.createMass(); + m.setSphereTotal(ballMass, ballRadius); + ballBody.setMass(m); + DPlane plane = OdeHelper.createPlane(space, 0, 0, 1, 0); + + plane.destroy(); + space.destroy(); + world.destroy(); + ballBody.destroy(); + ballGeom.destroy(); + + // Test duplicate calls to destroy() + plane.destroy(); + space.destroy(); + world.destroy(); + ballBody.destroy(); + ballGeom.destroy(); + } +}