最近のアドオン制作環境について2019改訂版
adventar.org
このエントリーはSimutrans Advent Calendar 2019 7日目の記事になります
学会補足資料:アドオンを効率的に作る - less /home/honoka/simutrans/simplay.logs
以前、このようなエントリーを補足記事として書いた事がある。今回はその記事に対して進歩やら技術的な紹介に対する自分の返答であり、まとめであるかもしれない。
そして、内容については初心者お断りに近くなるのでLinuxの簡単な操作や軽いプログラミングの知識があると読みやすいと思う。わからないところは随時調べながら読むか、以下のリンクからTwitterにて質問を受け付けるので気軽に聞いて欲しい。なるべく平易な表現を用いるようにはしたいが、時々難解な表現を用いる事があるのでそのあたりは留意してもらえると幸いである。
基本的な制作フロー
まずはアドオン制作のフローについて考えてみよう、以下のプロセスを経て1つのアドオンが誕生する。
これはこの記事を書いている筆者自身のパターンなので他にもあるかもしれない、ここでは架空の新産業セットを立ち上げる前提で話を進めることにする。
- 基本要件定義
- 産業の定義(種類・流れ)
- 貨物の定義(名前・カテゴリー・積載可能車両等)
- 要件定義を受けて各種ファイルを作成
- 各種ファイルがまとまったらpak化
- テスト環境に導入して各種確認作業
以上6(7)個の作業があるのだが、datやpngの作成はまだしも更新は何度もありその度にpak化を行っていた場合には古いデータのままテストして更新結果が反映されていなくてうんうんと唸ったりすることが~~実際にあった~~あるので自動化出来る要素は自動化しこの様な事故を減らしたいと思う。
次から具体的な実装例について上げていく。
pak化
先のパターンにおいて
各種ファイルがまとまったらpak化
と書いているが半分間違いとも言える、実態としては各pak毎にdatとpngが揃った時点で既にpak化を始めてしまうからだ。そして必要なファイルは揃った事や更新を検知したい、その為にLinux環境下という限定的な条件があるがinotifyというライブラリを用いる必要が出てくる。これは単独でも動作させられるがツールとして使おうとしたら各種機能が必要となってくる、そこで自分の環境下においてはRubyにてpak化のツールを作った。最近のカジュアルな開発のトレンドとして継続的インテグレーションというのがあるが、これに近いものをシンプルに実装して運用している事となる。
少し話を脱線して先程登場した""継続的インテグレーション""についての話をさせてもらいたい、これについてはCI – 継続的インテグレーションとは? | tracpath:Worksより次の文章を引用させていただくこととする
継続的インテグレーションとは、ソフトウェア開発のプロセスを自動化することで開発者がソースコードをコミットし、共有しているリポジトリにマージされることでビルドとテストが自動的に実行される手法である。
継続的インテグレーションにより、ソフトウェアのバグを早期に発見し対処することができ、チーム開発のスピードを上げ、コードの品質を保証することが可能である。
何を言っているかわからない人もいる気がするのでアドオン制作に置き換えながらざっくりとした解説を挟ませてもらう。最初にプロセスの自動化とあるがmakeobjを通したpakを生成する作業である、先に自動化出来る要素と挙げているがこのpak化という作業について言及している。次にソースコードのコミットとあるがソースコードについてはdatもしくはpngを想定していただき、コミットについてはそのdatもしくはpngを保存すると考えてほぼ差し支えないだろう。*2
このざっくりとした説明から何を言いたいかわかってくれたら幸いである、Twitter等で問い合わせは受け付けます。
自動化というがディレクトリの構成やファイル名に一定の規則が適応されることになっている、基本的にはdatとpng名のファイル名は同一としたり出来たpakファイル特定のディレクトリに入れさせたりするなどである。
特定の名前を付けた空ファイルをディレクトリに入れておくと、そのディレクトリの中でpngもしくはdatが更新されたらとしてもpak化を行わないなどである。
画像を切り出したい
さて、ここまででpak化が自動化出来てはい終わりとしたいがまだ実装したものがある画像切り出しである。2枚画像が並んでいるが1枚めがソースになる画像であり、2枚目が1タイル(64px x 64px)の範囲内に収まるように切り出した画像だ。どこぞのホームセンターっぽいとか言われたら御名答と答えよう。それはさておき、書き出した画像も自動的に切り出したいという要求が生まれてくる。アドオン制作のツールの一つにTileCutterという画像を切り出すGUIツールが有るのだが、画像を書き出した後に別ツールを操作して更にpak化用の画像を書き出すというのはどうにも~~面倒~~スムーズにアドオンを制作したいと思う。しかし、画像を切り出すとは言ってもサイズや切り出すサイズ等の問題が出て来てしまう。それをどうにかして力技に近い感じで解決した。
pak化について少し戻るが、そのツールにはpak化以外にも切り出しツールとの連携も機能として搭載している。切り出すpngとサイズを設定したファイルを読み込み、該当するpngが更新された時に切り出し処理が走る簡単な仕組みだ。
少し便利となっているがやはり手動でやるべき事は残ってはいる、設定ファイルを作ることだ。これがないといくら画像を書いた所で切り出してはくれない。
これからの展望
実は既に新しいツールの開発に着手している。鉄道車両ヲ制作する上で苦労するのが連結設定である、1文字間違えるだけでも車庫内で連結できないなど相当シビアで有る*3。
dat更新時にこれを通して問題が出たら通知を出そうとかそういう展開を考えている、他にもまだアイデア程度だが実装したいものは用意している。
最後に
今年もカレンダーに参加して技術的な話をさせていただきました、小難しいを通り越してますがまぁそういうことです。
この記事の投稿日基準で明後日にはまた自分のエントリーとして軽く景観についてと語る予定です。
Simutransはいいぞ
アドオン自作はいいぞ
ツール自作はいいぞ
Simutrans誕生20周年に寄せて(微修正)
本日3月6日はSimutransがこの世に公開されて20周年です、もうシムトラ自体は成人を迎えたと言ってもいいでしょう。
自分は102から始めたのですが当時と比較してもかなり変わっています、Standard版を基準としても緩急坂という2つの段階を持つ坂が実装されたり(120以降)、車庫内の検索から24両に固定された編成長を自在に設定ファイルで変更出来るなど相当な変化です。
アドオンにおいても普段プレイしているpak64を基準としますがテヌキ車両さんを筆頭に国内外の古今東西の鉄道車両や飛行機等乗り物系から箱積の新バリエーションが増えていっています、その傾向は他に主流であるpak128や同jpにおいても同様であり多数の作者がアドオンを増やしてより豊かな世界観を彩る為に日々制作して公開し続けています。
また、普段プレイしているのはOTRPという道路交通に手を加えたバージョンですがそれもまた日々進化している気がします
道路の通行方向指定や追い越し設定からOTRPが始まりましたがStandard版では取り入れにくい機能を取り込んで痒いところに手が届くという表現がぴったりなものと化しています、現在は増解結を実装しようと開発者であるhimeshiさんやshingoshoriさんが奮闘しており自分たちプレイヤー側はバグなどの報告でささやかながら貢献している気がします。
短い乱文となりましたが、これからもStandardを筆頭にした本体には機能拡張を期待するとともにアドオン作成に関わる方々には感謝を込めて今回のエントリーを締めたいと思います。
補完資料: 貨物運賃を計算したい(120.4〜?)
このエントリーは以下の環境にて実証を行いました、他の環境では数値が変化する可能性が有りますのでご容赦ください。
仮に参考にして不都合が生じてもこのエントリーを書いた人間は責任を一切負いません、そしてC言語はポインタで投げ捨てた初心者なので必要な箇所しか読んでいません。
- 本体:120.4 nightly Revision 8646 with OTRP
- pak: pak.nippon
ソースコードを読み解く時はVSCodeを使うと簡単に読み解けるので導入を強くおすすめします、なおシムトラのソースコードとVSCode導入は一切サポートしません。
貨物運賃はどうやって出すの?
上の式はSimutransのソースファイルの一つであるgoods_stats_t.ccというファイルの以下の行から導くことが出来ます。
このソースは一覧表の中にある貨物一覧において貨物1つごとの種類や運賃等を算出や描画処理を行うファイルとなります。
const sint32 grundwert128 = (sint32)wtyp->get_value() * welt->get_settings().get_bonus_basefactor(); // bonus price will be always at least this const sint32 grundwert_bonus = (sint32)wtyp->get_value()*(1000l+(bonus-100l)*wtyp->get_speed_bonus()); const sint32 price = (grundwert128>grundwert_bonus ? grundwert128 : grundwert_bonus); money_to_string( money_buf, price/300000.0 );
このソースの断片からではpriceという変数を出すためにはgrandwert_bonusという値の計算が必要になります、その値の計算には何やら面倒な式が出てきていますね。
valueとspeed_bonusは先日のエントリーで貨物のdatについて書いた時に説明しているので割愛します、
bonusはどこから来るの
ここで先程開いたgoods_stats_t.ccの少し上を見ると何やら怪しい関数が出てきますね
void goods_stats_t::update_goodslist( uint16 *g, int b, int l ) { goodslist = g; bonus = b; listed_goods = l; set_size( scr_size(BUTTON4_X + D_BUTTON_WIDTH + 2, listed_goods * (LINESPACE+1) ) ); }
貨物のリストを更新する関数ですが2つ目の引数であるbは内部でbonusに代入されていますね、ここでbonusはupdate_goodslistで値が設定されることはわかってもその値はどこから来るのかはわかりません。
では、その値をどこから引っ張るのかと言うとファイルを変えてgoods_frame_t.ccの中に答えの糸口があります。
//関係ないので省略 /** * This variable defines the current speed for bonus calculation * @author prissi */ sint16 goods_frame_t::relative_speed_change=100; //関係ない処理のため省略 void goods_frame_t::sort_list() { // 種別単位の速度ボーナス設定処理のため省略 goods_stats.update_goodslist( good_list, relative_speed_change, n ); }
先程出てきたupdate_goodslistという関数がここで登場していますね、その値にはrelative_speed_changeという変数が登場しますがどういう値を入れればいいかこの関数を見ただけではわかりませんね。
ですが最初の方に必要になる数字が代入されています、コメントを読むにボーナス計算に必要なスピードが設定します。
ここで100という値がrelative_speed_changeに入ることがわかり、それがbonusという変数の値として代入されることがわかりました。
bonusに入る値がわかったので実際にゲーム内における運賃を計算していきましょう、以下の条件を計算式に割り当てます。
- value: 180
- speed_bonus: 40
実際に計算した結果が以下のとおりです
この数値は画像中にある小口荷物という貨物に対してdatにて定義した数値をそのまま流用して計算しました
obj=good name=Delivery_Box(Small) metric=box catg=1 value=180 weight_per_unit=1 speed_bonus=40
最後に
来年もよしなに(雑)
Simutransに新たな産業を生み出したい人向けの雑記
このエントリーは以下のAdventCalenderへの参加記事となります
adventar.org
Simutransを長くプレイしているうちにアドオン制作やMIDI編集に本体改造まで始める気がしますが、その中のアドオン制作から産業を作る事に重点を置きたいと思います。
既存の産業に少しだけ手間を加えたい、全く新しい産業ネットワークを作りたいと思った貴方は必見です(多分
今回は既に筆者が公開している宅配便産業のデータを用いて産業のフローから制作課程までを解説します、以下にGithubへのリンクを貼り付けておきますので必要に応じて見ていただけると幸いです。
産業と貨物の流れを定義しよう
先程貼ったgithubのリポジトリから引っ張ってきました、これが今回参考にする宅配便産業の大まかな流れになります。同一の名前の産業にそれぞれ発送と配送がついていますがどうしてでしょう、一つづつ流れに関係する貨物や産業を見ていきます
まずは起点として営業所(発送)という産業を定義した上で小口荷物の発生が設定されました、この小口荷物とは何かというと画像のような箱を定義しています。本来ならば各家庭からの集配も産業として行うべきなのですがシムトラの仕様と多少の簡略化から、荷物の発送には営業所(発送)という産業へ自分で持ち込む必要が生まれています。
この小口荷物達は営業所へ置いておくだけではいつまでも配送してほしい場所へ一歩も動くことが出来ません。数個の営業所間同士で荷物をやり取りしても産業の流れとしては成立してしまいますが、ここもシムトラ的に産業のネットワークを作るのが面倒だと思います。そこで荷物を集約する設備として地区物流センター(配送)が登場します。10数個以上の営業所同士を筆者はやる気が全く無いですが直接繋ぐ人もいるかもしれません、ですが1つのセンターを結節点として経由するほうが産業ネットワークもスマートになりますよね。
話をやや脱線させますが、この記事を読んでいる方々は地理に明るいと信じてますので次のシチュエーションを想像してみてください。「あなたは飛行機に乗って新千歳空港に降り立ったところです。ここから旭川へ向かうとしたらどのようなルートを取りますか?」
新千歳空港に旭川行きという表示はありません、あるのは札幌もしくは以西の駅のみです。どうしたらここから旭川へ向かえると思いますか? 札幌でカムイやライラックと言った旭川行きの(もしくは経由する)特急列車に乗るのが常識的な正解です。はまなすで北海道へ来た人のように新札幌からダッシュで函館本線の森林公園へ向かうという乗り継ぎや、追分へ向かいそこから室蘭本線を爆走する元客車で岩見沢へ向かってそこから乗り換えるという手段も乗り潰し的にはありますが無かったことにさせてください。
先程の話から新千歳空港から旭川へは直接1本の列車で向かうことが出来ません、札幌駅で旭川方面に向かう列車への乗り換えが必要になりますね。この産業の荷物も同様に営業所間では直接荷物をやり取りせずに地区センター(配送)に一旦荷物を送り他の営業所から荷物を方面別に仕分けし地区カーゴと言う貨物で一纏めにし、そのカーゴ単位で目的地となる営業所が繋がっている他のセンターに転送してそこから営業所へ配送されます。
しかし、大規模なマップでやっているといくら営業所と地区センターを使っても地区センターの数が多すぎて管理できなくなる可能性も出てきます。そこで地区センターを集約する設備として主要物流センターが登場します。
説明自体は先程の営業所と地区センターの関係と同じことなので割愛します。変わるのは小口荷物と地区カーゴから地区カーゴと幹線カーゴという荷物が登場するだけです。
貨物を設定しよう
産業と貨物の流れはまとまりました、ここからは登場する貨物を定義していきます。
必要な項目は次の通り
- 貨物の名前(被らない事)
- 貨物の1つ辺りの単位
- 貨物のカテゴリ
- 運送料金
- 早く運べた場合のボーナス
- 貨物1つあたりの重量(単位:kg)
名前については割愛し、次の貨物の1つあたりの単位から説明していきます。何か適当な物の分量を指す時に何箱とか何本とか言いますがそれが貨物でも適用されます。小口荷物であれば箱が大半と仮定してboxとか、地区カーゴや幹線カーゴはそのままCargoにしています。
単位自体は自分で好きなように決められるのでわかりやすい単位を選びましょう。
貨物のカテゴリについて、シムトランスでは以下のカテゴリが定義されています
- 0 : 独自貨物。
- 1:梱包済み製品(piece goods)
- 2:ばら積み貨物(bulk goods)
- 3:液体貨物(oil/gasoline)
- 4:冷却貨物(cooled goods)
- 5 : 飲料(liquid food)
- 6 : 長尺物(long goods)
- 7 : 繊維(fabric)
0の独自貨物については専用車両の実装まで必須で厄介なのでスルーします、今回の宅配便産業では1の梱包済み製品を選択しています。基本的には0以外であれば既に公開されているアドオンを用いる事が可能であり、自分で輸送用の車両アドオンを起こす手間もかかりません。
実際問題として貨車アドオンも64であればテヌキ車両さんが大量に公開しているので、それらを使う事が出来るのが大きなメリットとも言えます。
運送料金については基本的な金額であり、金額の設定と次に説明するスピードボーナス次第では相当儲かりますがバランスを考えた値を設定しましょう。
スピードボーナスについては字の通り「早く運んだらボーナス上げるよ、遅かったらペナルティ掛けるね」というざっくりとした説明ですが早く運ばないと行けないもの以外は低めにしておくと大丈夫でしょうか。
重量についても説明するまでもないので割愛します。
産業を実装しよう
この辺りはSimutrans日本語Wikiを参照して頂けると助かります →
アドオン開発/datファイル記述リファレンス/factory(産業) - Simutrans日本語化・解説
学会補足資料:アドオンを効率的に作る
この記事はSimturasn AdventCalenderへの参加記事となります、アドベントカレンダーの詳細については以下のリンクから参照して頂けると助かります。
adventar.org
前日のsuitougreenteaさんによる「拙作パッチとツールで爆速ダイヤ制作 in Extended」は以下のリンクからどうぞ
github.com
自分のプレゼンから
去る9月23日に札幌にてシムトラ学会が主催されました、主催者としてかなり早い時期から検討や各種折衝に振り回されていたのが懐かしいですね。
その時に自分は普段のプレイ・開発環境ということ内容でハードからソフトウェアまでさらけ出すように発表していました、その中で「pak制作の自動化」という要素に触れましたが
つい最近まである問題を先送りにしていました。それは「生成されたpakのコピーが手動であること」ここまでを自動化して初めて完全に自動化が図られているのではないかと思います。
この自動化を先日ツールの作り直し+新規ツール追加という形で達成しましたのでこのエントリーを持って改めて自分の環境をまとめたいと思います。
実際に使っているツールは以下のリンクからご参照ください
制作フロー
アドオンの制作フローについて改めて整理すると以下の通りになります、自分の環境下においてのフローなので参考になる箇所が少ないかもしれませんが
- 作業フォルダの用意
- pakフォルダを作成(出力用)
- png(画像)の作成
- dat(性能)の作成
- makeobjにてpak化、pakフォルダへ出力
- テスト環境へpakフォルダ内にあるpakをコピー
- テスト環境のpakセットを指定してsimutransを起動して動作テスト
この中で手を動かすべき要素はpng / datの作成や動作テストですね、それ以外の特にコピーする要素については自動化するべき要素だと思います。
理由としては手動で最新のファイルを指定してコピーするのが面倒な事やdatやpngを書いて(描いて)すぐに動作を見たいというのが挙げられます、書いた次の瞬間には更新されたデータでテストできるというのはかなり楽なのではないでしょうか。
pakの自動化は達成済
既にpak作成の段階は自動化しています、単純にファイル更新を検知してそれをトリガーとしてmakeobjを走らせるだけのシンプルなスクリプトだけですが。
この自動化自体も曲者であり作業スタイルとして2つのパターンが存在します、次の画像は実際にアドオンを制作するディレクトリのツリー構造の出力結果です
一枚目は直下にpakフォルダがあり、2枚目は配下のディレクトリの中にそれぞれpakフォルダが存在しています。
それぞれ意味が有り1枚目は1つのセットとしてアドオンを制作するケース、2枚目はあるアドオンの拡張として作るケースです。このような構成でもpak化までの自動化は達成出来ました。
しかし、ここまで進んでもテスト環境へのpakのコピーは手動でやらないといけません。面倒ですよね?
自分でコピーするのが面倒すぎる
というわけでやっとさらなる自動化の話です、ここまで自動化すれば目の前のdatやpngとにらめっこしつつテスト環境を走らせるだけになりました。
面倒なことは徹底的に自動化ということでファイルコピーを自動化する段階に入りましたが、どうやってpakフォルダ内で更新されたファイルを判別するかですが以下のエントリーを参考に実装しました
https://futuremix.org/2011/01/find-newer-file-timestampfuturemix.org
この記事を参考に起動時とファイル更新時にタイムスタンプを取得し、初回は起動時のスタンプを参考に比較して記録し次回からは記録されたタイムスタンプを比較する方式でコピーまで実装出来ました。
まだ自動化スクリプトには問題が残りました、ファイルの組み合わせです。
貨物以外は同名のdatとpngが揃わないとmakeobjが走らない様に構成されており片方が欠けていたら絶対に動きません、しかし自動化はじゃんじゃん走らせたいのも事実。
そこでさらに別のツールが生まれました
ダミーファイルを作れ
そこでダミーファイルが出てきます、中身は空のpngファイルと簡単な定義だけしかないdatファイルです。
makeobjはdatがあればpngが空でもpak化してくれる仕様なのでこのダミーだけでも十分通用します、出来たダミーファイルに中身があるpngやdatを上書きしていけば最終的にアドオンが出来ます。
結局環境としてはどうなの
効率がかなり上がりました、息をするようにdatやpngを書き出したらすぐにテスト環境で更新されたものをテスト出来るなんて最高ですね。
細々とcp * /path/とかしている時間が相当無駄だったというのを改めて感じます、書く(描く)事とチェックに注力すれば問題ない時点でかなりの効率です
今後の課題
- ja.tabのコピーも自動化したい
- datのSDL化
最後に
学会補足資料と言いつつ補足できているか微妙ですね、普段はこんなもので作ってるよっていう紹介までにはなればと思います。
このツール群は全てLinux上で(ソースを読んで依存するライブラリを入れれば)動きますのでお試しください
略図作成のススメ 2nd(作図編)
この記事はSimturasn AdventCalenderへの参加記事となります、アドベントカレンダーの詳細については以下のリンクから参照して頂けると助かります。
adventar.org
前日の大和路特急さんによるエントリーはこちら
twitter.com
実際に作図してみよう
masatrans-lab-diary.hateblo.jp
前回の記事で必要な道具を用意するところまでは進めました、これから実際に略図を作成する段階へ入ります。今回はコンピュータ上で作図を行いますが手書きでもやることは変わりません。
では実際に作図しますが以下の条件を設定しました
- 2面4線
- 駅の前後は複線
- 片方に引き上げ線配置
そして、条件を全て満たす略図を作成したのが以下の画像になります
(面倒だから手で下書きしてトレース)
書き方を考える
先ほどの画像を見ながら略図に必要な要素を見つけます
基本は直線で書く
全て直線ですね、シムトラのシステム上直線上に駅を置いた前提で書いています。
実際の配線構造はすべて反映させません、駅が仮に曲線上に置けたとしても直線で書き切ります。
分岐は形のまま書く
画像では分岐が8箇所にありますがそれぞれ[ダブルシーサス(X) / 両開き分岐(Y) / 片開き分岐(y)]を表現しています、片開きの後のアルファベットは片開きを表現出来てるかさておき。
改めて画像を見ると
- 左方向のダブルシーサスで全番線に出入りできる
- 各番線の右方向にもダブルシーサスがあり本線・引上線に(から)進入可能である
- 引上線から両ホームに進入出来る
- 4番線(一番下側の線路)の左側に両開き分岐があり速度制限が予想される
- 全体的に配線が汚い
という事が見て取れると思います、実際にシムトラ上に線路配置等を済ませる前に各ホームの運用もある程度は想定出来る気がします。
この段階でうっかりロマンを求めすぎて実際に敷設したら経路無しが多発するという事だけは避けておきたいですね、そんなことは流石に信号等を設置してからでないとわかりませんが。