showKey(duration) {
    if (this._showKeyPromise == null) {
      // cancel hiding key
      if (this._stopShowingKeyPromise != null) {
        this._stopShowingKeyPromise.cancel();
        this._stopShowingKeyPromise = null;
      }

      // create/show key
      this._showKeyPromise = this.whenRequiredResourcesReady().then((requestId) => {
        if (!this.getAreResourcesValid(requestId)) return; // load invalidated or resources changed

        return new Promise((resolve) => {
          this._showKeyPromise = null;

          // key sprite
          if (this._lootCrateKeySprite == null) {
            this._lootCrateKeySprite = BaseSprite.create(this._getLootCrateKeySpriteIdentifier());
            this._lootCrateKeySprite.setVisible(false);
            this._lootCrateKeySprite.setRotation(90.0);
            this.addChild(this._lootCrateKeySprite, this._zOrderBehindCrate);
          }

          // animate key in
          const contentSize = this.getContentSize();
          const centerPosition = this.getCenterPosition();
          this._lootCrateKeySprite.setPosition(centerPosition.x, centerPosition.y - contentSize.height * 0.5 - this._lootCrateKeySprite.getContentSize().width * 0.5 - 30.0);
          this._lootCrateKeySprite.fadeTo(duration, 255.0, () => {
            resolve();
          });
        })
          .catch((error) => { EventBus.getInstance().trigger(EVENTS.error, error); });
      })
        .cancellable()
        .catch(Promise.CancellationError, () => {
          Logger.module('APPLICATION').log('MysteryCrateNode -> key show promise chain cancelled');
        });
    }
    return this._showKeyPromise;
  }
Shows key for crate.
@param {Number} [duration=0.0]
@returns {Promise}