年末大掃除! 対 謎のcallbackエラー

いやぁクリスマスまであと何日ですかね…

はい茶番はどうでもいいですね。アドカレ過ぎてますけど空いてるとこを埋めさせていただきます。
　

今回はネタを詰める時間もないので、最近あったエラー事例を解決までの道のりをレポート形式で。

<font color="Red">"CgAbBlastPanelOptChangeCallback"</font>このエラーについて。

きっと、ググってたどり着いてきた人ばかりでしょう…


■追記■
<font color="Red">以下の方の記事の方が真に迫ってると思うのでそちらの方を参照していただくのが安全かと思われます。</font>
https://qiita.com/ti_ni_ta/items/bdbf30d0236addb267a2

その上でまだ興味ある方は読み進めていただければと。



解決法だけ知りたい方はさくっと[まとめの項](#解決法まとめ)に飛んじゃってください。


# とにかくエラー出してくるやべぇヤツ

あるとき、あるシーンを開いてみるとこんなエラーが。

　![dispCallBackErr_01.png](https://qiita-image-store.s3.amazonaws.com/0/153835/e53897aa-6c93-3dec-5f26-bb04dad544f1.png)

``` // Error: line 1: Cannot find procedure "CgAbBlastPanelOptChangeCallback". //```

最初は特に気にしなかったのですが、だんだんとこれを頻繁に見かけるように…

TA/TDやってると何気ないエラーも気になります。

というのも、エラーがツールやプラグインによる要因だった場合死活問題だからです。

しかし、それ以前にこのエラーかなり奇妙です。

シーンを開いたときに出るので、シーン依存のエラーかと思いきや…

![dispCallBackErr_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/153835/606548c4-948e-e612-e7da-6684ad8f472f.png)
　

new sceneしても何故か出てくる…

![dispCallBackErr_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/153835/3a169c4c-321b-a77f-db94-26fb72aeba3f.png)　

エラーの量も増えとる…
　
　

# とりあえずググってみる

結果だけ言うとほとんど出てきません。

出てきてもmaいじれよという例ばかり。

となるともう自分で調査するしかないですね。

というわけで、該当シーンをmaで保存して…って**保存できません**。

unknown nodeとかでシーンが汚くてあれやこれやのせいなんですが、

ここら辺はさくっと自分で作っておいたツールできれいにしていざma。

![dispCallBackErr_04.png](https://qiita-image-store.s3.amazonaws.com/0/153835/c7312ad8-9ef5-b132-77d1-29b2f527013b.png)

なんやらかんやらのmelの間に目的の<font color="Red">"CgAbBlastPanelOptChangeCallback"</font>があるようです…

単純じゃなさそうですね。

ちなみに、試しにこの長ったらしいのを消して保存して、再オープンしてみると…

![dispCallBackErr_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/153835/606548c4-948e-e612-e7da-6684ad8f472f.png)
　

<font color="Red">**消えないやんけ！**</font>

すいません。取り乱しました…

いや、本当どういうことなの…

一応念のため**Mayaを再起動**してシーン開いてみると、なんとか消えました。

うーむ、これは記述されていた部分が怪しいのは当たり前として、何か更にありそうですね。
　

# おのれレイアウト保存機能

というわけで、該当記述部分を調べてみると、どうやらシーンのレイアウトを保存している部分のようです。

というわけで、試しにレイアウトを保存する機能をオフってみます。

![dispCallBackErr_06.png](https://qiita-image-store.s3.amazonaws.com/0/153835/fce17c8c-e3ad-3e4f-d10d-5be47eee1766.png)

この状態でシーンを保存してmaを見てみると、**該当部分の記述がちゃんと消えてます**。

これでもう安心ですね！一応シーンを開いて確認してみましょう。

![dispCallBackErr_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/153835/606548c4-948e-e612-e7da-6684ad8f472f.png)

<font color="Red">**消えとらんやんけ！**</font>

どういうこったよ…

正直頭を抱えるしかありません。

思わず、「なんでやねん」とこの世の理不尽に声を出して突っ込んでしまう始末(実話)

またも、ダメ元で**Mayaを再起動**してシーン開いてみると、なんとか消えてました。
　

# もしかして…<font color="DarkOrange">callback</font>

さて、まだ、完全解決には遠いですが、とりあえずの対処は見えてきました。

**・ maで該当部分を消す**
or
**・ レイアウト保存機能を切って再保存**
**　↓**
**・mayaを再起動**

これで一旦の対処はできそうです。

しかし、アーティスト陣に、このエラー出たらmaいじらせて、さらにはmayaを再起動させるのは酷です。

もっと工程少なく対処をしたいです。

というわけで、調査続行。

今まで出てきた条件から推測するに一度このエラーが出るとシーンではなく、**mayaにエラーが残る**様子。

となると、考えられるのは<font color="DarkOrange">scriptJob</font>やその他スクリプトによる<font color="DarkOrange">callback</font>です。

<font color="Red">"CgAbBlastPanelOptChangeCallback"</font>と名前からもあるように、<font color="DarkOrange">callback</font>であるのは一目瞭然なのですが、

さてどこの<font color="DarkOrange">callback</font>なのか。

さらに、エラー部分のmelを解読してみるとどうやらpanelEditorの<font color="DarkOrange">callback</font>というのがわかります。

試しに、一度エラーが出たMayaでpanelを1viewレイアウトから4viewレイアウトに変えてみます。

すると、

![dispCallBackErr_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/153835/606548c4-948e-e612-e7da-6684ad8f472f.png)
　

ヤツが出てきます。どうやら間違いないようです。
　

# その<font color="DarkOrange">callback</font>をぶち壊す

エラーの内容からして、<font color="Red">"CgAbBlastPanelOptChangeCallback"</font>このコマンドあらへんよってことですから、

なんかしら同名の関数を用意してしまえばいいとも言えます。

しかし、そもそもが必要なさそうなものなのにわざわざ用意するのもあれですし、

シーンには残り続けるので根本的な対処にはなりません。

ということで、この<font color="DarkOrange">callback</font>ごと消してしまえば、ma改変、レイアウト機能オフ、再起動しなくても根本的な対処ができそうです。

さて、どうしたものか…

というわけで調理したのがこちらになります。

```
import pymel.core as pm
# ---------------------------------------------------------
# clean up PanelCallback
# ---------------------------------------------------------
def cleanupPanelCallback():
    for item in pm.lsUI(editors=True):
        if type(item) == pm.ui.ModelEditor:
            pm.modelEditor(item, e=True, ec='')
```


まぁ、これは要するに、Maya内のmodelEditorのeditorChanged <font color="DarkOrange">callback</font>を強制的に上書くという力業です。

正直なところスマートではないです。

もしかしたら、editorChangedに消したくない情報が入っているかもだからです。

とはいえ、この<font color="DarkOrange">callback</font>を使うような事項が思いつかなかったので結局こういう形に落ち着きました。

あとは、これをエラーが出たら叩いてもらえればいいので、ワンクリックで解決できるようになります。

一応、試してみると…
　
![dispCallBackErr_07.png](https://qiita-image-store.s3.amazonaws.com/0/153835/5e97da55-c581-0c2a-234a-9329c7f03bac.png)

<font color="Red">**消えとるやんけ！**</font>

よかったです。正直また天丼くらうのかとドキドキしてました。

いやでも、エラーが出る度に叩かせるというのはもやもやします。

絶対叩かない人が出てきます。
　

# 目には目を<font color="DarkOrange">callback</font>には<font color="DarkOrange">callback</font>を

バケモノにはバケモノをぶつけんだよ！という精神で、<font color="DarkOrange">callback</font>には<font color="DarkOrange">callback</font>をぶつけることにします。

正確には、<font color="DarkOrange">callback</font>に<font color="DarkOrange">scriptJob</font>をぶつけます。

maya起動の際に、<font color="DarkOrange">SceneOpened</font>のジョブに対して<font color="Green">cleanupPanelCallback()</font>を叩く<font color="DarkOrange">scriptJob</font>を仕込みます。

本当は<font color="DarkOrange">SceneSaved</font>の時に叩けるといいんですけど、<font color="DarkOrange">SceneSaved</font>の<font color="DarkOrange">scriptJob</font>ってセーブした後に発動するので意味ないのです…

ちなみに、私の場合は既にシーン内の不要プラグインをきれいにする自作のpluginクリーンナップを仕込んでいたので、

これに追記する感じで入れました。
　


# ここがやべぇよやべぇヤツ

さて、一応これにて解決となるのですが、このエラーのやばいとこをまとめておきましょう。

アーティスト目線だと一見エラーが出るだけで実害がないように思えるのですが、そんなことありません。

**〇new sceneしてもエラー**

**〇どんなシーン開いてもエラー**

**〇エラー内包しているシーンを再び開くとエラー増殖**

**〇その状態で無事なシーンを気にせず保存するとそのシーンも感染**

さながら<font color="Red">**ウィルス**</font>です。

これに似た事例として、pluginがないことによるエラーがあります。

ただ、それは該当シーンのオープンだけにエラーが出る状態なので幾分かマシです。(正直それでも感染するので嫌なんですけど)

これを放置すると、他のツールを使ったときに出るエラーがどれか追い難くなり、お手上げとなります。


# 解決法まとめ

#### A.手作業で解決
**1. maで<font color="Red">"CgAbBlastPanelOptChangeCallback"</font>が記述されている部分を含むコマンドを削除する。**
もしくは、
**1. レイアウト保存機能を切って再保存**
![dispCallBackErr_06.png](https://qiita-image-store.s3.amazonaws.com/0/153835/fce17c8c-e3ad-3e4f-d10d-5be47eee1766.png)

**2. Mayaを再起動。**

#### B.スクリプトで解決

```
import pymel.core as pm
# ---------------------------------------------------------
# clean up PanelCallback
# ---------------------------------------------------------
def cleanupPanelCallback():
    for item in pm.lsUI(editors=True):
        if type(item) == pm.ui.ModelEditor:
            pm.modelEditor(item, e=True, ec='')
cleanupPanelCallback()
```

これを実行します。

徹底策として<font color="DarkOrange">SceneOpened</font>のジョブに対して<font color="Green">cleanupPanelCallback()</font>を叩く<font color="DarkOrange">scriptJob</font>を仕込んでおきます。
　

# 根本原因の予測

さて、これが起きた要因なんですが、正直確定的な証拠がないので推測しかありません。

どうやら、Mayaのバージョンが怪しいもので保存されたシーンを、現行バージョンで読んだときに残るっぽいです。

今のところ、今の仕事のプロジェクト内で作られたものに関しては起きておらず、

外部からのデータでのみ起きていました。

なのでそうではないかと。

しかし、何度も言いますが、あくまで推測ですのであしからず。


# おわりに

まぁ、あんまりきれいな解決方法ではありませんが、

一度きれいにしてしまえば正常な環境では起きない問題なので、とりあえずはこの対処で満足しています。

ちなみにこの解決方法

```// Error: line 1: Cannot find procedure "onModelChange3dc". //```

こういった、別のpanel <font color="DarkOrange">callback</font>系エラーにも効きます。

これはなんかのハードウェアシェーダー系のpluginで呼んでると出るようになるみたいです。

例に挙げたpluguinごみエラーとの併用系エラーですね。



というわけで、シーンエラーはほっとかないでおきましょうというお話でした。

疑問に思ったら近くのTA/TDに聞いてみてください。

stresslessなシーンの作成に役立つはずです。


ということでここまで(:3ﾉｼ　)ﾍ
　
　
　
　
　※免責事項※
本記事内で公開しているコードの安全性について、当方は一切の保証を与えておりません。
これらのコードを使用したことによって引き起こる損害に対し、当方は一切責任を負うものではありません。
自己責任でご使用ください。