showInspectCard(sdkCard, node) {
    const currentSdkCard = this._inspectCardNode.getSdkCard();
    if (!this._player.getFollowupCard() && (currentSdkCard == null || currentSdkCard !== sdkCard)) {
      // stop showing previous
      this.stopShowingInspectCard(currentSdkCard);

      // show new
      if (sdkCard != null) {
        const isInspectingNode = node instanceof cc.Node;
        const isInspectingEntityNode = isInspectingNode && node instanceof EntityNode;
        const isInspectingBottomDeckCardNode = isInspectingNode && node instanceof BottomDeckCardNode;
        const isInspectingArtifactNode = isInspectingNode && node instanceof ArtifactNode;
        const isInspectingBattleLogNode = isInspectingNode && node instanceof BattleLogNode;
        const isInspectingSignatureCardNode = isInspectingNode && node instanceof SignatureCardNode;
        let showBaseState = false;
        let actionToShowStateFor;
        let actionEventTypeToShowStateFor;
        if (isInspectingArtifactNode) {
          // always show artifact nodes in base state
          // this is because the artifact's modifiers are active
          // but the artifact itself is not
          // so the state will always be as of when the artifact is played
          // which we don't want for inspecting artifact nodes
          showBaseState = true;
        } else if (isInspectingBattleLogNode) {
          if (!sdkCard.getActionStateRecord().getHasRecordedStateForActions()) {
            // on reconnect, action state record gets reset
            // battle log nodes should just show base state in this case
            showBaseState = true;
          } else {
            // show battle log node state at the action it was entered
            actionToShowStateFor = node.getAction();
            actionEventTypeToShowStateFor = EVENTS.update_cache_action;
          }
        }
        let showAsIfOwnedByPlayer2 = sdkCard.isOwnedByPlayer2();
        if (!showAsIfOwnedByPlayer2 && sdkCard.isOwnedByGameSession()) {
          // when owned by game session, inspect should always be on side of my player
          if (this.getMyPlayer() === this.getPlayer2()) {
            showAsIfOwnedByPlayer2 = true;
          }
        }

        // show inspect
        // inspect triggers rebuild so it must be done before using content size
        this._inspectCardNode.showInspect(sdkCard, showBaseState, actionToShowStateFor, actionEventTypeToShowStateFor, showAsIfOwnedByPlayer2, null, this.getShouldShowCardInstructionals());
        if (sdkCard.getReferencedCardData()) {
          referencedCard = SDK.GameSession.getInstance().createCardForIdentifier(sdkCard.getReferencedCardData().id);
          referencedCard.setOwner(sdkCard.getOwner());
          this._referencedCardNode.showInspect(referencedCard, true, actionToShowStateFor, actionEventTypeToShowStateFor, showAsIfOwnedByPlayer2, null, this.getShouldShowCardInstructionals());
        }

        const cardContentSize = this._inspectCardNode.getCardContentSize();

        // calculate base position
        let baseInspectPosition;
        if (isInspectingBottomDeckCardNode) {
          // position at a node in hand
          baseInspectPosition = UtilsEngine.getGSINodeCenterScreenPosition(node);
          baseInspectPosition.y += CONFIG.TILESIZE * 0.25;
        } else if (isInspectingArtifactNode) {
          // position at off board inspect location
          if (showAsIfOwnedByPlayer2) {
            // player 2
            baseInspectPosition = UtilsEngine.getPlayer2InspectOffBoardCardPosition();
          } else {
            // player 1
            baseInspectPosition = UtilsEngine.getPlayer1InspectOffBoardCardPosition();
          }
        } else if (isInspectingBattleLogNode) {
          // position at battle log node using current stack matrix
          baseInspectPosition = UtilsEngine.getGSINodeCenterScreenPosition(node);
          baseInspectPosition.x += CONFIG.BATTLELOG_ENTRY_SIZE * 0.5;
        } else {
          // position in fixed player inspect locations
          if (showAsIfOwnedByPlayer2) {
            // player 2
            baseInspectPosition = UtilsEngine.getPlayer2InspectCardPosition();
          } else {
            // player 1
            baseInspectPosition = UtilsEngine.getPlayer1InspectCardPosition();
          }
          if (isInspectingSignatureCardNode) {
            // position below signature card node
            baseInspectPosition.y -= node.getContentSize().height * 0.72;
          }
        }

        let inspectX;
        let inspectY;

        // inspect positions
        if (isInspectingBottomDeckCardNode) {
          // position at a node in hand
          const modifiersContentSize = this._inspectCardNode.getModifiersContentSize();
          inspectX = baseInspectPosition.x;
          inspectY = baseInspectPosition.y + cardContentSize.height * 0.5 + modifiersContentSize.height;
        } else if (isInspectingBattleLogNode) {
          // position at battle log node
          inspectX = baseInspectPosition.x + cardContentSize.width * 0.5;
          // TODO: remove this top/bottom code when player frames are migrated into engine
          inspectY = Math.min(this._battleLog.getBattleLogTop() - cardContentSize.height * 0.5, Math.max(this._battleLog.getBattleLogBottom() + cardContentSize.height * 0.5, baseInspectPosition.y));
        } else {
          // position in fixed player inspect locations
          if (showAsIfOwnedByPlayer2) {
            // player 2
            inspectX = baseInspectPosition.x - cardContentSize.width * 0.5;
            inspectY = baseInspectPosition.y - cardContentSize.height * 0.5;
          } else {
            // player 1
            inspectX = baseInspectPosition.x + cardContentSize.width * 0.5;
            inspectY = baseInspectPosition.y - cardContentSize.height * 0.5;
          }
        }

        // ensure card itself doesn't go outside screen
        inspectX = Math.max(Math.min(inspectX, UtilsEngine.getGSIWinRight() - cardContentSize.width * 0.5), UtilsEngine.getGSIWinLeft() + cardContentSize.width * 0.5);
        inspectY = Math.max(Math.min(inspectY, UtilsEngine.getGSIWinTop() - cardContentSize.height * 0.5), UtilsEngine.getGSIWinBottom() + cardContentSize.height * 0.5);

        // ensure meta content doesn't go outside screen
        if (this._inspectCardNode.getKeywordsShowing() && this._inspectCardNode.getHasKeywords()) {
          // keywords
          const cardKeywordsContentSize = this._inspectCardNode.getKeywordsContentSize();
          if (this._inspectCardNode.getKeywordsShowingOnLeft()) {
            if (inspectX - cardContentSize.width * 0.5 - cardKeywordsContentSize.width < UtilsEngine.getGSIWinLeft()) {
              // show to the right
              this._inspectCardNode.showKeywordsOnRight();
            }
          } else if (inspectX + cardContentSize.width * 0.5 + cardKeywordsContentSize.width > UtilsEngine.getGSIWinRight()) {
            // show to the left
            this._inspectCardNode.showKeywordsOnLeft();
          }
        }

        // set final inspect position
        this._inspectCardNode.setPosition(inspectX, inspectY);

        const spacing = this._inspectCardNode.getCardContentSize().width * 1.5;
        if (inspectX + spacing < UtilsEngine.getGSIWinRight()) {
          this._referencedCardNode.setPosition(inspectX + spacing, inspectY);
        } else {
          this._referencedCardNode.setPosition(inspectX - spacing, inspectY);
        }

        this.getEventBus().trigger(EVENTS.inspect_card_start, { type: EVENTS.inspect_card_start, card: sdkCard });
      }
    }
  }
Starts inspecting a card
@param {SDK.Card} sdkCard card to show
@param {Node} node node to show card over