Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features

 Conflicts:
	core/assets/bundles/bundle_zh_CN.properties
	core/assets/bundles/bundle_zh_TW.properties
This commit is contained in:
Anuken
2021-11-22 13:17:36 -05:00
8 changed files with 707 additions and 944 deletions

View File

@@ -15,7 +15,7 @@ jobs:
cd ../MindustryBuilds cd ../MindustryBuilds
BNUM=$(($GITHUB_RUN_NUMBER + 20000)) BNUM=$(($GITHUB_RUN_NUMBER + 20000))
git tag ${BNUM} git tag ${BNUM}
git config --global user.name "Build Uploader" git config --global user.name "Github Actions"
git push https://Anuken:${{ secrets.API_TOKEN_GITHUB }}@github.com/Anuken/MindustryBuilds ${BNUM} git push https://Anuken:${{ secrets.API_TOKEN_GITHUB }}@github.com/Anuken/MindustryBuilds ${BNUM}
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v1 uses: actions/setup-java@v1

View File

@@ -35,7 +35,7 @@ load.mod = MOD
load.scripts = Scripts load.scripts = Scripts
be.update = 新しいBleeding Edgeビルドがあります: be.update = 新しいBleeding Edgeビルドがあります:
be.update.confirm = ダウンロードして再起動しますか\uff1f be.update.confirm = ダウンロードして再起動しますか
be.updating = 更新中... be.updating = 更新中...
be.ignore = 無視する be.ignore = 無視する
be.noupdates = 更新が見つかりません。 be.noupdates = 更新が見つかりません。
@@ -52,7 +52,7 @@ mods.browser.sortstars = お気に入り数で並べる
schematic = 設計図 schematic = 設計図
schematic.add = 設計図を保存 schematic.add = 設計図を保存
schematics = 設計図一覧 schematics = 設計図一覧
schematic.replace = その名前の設計図は既に存在しています。上書きしますか\uff1f schematic.replace = その名前の設計図は既に存在しています。上書きしますか
schematic.exists = その名前の設計図は既に存在しています。 schematic.exists = その名前の設計図は既に存在しています。
schematic.import = 設計図をインポート schematic.import = 設計図をインポート
schematic.exportfile = ファイルに出力する schematic.exportfile = ファイルに出力する
@@ -73,7 +73,7 @@ schematic.addtag = タグを追加
schematic.texttag = テキストタグ schematic.texttag = テキストタグ
schematic.icontag = アイコンタグ schematic.icontag = アイコンタグ
schematic.renametag = タグの名前変更 schematic.renametag = タグの名前変更
schematic.tagdelconfirm = このタグをすべて削除しますか\uff1f schematic.tagdelconfirm = このタグをすべて削除しますか
schematic.tagexists = このタグはすでに存在します。 schematic.tagexists = このタグはすでに存在します。
stats = Stats stats = Stats
@@ -156,7 +156,7 @@ mod.jarwarn = [scarlet]JAR mods は本質的に安全ではありません。[]\
mod.item.remove = これは以下のModの一部です。[accent] '{0}'[] 削除するにはそのModを削除してください。 mod.item.remove = これは以下のModの一部です。[accent] '{0}'[] 削除するにはそのModを削除してください。
mod.remove.confirm = このModを削除します。 mod.remove.confirm = このModを削除します。
mod.author = [lightgray]著者:[] {0} mod.author = [lightgray]著者:[] {0}
mod.missing = このデータには、最近更新された、または、有効化されてない以下のModが含まれています。\n[accent]データが破損する可能性があります。[]\n読み込んでもよろしいですか\uff1f\n[lightgray]{0} mod.missing = このデータには、最近更新された、または、有効化されてない以下のModが含まれています。\n[accent]データが破損する可能性があります。[]\n読み込んでもよろしいですか\n[lightgray]{0}
mod.preview.missing = このModをワークショップで公開するには、Modのプレビュー画像を設定する必要があります。\n[accent] preview.png[] というファイル名の画像をmodsのフォルダに配置し、再試行してください。 mod.preview.missing = このModをワークショップで公開するには、Modのプレビュー画像を設定する必要があります。\n[accent] preview.png[] というファイル名の画像をmodsのフォルダに配置し、再試行してください。
mod.folder.missing = ワークショップで公開できるのは、フォルダ形式のModのみとなります。\nModをフォルダ形式に変換するには、ファイルをフォルダに解凍し、古いzipを削除してからゲームを再起動するか、modを再読み込みしてください。 mod.folder.missing = ワークショップで公開できるのは、フォルダ形式のModのみとなります。\nModをフォルダ形式に変換するには、ファイルをフォルダに解凍し、古いzipを削除してからゲームを再起動するか、modを再読み込みしてください。
mod.scripts.disable = お使いのデバイスはScriptを使用したModをサポートしていません。 ゲームをプレイするには、これらのModを無効にする必要があります。 mod.scripts.disable = お使いのデバイスはScriptを使用したModをサポートしていません。 ゲームをプレイするには、これらのModを無効にする必要があります。
@@ -356,11 +356,11 @@ workshop.error = ワークショップの詳細を取得中にエラーが発生
map.publish.confirm = 本当にこのマップを公開しますか?\n\n[lightgray]公開するためには、ワークショップ利用規約に同意する必要があります。 map.publish.confirm = 本当にこのマップを公開しますか?\n\n[lightgray]公開するためには、ワークショップ利用規約に同意する必要があります。
workshop.menu = このアイテムに対して行う操作を選択してください。 workshop.menu = このアイテムに対して行う操作を選択してください。
workshop.info = アイテムの詳細 workshop.info = アイテムの詳細
changelog = 更新履歴 \uff08オプション\uff09: changelog = 更新履歴 (オプション):
eula = Steamの使用許諾契約 eula = Steamの使用許諾契約
missing = このアイテムは削除または移動されています。\n[lightgray]ワークショップのリストは自動的にリンク解除されました。 missing = このアイテムは削除または移動されています。\n[lightgray]ワークショップのリストは自動的にリンク解除されました。
publishing = [accent]公開中... publishing = [accent]公開中...
publish.confirm = 公開してもよろしいですか\uff1f\n\n[lightgray]最初に、ワークショップの使用許諾契約に同意するか確認してください。 publish.confirm = 公開してもよろしいですか\n\n[lightgray]最初に、ワークショップの使用許諾契約に同意するか確認してください。
publish.error = 公開中のエラー: {0} publish.error = 公開中のエラー: {0}
steam.error = Steam サービスの初期化に失敗しました。\nエラー: {0} steam.error = Steam サービスの初期化に失敗しました。\nエラー: {0}
@@ -688,12 +688,12 @@ settings.graphics = グラフィック
settings.cleardata = データを削除... settings.cleardata = データを削除...
settings.clear.confirm = データを削除してもよろしいですか?\nこれを元に戻すことはできません! settings.clear.confirm = データを削除してもよろしいですか?\nこれを元に戻すことはできません!
settings.clearall.confirm = [scarlet]警告![]\nこれはすべてのデータが削除されます。これにはセーブデータ、マップ、アンロック、キーバインドが含まれます。\n「ok」 を押すと、すべてのデータが削除され、自動的に終了します。 settings.clearall.confirm = [scarlet]警告![]\nこれはすべてのデータが削除されます。これにはセーブデータ、マップ、アンロック、キーバインドが含まれます。\n「ok」 を押すと、すべてのデータが削除され、自動的に終了します。
settings.clearsaves.confirm = カスタムプレイのセーブデータをすべて削除してもよろしいですか\uff1f settings.clearsaves.confirm = カスタムプレイのセーブデータをすべて削除してもよろしいですか
settings.clearsaves = セーブデータを削除 settings.clearsaves = セーブデータを削除
settings.clearresearch = 研究リセット settings.clearresearch = 研究リセット
settings.clearresearch.confirm = キャンペーンの研究をすべて削除してもよろしいですか\uff1f settings.clearresearch.confirm = キャンペーンの研究をすべて削除してもよろしいですか
settings.clearcampaignsaves = キャンペーンのリセット settings.clearcampaignsaves = キャンペーンのリセット
settings.clearcampaignsaves.confirm = キャンペーンのセーブデータをすべて削除してもよろしいですか\uff1f settings.clearcampaignsaves.confirm = キャンペーンのセーブデータをすべて削除してもよろしいですか
paused = [accent]< ポーズ > paused = [accent]< ポーズ >
clear = 消去 clear = 消去
banned = [scarlet]使用禁止 banned = [scarlet]使用禁止
@@ -926,7 +926,7 @@ setting.lasersopacity.name = 電線の透明度
setting.bridgeopacity.name = ブリッジの透明度 setting.bridgeopacity.name = ブリッジの透明度
setting.playerchat.name = ゲーム内にチャットを表示 setting.playerchat.name = ゲーム内にチャットを表示
setting.showweather.name = 天気のグラフィックを表示 setting.showweather.name = 天気のグラフィックを表示
public.confirm = ゲームを公開しますか\uff1f\n[accent]誰でもゲームに参加できるようになります。\n[lightgray]あとから設定で変更できます。 public.confirm = ゲームを公開しますか\n[accent]誰でもゲームに参加できるようになります。\n[lightgray]あとから設定で変更できます。
public.confirm.really = フレンドと遊びたい場合は、[scarlet]公開サーバー[] ではなく [green]フレンド招待[] を使おう!\nゲームを [scarlet]公開[]してもよろしいですか? public.confirm.really = フレンドと遊びたい場合は、[scarlet]公開サーバー[] ではなく [green]フレンド招待[] を使おう!\nゲームを [scarlet]公開[]してもよろしいですか?
public.beta = ベータ版では使用できません。 public.beta = ベータ版では使用できません。
uiscale.reset = UIサイズが変更されました。\nこのままでよければ「OK」を押してください。\n[scarlet][accent]{0}[] 秒で元の設定に戻ります... uiscale.reset = UIサイズが変更されました。\nこのままでよければ「OK」を押してください。\n[scarlet][accent]{0}[] 秒で元の設定に戻ります...
@@ -1353,7 +1353,7 @@ block.constructor.description = 最大で2x2の大きさの構造物を建造し
block.large-constructor.name = 大型コンストラクター block.large-constructor.name = 大型コンストラクター
block.large-constructor.description = 最大で4x4の大きさの構造物を建造します。 block.large-constructor.description = 最大で4x4の大きさの構造物を建造します。
block.deconstructor.name = デコンストラクター block.deconstructor.name = デコンストラクター
block.deconstructor.description = 構造物やユニットを解体します。建造費の100\uff05が戻ってきます。 block.deconstructor.description = 構造物やユニットを解体します。建造費の100が戻ってきます。
block.payload-loader.name = ペイロード搬入機 block.payload-loader.name = ペイロード搬入機
block.payload-loader.description = 液体や資源をブロックに搬入します。 block.payload-loader.description = 液体や資源をブロックに搬入します。
block.payload-unloader.name = ペイロード搬出機 block.payload-unloader.name = ペイロード搬出機
@@ -1387,10 +1387,10 @@ hint.desktopPause = [accent][[スペース][]を押して、ゲームを一時
hint.placeDrill = 右下のメニューの\ue85e [accent]ドリル[]タブを選択し、\uf870 [accent]ドリル[]を選択し、銅地域をクリックして配置します。 hint.placeDrill = 右下のメニューの\ue85e [accent]ドリル[]タブを選択し、\uf870 [accent]ドリル[]を選択し、銅地域をクリックして配置します。
hint.placeDrill.mobile = 右下のメニューの\ue85e [accent]ドリル[]タブを選択し、\uf870 [accent]ドリル[]を選択し、銅地域をタップして配置します。\n\n右下の\ue800 [accent]チェックマーク[]をタップして確認します。 hint.placeDrill.mobile = 右下のメニューの\ue85e [accent]ドリル[]タブを選択し、\uf870 [accent]ドリル[]を選択し、銅地域をタップして配置します。\n\n右下の\ue800 [accent]チェックマーク[]をタップして確認します。
hint.placeConveyor = コンベアーを使い、アイテムをドリルから他のブロックへ移動します。\ue814 [accent]運搬[]タブから、\uf896 [accent]コンベアー[]を選択します。\n\n複数のコンベアーを配置するには、クリックしてドラッグします。\n[accent]マウスホイール[]により回転します。 hint.placeConveyor = コンベアーを使い、アイテムをドリルから他のブロックへ移動します。\ue814 [accent]運搬[]タブから、\uf896 [accent]コンベアー[]を選択します。\n\n複数のコンベアーを配置するには、クリックしてドラッグします。\n[accent]マウスホイール[]により回転します。
hint.placeConveyor.mobile = コンベアーを使い、アイテムをドリルから他のブロックへ移動します。\ue814 [accent]運搬[]タブから、\uf896 [accent]コンベアー[]を選択します。\n\n指を\uff11秒間押したままドラッグすると、複数のコンベアーを配置します。 hint.placeConveyor.mobile = コンベアーを使い、アイテムをドリルから他のブロックへ移動します。\ue814 [accent]運搬[]タブから、\uf896 [accent]コンベアー[]を選択します。\n\n指を秒間押したままドラッグすると、複数のコンベアーを配置します。
hint.placeTurret = \uf861 [accent]ターレット[]を配置して、敵から基地を守ります。\n\nターレットには弾薬が必要です。この場合は\uf838銅です。\nコンベアーとドリルを使用して補給します。 hint.placeTurret = \uf861 [accent]ターレット[]を配置して、敵から基地を守ります。\n\nターレットには弾薬が必要です。この場合は\uf838銅です。\nコンベアーとドリルを使用して補給します。
hint.breaking = [accent]右クリック[]と右クリックドラッグによりブロックを壊します。 hint.breaking = [accent]右クリック[]と右クリックドラッグによりブロックを壊します。
hint.breaking.mobile = 右下にある\ue817 [accent]ハンマー[]をアクティブにして、タップしてブロックを壊します。\n\n指を\uff11秒間押したままドラッグすると、範囲選択が出来ます。 hint.breaking.mobile = 右下にある\ue817 [accent]ハンマー[]をアクティブにして、タップしてブロックを壊します。\n\n指を秒間押したままドラッグすると、範囲選択が出来ます。
hint.blockInfo = [accent]建築メニュー[]でブロックを選択し、右側の[accent][[?][]ボタンを押すと、ブロックの情報が表示されます。 hint.blockInfo = [accent]建築メニュー[]でブロックを選択し、右側の[accent][[?][]ボタンを押すと、ブロックの情報が表示されます。
hint.derelict = [accent]放棄[]され、すでに機能を失った古い基地建造物の残骸です。\n\nこれらは[accent]解体[]することにより、資源になります。 hint.derelict = [accent]放棄[]され、すでに機能を失った古い基地建造物の残骸です。\n\nこれらは[accent]解体[]することにより、資源になります。
hint.research = \ue875 [accent]研究[]ボタンを押して、新しいテクノロジーを研究します。 hint.research = \ue875 [accent]研究[]ボタンを押して、新しいテクノロジーを研究します。
@@ -1399,7 +1399,7 @@ hint.unitControl = [accent][[左ctrl][]を押しながら[accent]クリック[]
hint.unitControl.mobile = [accent][ダブルタップ[]すると味方ユニットやターレットを操作できます。 hint.unitControl.mobile = [accent][ダブルタップ[]すると味方ユニットやターレットを操作できます。
hint.launch = 十分な資源を確保できたら、右下の\ue827 [accent]マップ[]から、近くのセクターを選択して[accent]発射[]できます。 hint.launch = 十分な資源を確保できたら、右下の\ue827 [accent]マップ[]から、近くのセクターを選択して[accent]発射[]できます。
hint.launch.mobile = 十分な資源を確保できたら、\ue88c [accent]メニュー[]の\ue827 [accent]マップ[]から、近くのセクターを選択して[accent]発射[]できます。 hint.launch.mobile = 十分な資源を確保できたら、\ue88c [accent]メニュー[]の\ue827 [accent]マップ[]から、近くのセクターを選択して[accent]発射[]できます。
hint.schematicSelect = [accent][[F][]を押しながらドラッグして、コピー&ペーストするブロックを選択します。\n\n[accent][[ミドルクリック][]により、\uff11つのブロックタイプをコピーします。 hint.schematicSelect = [accent][[F][]を押しながらドラッグして、コピー&ペーストするブロックを選択します。\n\n[accent][[ミドルクリック][]により、つのブロックタイプをコピーします。
hint.conveyorPathfind = [accent][[左-Ctrl][]を押しながらコンベアーをドラッグすると、経路が自動生成されます。 hint.conveyorPathfind = [accent][[左-Ctrl][]を押しながらコンベアーをドラッグすると、経路が自動生成されます。
hint.conveyorPathfind.mobile = \ue844 [accent]対角線モード[]を有効にし、コンベアーをドラッグすると経路が自動生成します。 hint.conveyorPathfind.mobile = \ue844 [accent]対角線モード[]を有効にし、コンベアーをドラッグすると経路が自動生成します。
hint.boost = [accent][[左シフト][]を押したままにすると、操作中のユニットは障害物を飛び越えます。\n\n少数の地上ユニットのみがこのブースターを搭載しています。 hint.boost = [accent][[左シフト][]を押したままにすると、操作中のユニットは障害物を飛び越えます。\n\n少数の地上ユニットのみがこのブースターを搭載しています。

View File

@@ -101,7 +101,7 @@ customgame = Пользовательская игра
newgame = Новая игра newgame = Новая игра
none = <ничего> none = <ничего>
none.found = [lightgray]<ничего не найдено> none.found = [lightgray]<ничего не найдено>
none.inmap = [lightgray]<none in map> none.inmap = [lightgray]<нет на карте>
minimap = Мини-карта minimap = Мини-карта
position = Координаты position = Координаты
close = Закрыть close = Закрыть
@@ -882,7 +882,7 @@ setting.fpscap.name = Максимальный FPS
setting.fpscap.none = Неограниченный setting.fpscap.none = Неограниченный
setting.fpscap.text = {0} FPS setting.fpscap.text = {0} FPS
setting.uiscale.name = Масштаб пользовательского интерфейса setting.uiscale.name = Масштаб пользовательского интерфейса
setting.uiscale.description = Restart required to apply changes. setting.uiscale.description = Для вступления изменений в силу может потребоваться перезагрузка игры.
setting.swapdiagonal.name = Всегда диагональное размещение setting.swapdiagonal.name = Всегда диагональное размещение
setting.difficulty.training = Обучение setting.difficulty.training = Обучение
setting.difficulty.easy = Лёгкая setting.difficulty.easy = Лёгкая
@@ -1053,7 +1053,7 @@ rules.title.enemy = Враги
rules.title.unit = Боевые единицы rules.title.unit = Боевые единицы
rules.title.experimental = Экспериментально rules.title.experimental = Экспериментально
rules.title.environment = Окружение rules.title.environment = Окружение
rules.title.teams = Teams rules.title.teams = Команды
rules.lighting = Освещение rules.lighting = Освещение
rules.enemyLights = Вражеские огни rules.enemyLights = Вражеские огни
rules.fire = Огонь rules.fire = Огонь
@@ -1443,8 +1443,8 @@ liquid.water.description = Используется для охлаждения
liquid.slag.description = Может быть переработан в разделителе на составляющие металлы или распылён на врагов в качестве оружия. liquid.slag.description = Может быть переработан в разделителе на составляющие металлы или распылён на врагов в качестве оружия.
liquid.oil.description = Используется в производстве продвинутых материалов и как зажигательный боеприпас. liquid.oil.description = Используется в производстве продвинутых материалов и как зажигательный боеприпас.
liquid.cryofluid.description = Используется в качестве охлаждающей жидкости для реакторов, турелей и фабрик. liquid.cryofluid.description = Используется в качестве охлаждающей жидкости для реакторов, турелей и фабрик.
block.derelict = \uf77e [lightgray]Derelict
block.derelict = \uf77e [lightgray]Заброшенный
block.armored-conveyor.description = Перемещает предметы вперёд. Не принимает вход по бокам. block.armored-conveyor.description = Перемещает предметы вперёд. Не принимает вход по бокам.
block.illuminator.description = Излучает свет. block.illuminator.description = Излучает свет.
block.message.description = Сохраняет сообщение для связи между союзниками. block.message.description = Сохраняет сообщение для связи между союзниками.
@@ -1470,8 +1470,8 @@ block.item-source.description = Постоянно выдаёт предметы
block.item-void.description = Уничтожает любые предметы. Только песочница. block.item-void.description = Уничтожает любые предметы. Только песочница.
block.liquid-source.description = Постоянно выдаёт жидкость. Только песочница. block.liquid-source.description = Постоянно выдаёт жидкость. Только песочница.
block.liquid-void.description = Уничтожает любые жидкости. Только песочница. block.liquid-void.description = Уничтожает любые жидкости. Только песочница.
block.payload-source.description = Infinitely outputs payloads. Sandbox only. block.payload-source.description = Постоянно выдает грузы. Только песочница.
block.payload-void.description = Destroys any payloads. Sandbox only. block.payload-void.description = Уничтожает любые грузы. Только песочница.
block.copper-wall.description = Защищает постройки от вражеских снарядов. block.copper-wall.description = Защищает постройки от вражеских снарядов.
block.copper-wall-large.description = Защищает постройки от вражеских снарядов. block.copper-wall-large.description = Защищает постройки от вражеских снарядов.
block.titanium-wall.description = Защищает постройки от вражеских снарядов. block.titanium-wall.description = Защищает постройки от вражеских снарядов.
@@ -1778,7 +1778,7 @@ lenum.itemdrop = Сбрасывание предметов.
lenum.itemtake = Взятие предметов из постройки. lenum.itemtake = Взятие предметов из постройки.
lenum.paydrop = Сбрасывание текущего груза. lenum.paydrop = Сбрасывание текущего груза.
lenum.paytake = Взятие груза на текущей позиции. lenum.paytake = Взятие груза на текущей позиции.
lenum.payenter = Enter/land on the payload block the unit is on. lenum.payenter = Войти/приземлиться на грузовой блок на котором находится единица.
lenum.flag = Числовой флаг единицы. lenum.flag = Числовой флаг единицы.
lenum.mine = Копание в позиции. lenum.mine = Копание в позиции.
lenum.build = Строительство структур. lenum.build = Строительство структур.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ sourceSets.main.java.srcDirs = ["src/"]
import arc.files.Fi import arc.files.Fi
import arc.files.ZipFi
import arc.func.Func2 import arc.func.Func2
import arc.graphics.Color import arc.graphics.Color
import arc.graphics.Pixmap import arc.graphics.Pixmap
@@ -11,9 +12,12 @@ import arc.struct.IntMap
import arc.struct.ObjectMap import arc.struct.ObjectMap
import arc.struct.OrderedMap import arc.struct.OrderedMap
import arc.struct.Seq import arc.struct.Seq
import arc.util.Http
import arc.util.Log import arc.util.Log
import arc.util.OS
import arc.util.async.Threads import arc.util.async.Threads
import arc.util.io.PropertiesUtils import arc.util.io.PropertiesUtils
import arc.util.io.Streams
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -261,10 +265,47 @@ task genSprites(dependsOn: classes, type: JavaExec){
} }
task fontgen(dependsOn: classes, type: JavaExec){ task fontgen(dependsOn: classes, type: JavaExec){
mainClass = "mindustry.tools.FontGenerator" /* icon font pipeline:
classpath = sourceSets.main.runtimeClasspath 1. take set of pre-defined icons and SVGs
standardInput = System.in 2. use Fontello API to get a font with these
workingDir = "../" 3. combine fontello font and standard font, get output font
4. use json to generate a file with constants for every icon size+type (during annotation processing)
*/
doLast{
Fi folder = Fi.get("core/assets-raw/fontgen/out/");
folder.mkdirs();
Log.info("Session...");
OS.exec("curl", "--fail", "--output", "core/assets-raw/fontgen/out/session", "--form", "config=@core/assets-raw/fontgen/config.json", "https://fontello.com");
Log.info("Zip...");
String session = folder.child("session").readString();
Http.get("https://fontello.com/" + session + "/get").block(result -> {
Streams.copy(result.getResultAsStream(), folder.child("font.zip").write());
});
Log.info("Icon font...");
ZipFi zip = new ZipFi(folder.child("font.zip"));
Fi dest = folder.child("font.woff");
zip.list()[0].child("font").child("fontello.ttf").copyTo(dest);
dest.copyTo(Fi.get("core/assets/fonts/icon.ttf"));
Log.info("Merge...");
//TODO this is broken
Log.info(OS.exec("fontforge", "-script",
Fi.get("core/assets-raw/fontgen/merge.pe").absolutePath(),
Fi.get("core/assets/fonts/font.woff").absolutePath(),
Fi.get("core/assets-raw/fontgen/out/font.woff").absolutePath())
);
Log.info("Done.");
}
} }
task icongen(dependsOn: classes, type: JavaExec){ task icongen(dependsOn: classes, type: JavaExec){
@@ -293,7 +334,7 @@ task updateBundles{
continue; continue;
} }
if(ch >= 0xE000){ if(ch >= 0xE000 && ch <= 0xF8FF){
String hex = Integer.toHexString((int)ch); String hex = Integer.toHexString((int)ch);
outBuffer.append("\\u"); outBuffer.append("\\u");
for(int j = 0; j < 4 - hex.length(); j++){ for(int j = 0; j < 4 - hex.length(); j++){

View File

@@ -1,227 +0,0 @@
package mindustry.tools;
import arc.*;
import arc.files.*;
import arc.func.*;
import arc.struct.*;
import arc.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import static mindustry.tools.ScriptMainGenerator.*;
//experimental binding generator - used for Nim, but can be used for other languages as well, theoretically
public class BindingsGenerator{
//list of touchy class names that lead to conflicts or should not be referenced; all typedefs and procs containing these are ignored
static Seq<String> ignored = Seq.with(".Entry", ".MapIterator", "arc.freetype.FreeType.Glyph", "FrameBufferBuilder", "Spliterator",
"java.util.function", "java.util.stream", "ArrayList", "Constable", "Optional", "java.lang.reflect", "rhino.Context", "arc.graphics.GL20", "arc.graphics.GL30");
static ObjectSet<Class<?>> classSet = new ObjectSet<>();
static ObjectSet<String> keywords = ObjectSet.with("object", "string");
public static void main(String[] args) throws Exception{
Seq<String> blacklist = Seq.with(
"mindustry.tools",
"arc.backend",
"arc.maps",
"arc.util.serialization.Xml",
"arc.fx",
"arc.net", "arc.Net",
"arc.freetype"
);
Seq<Class<?>> classes = Seq.withArrays(
getClasses("mindustry")
//getClasses("arc")
);
classes.removeAll(type -> type.isSynthetic() || type.isAnonymousClass() || type.getCanonicalName() == null || Modifier.isPrivate(type.getModifiers())
|| blacklist.contains(s -> type.getName().startsWith(s)));
classes.addAll(Enum.class, FloatBuffer.class, IntBuffer.class, ByteBuffer.class, StringBuilder.class,
Comparator.class, Comparable.class, Reader.class, Writer.class, PrintStream.class, PrintWriter.class, File.class, Charset.class,
ClassLoader.class, DoubleBuffer.class, CharBuffer.class, Locale.class,
LongBuffer.class, DataInputStream.class, DataOutputStream.class, Events.class, Cons.class
);
classes.distinct();
classes = sorted(classes);
classes.removeAll(BindingsGenerator::ignore);
classes.removeAll(c -> !Modifier.isPublic(c.getModifiers()));
ObjectMap<String, Seq<Class<?>>> similars = new ObjectMap<>();
classes.each(c -> similars.get(c.getSimpleName(), Seq::new).add(c));
similars.each((key, val) -> {
if(val.size > 1){
Log.info("\n" + key + ":\n" + val.toString("\n", v -> "- " + v.getCanonicalName()));
}
});
classSet = classes.asSet();
classSet.addAll(Object.class, Number.class, Integer.class, Double.class, Short.class, Float.class, Byte.class, Long.class, String.class, Boolean.class, Throwable.class, Exception.class, Class.class);
classSet.addAll(void.class, int.class, float.class, long.class, char.class, byte.class, boolean.class, double.class, short.class);
StringBuilder result = new StringBuilder();
result.append("import jnim, jnim/java/lang\n\n{.push hint[ConvFromXtoItselfNotNeeded]: off.}\n\n");
for(Class<?> type : classes){
result.append("jclassDef ").append(type.getName()).append(" of `")
.append(repr(type.getSuperclass())).append("`\n");
}
result.append("\n");
for(Class<?> type : classes){
Seq<Executable> exec = new Seq<>();
Seq<Method> methods = Seq.with(type.getDeclaredMethods());
methods.removeAll(m -> ignore(m.getReturnType()) || !discovered(m.getReturnType()));
exec.addAll(methods);
exec.addAll(type.getDeclaredConstructors());
exec.removeAll(e -> !Modifier.isPublic(e.getModifiers()) || keywords.contains(e.getName()));
exec.removeAll(e -> Structs.contains(e.getParameterTypes(), BindingsGenerator::ignore));
exec.removeAll(e -> Structs.contains(e.getParameterTypes(), p -> !discovered(p)));
Seq<Field> fields = Seq.select(type.getDeclaredFields(), f ->
Modifier.isPublic(f.getModifiers()) &&
!keywords.contains(f.getName()) &&
!ignore(f.getType()) && Modifier.isPublic(f.getType().getModifiers()) &&
!(f.getType().isArray() &&
f.getType().getComponentType().isArray()) &&
classSet.contains(f.getType())
);
if(exec.size + fields.size <= 0) continue;
result.append("jclassImpl ").append(type.getName()).append(" of `")
.append(repr(type.getSuperclass())).append("`").append(":").append("\n");
for(Field field : fields){
result.append(" proc `").append(field.getName()).append("`");
result.append(": ").append(str(field.getType()));
result.append(" {.prop");
if(Modifier.isStatic(field.getModifiers())) result.append(", `static`");
if(Modifier.isStatic(field.getModifiers())) result.append(", `final`");
result.append(".}\n");
}
for(Executable method : exec){
String mname = method.getName().equals("<init>") || method.getName().equals(type.getName()) ? "new" : method.getName();
if(method instanceof Method){
Method m = (Method)method;
//if a field by the same name exists, use it to prevent ambiguity
if(method.getParameterCount() == 0 && fields.contains(f -> f.getName().equals(method.getName()))){
continue;
}
//check if this is a less specific method that was overridden by another method
if(methods.contains(other ->
other != m &&
m.getName().equals(other.getName()) &&
m.getParameterCount() == other.getParameterCount() &&
Arrays.equals(m.getParameterTypes(), other.getParameterTypes()) &&
m.getReturnType().isAssignableFrom(other.getReturnType())
)){
continue;
}
}
result.append(" proc `").append(mname).append("`");
if(method.getParameterCount() > 0){
result.append("(");
for(int i = 0; i < method.getParameterCount(); i++){
Class p = method.getParameterTypes()[i];
result.append(method.getParameters()[i].getName()).append(": ").append(str(p));
if(i != method.getParameterCount() - 1){
result.append(", ");
}
}
result.append(")");
}
if(method instanceof Method){
Method m = (Method)method;
if(!m.getReturnType().equals(void.class)){
result.append(": ").append(str(m.getReturnType()));
}
}
if(Modifier.isStatic(method.getModifiers())){
result.append(" {.`static`.}");
}
result.append("\n");
}
result.append("\n");
}
result.append("{.pop.}\n");
//change directory as needed later
Fi.get("/home/anuke/Projects/Nimdustry-java/mindustry_bindings.nim").writeString(result.toString());
Log.info("Done. Classes found: @", classes.size);
}
static boolean discovered(Class<?> type){
return classSet.contains(type) || (type.isArray() && discovered(type.getComponentType()));
}
static boolean ignore(Class<?> type){
if(type == null) return false;
if(type.isArray() && type.getComponentType().isArray()) return true;
return ignored.contains(s -> type.getCanonicalName().contains(s)) || ignore(type.getSuperclass());
}
static Seq<Class<?>> sorted(Seq<Class<?>> classes){
ObjectSet<Class<?>> visited = new ObjectSet<>();
Seq<Class<?>> result = new Seq<>();
for(Class<?> c : classes){
if(!visited.contains(c)){
topoSort(c, result, visited);
}
}
return result;
}
static void topoSort(Class<?> c, Seq<Class<?>> stack, ObjectSet<Class<?>> visited){
visited.add(c);
for(Class<?> sup : c.getInterfaces()){
if(!visited.contains(sup)){
topoSort(sup, stack, visited);
}
}
if(c.getSuperclass() != null && !c.getSuperclass().equals(Object.class) && !visited.contains(c.getSuperclass())){
topoSort(c.getSuperclass(), stack, visited);
}
stack.add(c);
}
static String repr(Class type){
if(type == null) return "JVMObject";
if(type.equals(Object.class)) return "Object";
if(type.equals(String.class)) return "string";
if(!Modifier.isPublic(type.getModifiers())) return "Object";
return type.getSimpleName();
}
static String str(Class type){
if(type.equals(Object.class)) return "Object";
if(type.equals(String.class)) return "string";
if(type.isArray()) return "seq[" + str(type.getComponentType()) + "]";
if(type.isPrimitive()) return "j" + type.getSimpleName();
return type.getSimpleName();
}
}

View File

@@ -1,51 +0,0 @@
package mindustry.tools;
import arc.files.*;
import arc.util.*;
import arc.util.io.*;
/* icon font pipeline:
1. take set of pre-defined icons and SVGs
2. use Fontello API to get a font with these
3. combine fontello font and standard font, get output font
4. use json to generate a file with constants for every icon size+type (during annotation processing)
*/
public class FontGenerator{
//E000 to F8FF
public static void main(String[] args){
Fi folder = Fi.get("core/assets-raw/fontgen/out/");
folder.mkdirs();
Log.info("Session...");
OS.exec("curl", "--fail", "--output", "core/assets-raw/fontgen/out/session", "--form", "config=@core/assets-raw/fontgen/config.json", "https://fontello.com");
Log.info("Zip...");
String session = folder.child("session").readString();
Http.get("https://fontello.com/" + session + "/get").block(result -> {
Streams.copy(result.getResultAsStream(), folder.child("font.zip").write());
});
Log.info("Icon font...");
ZipFi zip = new ZipFi(folder.child("font.zip"));
Fi dest = folder.child("font.woff");
zip.list()[0].child("font").child("fontello.ttf").copyTo(dest);
dest.copyTo(Fi.get("core/assets/fonts/icon.ttf"));
Log.info("Merge...");
//TODO this is broken
Log.info(OS.exec("fontforge", "-script",
Fi.get("core/assets-raw/fontgen/merge.pe").absolutePath(),
Fi.get("core/assets/fonts/font.woff").absolutePath(),
Fi.get("core/assets-raw/fontgen/out/font.woff").absolutePath())
);
Log.info("Done.");
}
}