UE5 python Google SpreadSheetからCSVを自動でインポートする
やあ
前回の続きだよ。
pto8913.hatenablog.com
前回はGoogle SpreadSheet
から、python
を介してデータを取ってこられるようになった。
今回はUnreal Engine
のエディタでボタンを押すだけで、Google SpreadSheet
からシートをcsvでダウンロードして、そのcsvと一致するDataTable
を再インポートできるようにするよ。
- やあ
- 前提条件
- pythonからGoogle SpreadSheetをcsvでダウンロードする
- ボタンを押して再インポートできるようにする
- 完全版
前提条件
DataTableの名前 = "Google SpreadSheet
のタイトル"_-_"シートの名前"
の形になっていること
DataTableの構造とGoogle SpreadSheet
の構造が一致していること
pythonからGoogle SpreadSheetをcsvでダウンロードする
サービスアカウントのメールアドレスに共有したGoogle SpreadSheet
からすべてのWorkSheet
をダウンロードしてみる。
import json import gspread import csv import os ROOT_DIR = os.path.abspath(os.curdir) + "/" SCRIPT_DIR = f'{ROOT_DIR}Scripts/' # 前回作ったサービスアカウントのjsonファイル! gc = gspread.service_account(f'{SCRIPT_DIR}service_account.json') # サービスアカウントのメールアドレスに共有したSpreadSheetの一覧を取得 for row in gc.openall(): spread_sheet = gc.open(row.title) for worksheet in spread_sheet.worksheets(): filename = f'{spread_sheet.title}_-_{work_sheet.title}.csv' with open(f'{ダウンロードする場所}/{filename}', 'w', encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(work_sheet.get_all_values())
動かすたびに全部ダウンロードするのはうれしくない!
なので特定のファイルをダウンロードする
特定のGoogle SpreadSheetから特定のWorkSheetをcsvでダウンロード
SpreadSheetのタイトルでSpreadSheetを指定
タイトルはこの部分!
spread_sheet = gc.open(SpreadSheetのタイトル)
もしくは
# https://docs.google.com/spreadsheets/d/{この部分がSpreadSheetのId}/edit#gid={この部分がWorkSheetのId}
spread_sheet = gc.open_by_key(SpreadSheetのId)
work_sheet = spreadsheet.get_worksheet_by_id(WorkSheetのId)
これでさっきみたいにcsv.writer
でダウンロードする
いちいちタイトルやIdなんかを調べるのは大変だ・・・
なので次はタイトルやIdをjsonに保存して、EditorUtilityWidget
を使ってjsonをエディタでみられるようにする!
タイトルとIdのリストを作る!
jsonに保存する
こんな構造でjsonに書き込む
{ spreadsheet1: { worksheet1: id, worksheet2: id }, spreadsheet2: { worksheet1: id } }
def RecreateSheetJson(): titles = {} for row in gc.openall(): sheets = {} spread_sheet = gc.open(row.title) for work_sheet in spread_sheet.worksheets(): sheets[work_sheet.title] = work_sheet.id titles[row.title] = sheets with open(f'{SCRIPT_DIR}sheet.json', 'w', encoding='utf-8') as f: json.dump(titles, f, indent=4)
Unreal Engineでpythonとjsonを使えるようにする
エディタの設定からpython Developer Modeを有効にする
Plugins
からJson Blueprint Utilities
を有効にする
エディタを再起動。
Unreal Engineのpythonからgspreadを呼べるようにする
Ctrl+R
→cmd
でコマンドプロンプトを開きます
開いたらUnreal Engineのpythonでpip install gspread
します
"C:\Program Files\Epic Games\UE_5.0\Engine\Binaries\ThirdParty\Python3\Win64\python.exe" -m pip install gspread
EditorUtilityWidgetでjsonのリストを表示する
Content Browser
を右クリックしてEditorUtilityWidget
を作成
名前はEUW_SpreadSheet_Import
にしたよ
ボタンを押してpythonの関数を呼んでみる
いい感じにボタンを配置します
ボタンのOnClickedイベントを実装する
pythonのファイルから関数を呼び出す!
sheet_to_json.py
import json import unreal import gspread ROOT_DIR = unreal.Paths.project_dir() SCRIPT_DIR = f'{ROOT_DIR}Scripts/' SHEET_JSON = f'{SCRIPT_DIR}sheet.json' gc = gspread.service_account(f'{SCRIPT_DIR}service_account.json') def RecreateSheetJson(): titles = {} for row in gc.openall(): sheets = {} SpreadSheet = gc.open(row.title) for WorkSheet in SpreadSheet.worksheets(): sheets[WorkSheet.title] = WorkSheet.id titles[row.title] = sheets with open(SHEET_JSON, 'w', encoding='utf-8') as f: json.dump(titles, f, indent=4)
実行するとProjectName/Scripts
の下にsheet.json
ができるはずだよ
リストを表示するためのUIを作る
Content Browser
を右クリックしてWidget Blueprint
を作る
名前はWBP_SpreadSheet_WorkSheet_List
SpreadSheet
のタイトルをクリックしたらWorkSheet
のリストが表示できるようにする
WorkSheet
を表示するためのスロットUIを作る
名前はWBP_SpreadSheet_WorkSheet_Slot
WBP_SpreadSheet_WorkSheet_List
に実装
ボタンを押したらSpreadSheetのリストが表示されるようにする
EUW_SpreadSheet_Import
にWBP_SpreadSheet_WorkSheet_List
を表示するためにちょっと変更
EUW_SpreadSheet_Import
に実装
これでボタンを押したら、サービスアカウントのメールアドレスに共有したGoogle SpreadSheetが表示されるはずだよ
リストをクリックしたらSpreadSheetとWorkSheetの名前を指定できるようにする
WBP_SpreadSheet_WorkSheet_Slot
にOnClicked
イベントを作成
WBP_SpreadSheet_WorkSheet_List
にOnClicked
イベントを作成
WBP_SpreadSheet_WorkSheet_List
にOnExpansionChanged
イベントを作成
WBP_SpreadSheet_WorkSheet_Slot
のクリックイベントにバインド
EUW_SpreadSheet_Import
をちょっと変更
EUW_SpreadSheet_Import
にイベントを追加
WBP_SpreadSheet_WorkSheet_List
のイベントをバインド
これでボタンを押したら選択できるようになったはずだよ。
ボタンを押して再インポートできるようにする
sheet_to_json.py
import json import unreal import gspread import csv import os ROOT_DIR = unreal.Paths.project_dir() SCRIPT_DIR = f'{ROOT_DIR}Scripts/' SHEET_JSON = f'{SCRIPT_DIR}sheet.json' DATATABLE_DIR = f'{ROOT_DIR}DataTableSource/' if not os.path.exists(DATATABLE_DIR): os.makedirs(DATATABLE_DIR, exist_ok=True) gc = gspread.service_account(f'{SCRIPT_DIR}service_account.json') def RecreateSheetJson(): titles = {} for row in gc.openall(): sheets = {} SpreadSheet = gc.open(row.title) for WorkSheet in SpreadSheet.worksheets(): sheets[WorkSheet.title] = WorkSheet.id titles[row.title] = sheets with open(SHEET_JSON, 'w', encoding='utf-8') as f: json.dump(titles, f, indent=4) def GetFileName(SpreadSheetTitle: str, WorkSheetTitle: str) -> str: return f'{SpreadSheetTitle}_-_{WorkSheetTitle}' def GetDownloadName(DownloadDir: str, SpreadSheetTitle: str, WorkSheetTitle: str) -> str: return f'{DownloadDir}{GetFileName(SpreadSheetTitle,WorkSheetTitle)}.csv' def DownloadWorkSheet(DownloadDir: str, SpreadSheetTitle: str, WorkSheetTitle: str) -> bool: with open(SHEET_JSON, 'r', encoding='utf-8') as f: Sheet_Json = json.load(f) if Sheet_Json[SpreadSheetTitle]: SpreadSheet = gc.open(SpreadSheetTitle) if not SpreadSheet: return False WorkSheet_Id = Sheet_Json[SpreadSheetTitle][WorkSheetTitle] WorkSheet = SpreadSheet.get_worksheet_by_id(WorkSheet_Id) if not WorkSheet: return False DOWNLOAD_NAME = GetDownloadName(DownloadDir, SpreadSheetTitle, WorkSheetTitle) with open(DOWNLOAD_NAME, 'w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(WorkSheet.get_all_values()) return True return False def ReimportWorkSheet(EditorDataTableDir: str, SpreadSheetTitle: str, WorkSheetTitle: str, IsReDownload: bool = True) -> bool: DOWNLOAD_NAME = GetDownloadName(DATATABLE_DIR, SpreadSheetTitle, WorkSheetTitle) if IsReDownload: if not DownloadWorkSheet(DATATABLE_DIR, SpreadSheetTitle, WorkSheetTitle): return False if not os.path.exists(DOWNLOAD_NAME): if not DownloadWorkSheet(DATATABLE_DIR, SpreadSheetTitle, WorkSheetTitle): return False FILE_NAME = GetFileName(SpreadSheetTitle,WorkSheetTitle) if os.path.exists(DOWNLOAD_NAME): DTPaths = unreal.EditorAssetLibrary.list_assets(EditorDataTableDir) for DTPath in DTPaths: if FILE_NAME in DTPath: task = unreal.AssetImportTask() task.filename = DOWNLOAD_NAME task.destination_path = EditorDataTableDir task.replace_existing = True task.automated = True task.save = False csv_factory = unreal.CSVImportFactory() Obj = unreal.EditorAssetLibrary.load_asset(DTPath) DataTable = unreal.DataTable.cast(Obj) row_struct = DataTable.get_editor_property("row_struct") csv_factory.automated_import_settings.import_row_struct = row_struct task.factory = csv_factory asset_tools = unreal.AssetToolsHelpers.get_asset_tools() asset_tools.import_asset_tasks([task]) return True return False def ReimportAllWorkSheet(EditorDataTableDir: str, SpreadSheetTitle: str, IsReDownload: bool = True) -> bool: SpreadSheet = gc.open(SpreadSheetTitle) for WorkSheet in SpreadSheet.worksheets(): ReimportWorkSheet(EditorDataTableDir, SpreadSheetTitle, WorkSheet.title, IsReDownload) return True
EUW_SpreadSheet_Import
にボタンを追加
OnClickedイベントを作成
これでボタンを押したら指定したGoogle SpreadSheet
を再インポートできるよ
完全版
プラグインにした