diff --git a/.github/ISSUE_TEMPLATE/Asset-Submission.yaml b/.github/ISSUE_TEMPLATE/Asset-Submission.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/Asset-Submission.yaml rename to .github/ISSUE_TEMPLATE/Asset-Submission.yml diff --git a/.github/ISSUE_TEMPLATE/User-Acceptance-Testing.yml b/.github/ISSUE_TEMPLATE/User-Acceptance-Testing.yml new file mode 100644 index 00000000..b62bcf5f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/User-Acceptance-Testing.yml @@ -0,0 +1,56 @@ +name: User Acceptance Testing +description: Procedure for doing human QA release testing +labels: ["uat"] +body: + - type: markdown + attributes: + value: | + For each test below, check the box if it passes. If it fails, elaborate + and then either way, attach this issue to the final + - type: textarea + id: blender-versions + attributes: + label: Blender version(s) tested + validations: + required: true + - type: checkboxes + id: uat-tests + attributes: + label: Test cases + description: Go line by line and check the boxes for each test passed + options: + - label: Remove MCprep, restart blender, then Install MCprep, enable, disable, then enable again without errors + - label: Open Mineways or jmc2obj button (configure as necessary to make it run the executbale) + - label: Import any exported obj world, and verify that it imported into own collection, correct exporter was auto-selected, and on selecting one of the objects it contains the custome object properties which are appropriate + - label: Go into rendered mode to verify blurry/bad textures, then press prep materials and check they are fixed as expected + - label: Import a world with broken textures, then check that prep materials or Advanced/find missing works + - label: Select a block like lava, and use advanced > animate textures, press play to make sure it's now animated + - label: Go to the materials tab with any primitive object selected, load materials, then try applying lava - again selecting animate textures; ensure on play it's animated + - label: Try running mesh swap on the entire scene, veryfing at least one object is meshswaped (will be world dependant, typically tall grass should at least be there) + - label: Try advanced > combine materials and combine images, mostly making sure it doesn't error out + - label: Try sync materials (more advanced, you might need to make a custom material first in the addon lib folder) + - label: Enter rendered mode, then press Create MC sky, try once with each of the options (changing in the redo last options) in rendered mode and verifying that it reacts e.g. adding/removing shader/mesh moon/sun and adding/removing clouds per tick box + - label: Test pressing render panorama, picking a small resolution to make it fast + - label: Test changing the time of day (after having added one of the dynamic sky options) + - label: Try skin swapping (from file, username, and/or pre-installed list). Check that it applies to all children of a rig when the armature is selected, but only individual meshes if meshes are selected without the rig + - label: Try a mob spawn + - label: Try a (few) block spawns + - label: Try an item spawn (either from list and/or from a file on disk) + - label: Try each type of available effect spawn (weather geo, weather particle, tnt collection at different frames, and some particle) + - label: Try an entity spawn + - label: Try a meshswap spawn, especially animated ones like torches or lighting-based ones like jack_o_lanterns + + - type: textarea + id: test-failures + attributes: + label: Test failures + description: For each test failure, note the number here and describe what exactly failed + validations: + required: false + - type: textarea + id: automated-tests + attributes: + label: Automated test results + description: Paste the output of unit tests here, either local run or the github action result + validations: + required: false diff --git a/.gitignore b/.gitignore index 063983ea..89b3e625 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,12 @@ venv/ *.sublime-* MCprep_addon/import_bridge/conf MCprep_addon/import_bridge/nbt -MCprep_addon/MCprep_resources/ +MCprep_addon/MCprep_resources/*.blend +MCprep_addon/MCprep_resources/mcprep_data.json +MCprep_addon/MCprep_resources/effects +MCprep_addon/MCprep_resources/resourcepacks +MCprep_addon/MCprep_resources/rigs +MCprep_addon/MCprep_resources/skins +MCprep_addon/MCprep_resources/textures +!MCprep_addon/MCprep_resources/Languages/* MCprep_addon/.vscode diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6d4cd52a..1d8e5d3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,21 +129,20 @@ In order to run these tests, **you must ensure your git folder with your MCprep At the moment, only the project lead (TheDuckCow) should ever mint new releases for MCprep. However, the steps are noted here for completeness: -1. All releases need a corresponding milestone, like v3.3.1 -1. Make sure the version is the correct number for the release (should match a corresponding milestone). Make this commit on the dev branch. -1. Create a pull request and merge dev into master (without deleting the dev branch). Close out any remaining corresponding milestones. Add this pull request to the milestone, only merging when all other tasks are completed or moved out of the milestone. -1. Check out master, git pull -1. Make sure that `"dev" = False` in conf.py, so that prod resources are used for reporting (it should always be this way on the master branch without doing anything, even after doing a merge from dev; but *always* double check) -1. Create [a draft release](https://github.com/TheDuckCow/MCprep/releases/new) on GitHub - - Tag is in the form `3.3.1`, no leading `v`. - - The title however is in the form `MCprep v3.3.0 | ShortName` where version has a leading `v`. - - Copy the body fo the description from the prior release, and then update the text and splash screen (if a major release). Edit a prior release without making changes to get the raw markdown code, e.g. [from here](https://github.com/TheDuckCow/MCprep/releases/edit/3.3.0). -1. Run `bpy-addon-build.py` to build the addon -1. Run all tests, ideally on two different operating systems. Use the `./run_tests.sh -all` flag to run on all versions of blender -1. If all tests pass, again DOUBLE CHECK that "dev" = false in conf.py, then -1. Drag and drop the generated updated zip file onto github. -1. Rename so it's in the form including its version number, e.g. `MCprep_addon_v3.3.0.zip` -1. Press publish release + +1. Checkout dev, and commit the correct release version in `MCprep_addon/__init__.py` (should match a corresponding milestone) +1. Create a pull request to merge dev into master. This can be approved and merged without review, since all code is already reviewed - but only TheDuckCow may do this bypass with current repo permissions +1. Locally, check out master and run `git pull` +1. Run all local unit tests using `python run_tests.py -a` + - While we do have remote github unit tests, TheDuckCow has many more versions locally for wider testing to be more comprehensive. But, github action unittests can be used in a standin if necessary. +1. Create a new UAT issue from [issues here](https://github.com/Moo-Ack-Productions/MCprep/issues/new/choose) with the name of the corresponding milestone + - The automated test results above should be pasted into the last section of this UAT form. + - If not all UAT steps pass, consider halting the release and/or updating/creating new issues +1. If all UAT steps pass, the run `./push_latest.sh` in the repo root + - Follow the script's instructions and prompts for ensuring the release completes + - You will likely need to update POT files and the json mapping via `mcprep_data_refresh.py` which gets called from within this script. Make a new PR if appropriate. +1. After this script has finished, go to [github releases](https://github.com/Moo-Ack-Productions/MCprep/releases) and edit the draft release to hand hand-adjusted changelogs +1. Press release 1. **Immediately** download and install an old release MCprep, and install into blender (restart blender too) 1. Make sure that the trigger to update MCprep to the new version is working. 1. If it works, then **immediately update** the https://theduckcow.com/dev/blender/mcprep-download/ page to point to the new number (must be manually updated by TheDuckCow). @@ -152,7 +151,6 @@ At the moment, only the project lead (TheDuckCow) should ever mint new releases 1. git checkout dev, and then upversion the dev branch to a unique incremental version. So if you just released v3.3.1, then the dev branch should be updated to be (3, 3, 1, 1) so that we can tell official releases apart from dev versions. - ## Creating your blender_execs.txt Your `blender_execs.txt` defines where to find the executables used in the automated testing scripts. Only these executables will be used during automated testing, noting that the testing system only supports blender version 2.8+ (sadly, only manual testing is possible in blender 2.7 with the current setup). It could look like: diff --git a/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po b/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po index 81cd45e1..6cac66b6 100644 --- a/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po +++ b/MCprep_addon/MCprep_resources/Languages/en_US/LC_MESSAGES/mcprep.po @@ -14,7 +14,7 @@ msgstr "" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: MCprep_addon/mcprep_ui.py:98 diff --git a/MCprep_addon/MCprep_resources/Languages/mcprep.pot b/MCprep_addon/MCprep_resources/Languages/mcprep.pot index 942aff27..24854515 100644 --- a/MCprep_addon/MCprep_resources/Languages/mcprep.pot +++ b/MCprep_addon/MCprep_resources/Languages/mcprep.pot @@ -1,9 +1,9 @@ # msgid "" msgstr "" -"Project-Id-Version: 3.6.1\n" +"Project-Id-Version: 3.6.1.1\n" "Report-Msgid-Bugs-To: https://github.com/Moo-Ack-Productions/MCprep/issues\n" -"POT-Creation-Date: 2024-08-22 21:18-0700\n" +"POT-Creation-Date: 2024-08-24 22:58-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po b/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po new file mode 100644 index 00000000..5a7a5b14 --- /dev/null +++ b/MCprep_addon/MCprep_resources/Languages/zh_CN/LC_MESSAGES/mcprep.po @@ -0,0 +1,596 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-02-03 22:03-0600\n" +"PO-Revision-Date: 2024-02-03 22:16-0600\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.4.1\n" + +#: MCprep_addon/mcprep_ui.py:98 +msgid "Restart blender" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:100 +msgid "to complete update" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:109 +msgid "Mob Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:111 +msgid "Menu for placing in the shift-A add object menu" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:121 +msgid "Load mobs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:150 +msgid "Meshswap Objects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:157 +msgid "No meshswap blocks found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:179 +msgid "Item Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:185 +msgid "No items found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:202 +msgid "Effects Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:245 +msgid "Entity Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:252 +msgid "No entities found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:268 +msgid "Model Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:274 +msgid "No models found!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:314 +msgid "Load spawners" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:516 +msgid "World Importing & Meshswapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:520 +msgid "Default Exporter:" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:525 +msgid "jmc2obj executable" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:530 +msgid "Mineways executable" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:535 +msgid "World OBJ Exports Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:540 +msgid "Meshwap assets" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:546 MCprep_addon/mcprep_ui.py:871 +#: MCprep_addon/mcprep_ui.py:1337 MCprep_addon/mcprep_ui.py:1485 +msgid "MeshSwap file not found" +msgstr "未找到网格变形文件" + +#: MCprep_addon/mcprep_ui.py:550 +msgid "Entity assets" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:556 MCprep_addon/mcprep_ui.py:1435 +msgid "Entity file not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:562 MCprep_addon/mcprep_ui.py:1658 +msgid "Effects folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:566 +msgid "Texture / Resource packs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:570 MCprep_addon/mcprep_ui.py:843 +#: MCprep_addon/mcprep_ui.py:1651 +msgid "Texture pack folder" +msgstr "材质包文件夹" + +#: MCprep_addon/mcprep_ui.py:575 +msgid "Install to folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:579 +msgid "Open texture pack folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:584 +msgid "Mob spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:588 +msgid "Rig Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:593 +msgid "Select/install mobs" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:596 +msgid "Install file for mob spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:598 +msgid "Open rig folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:603 MCprep_addon/mcprep_ui.py:675 +msgid "Skin swapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:607 +msgid "Skin Folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:612 +msgid "Install skins" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:614 +msgid "Install skin file for swapping" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:616 +msgid "Open skin folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:621 +msgid "Effects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:625 +msgid "Effect folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:631 +msgid "Open effects folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:643 +msgid "Using MCprep in experimental mode!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:644 +msgid "Early access features and requests for feedback" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:645 +msgid "will be made visible. Thank you for contributing." +msgstr "" + +#: MCprep_addon/mcprep_ui.py:649 +msgid "Unsure on how to use the addon? Check out these resources" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:654 +msgid "MCprep page for instructions and updates" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:662 +msgid "Learn MCprep + Blender, 1-minute tutorials" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:669 +msgid "Import Minecraft worlds" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:672 +msgid "Mob (rig) spawning" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:681 +msgid "jmc2obj/Mineways" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:684 MCprep_addon/mcprep_ui.py:897 +msgid "World Tools" +msgstr "世界工具" + +#: MCprep_addon/mcprep_ui.py:687 +msgid "Tutorial Series" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:695 +msgid "Anonymous user tracking settings" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:704 +msgid "Opt into anonymous usage tracking" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:709 +msgid "Opt OUT of anonymous usage tracking" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:713 +msgid "For info on anonymous usage tracking:" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:716 +msgid "Open the Privacy Policy" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:725 +msgid "World Imports" +msgstr "导入地图" + +#: MCprep_addon/mcprep_ui.py:748 +msgid "World exporter" +msgstr "地图导出工具" + +#: MCprep_addon/mcprep_ui.py:759 MCprep_addon/mcprep_ui.py:787 +msgid "Select exporter!" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:769 +msgid "OBJ world import" +msgstr "导入 OBJ 世界" + +#: MCprep_addon/mcprep_ui.py:773 MCprep_addon/mcprep_ui.py:1879 +msgid "MCprep tools" +msgstr "MCprep 工具" + +#: MCprep_addon/mcprep_ui.py:774 +msgid "Prep Materials" +msgstr "准备材质" + +#: MCprep_addon/mcprep_ui.py:781 +msgid "OBJ incompatible with textureswap" +msgstr "OBJ与纹理交换不兼容" + +#: MCprep_addon/mcprep_ui.py:785 +msgid "Mesh Swap" +msgstr "网格变形" + +#: MCprep_addon/mcprep_ui.py:807 +msgid "(UI already improved)" +msgstr "(UI 已经改善)" + +#: MCprep_addon/mcprep_ui.py:810 +msgid "Improve UI" +msgstr "改善 UI" + +#: MCprep_addon/mcprep_ui.py:817 +msgid "Cycles Optimizer" +msgstr "Cycles 优化器" + +#: MCprep_addon/mcprep_ui.py:829 MCprep_addon/mcprep_ui.py:836 +#: MCprep_addon/mcprep_ui.py:1023 MCprep_addon/mcprep_ui.py:1030 +#: MCprep_addon/mcprep_ui.py:1112 MCprep_addon/mcprep_ui.py:1212 +#: MCprep_addon/mcprep_ui.py:1219 MCprep_addon/mcprep_ui.py:1320 +#: MCprep_addon/mcprep_ui.py:1325 MCprep_addon/mcprep_ui.py:1390 +#: MCprep_addon/mcprep_ui.py:1394 MCprep_addon/mcprep_ui.py:1470 +#: MCprep_addon/mcprep_ui.py:1474 MCprep_addon/mcprep_ui.py:1549 +#: MCprep_addon/mcprep_ui.py:1553 MCprep_addon/mcprep_ui.py:1638 +#: MCprep_addon/mcprep_ui.py:1642 +msgid "Advanced" +msgstr "高级" + +#: MCprep_addon/mcprep_ui.py:859 +msgid "Combine Materials" +msgstr "合并材质" + +#: MCprep_addon/mcprep_ui.py:861 +msgid "Combine Images" +msgstr "合并图像" + +#: MCprep_addon/mcprep_ui.py:863 +msgid "Meshswap source:" +msgstr "网格变形源:" + +#: MCprep_addon/mcprep_ui.py:869 +msgid "MeshSwap file must be .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:880 +msgid "World Bridge" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:911 +msgid "World settings and lighting" +msgstr "世界设置和光照" + +#: MCprep_addon/mcprep_ui.py:926 +msgid "Time of day" +msgstr "时间" + +#: MCprep_addon/mcprep_ui.py:933 +#, python-brace-format +msgid "{h}:{m}, day {d}" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:942 +msgid "No time controller," +msgstr "没有时间控制器," + +#: MCprep_addon/mcprep_ui.py:943 +msgid "add dynamic MC world." +msgstr "请添加动态MC世界。" + +#: MCprep_addon/mcprep_ui.py:952 +msgid "Skin Swapper" +msgstr "皮肤交换器" + +#: MCprep_addon/mcprep_ui.py:969 +msgid "Select skin" +msgstr "选择皮肤" + +#: MCprep_addon/mcprep_ui.py:986 +msgid "No skins found/loaded" +msgstr "未找到/加载皮肤" + +#: MCprep_addon/mcprep_ui.py:988 MCprep_addon/mcprep_ui.py:993 +msgid "Press to reload" +msgstr "\"按下重新加载" + +#: MCprep_addon/mcprep_ui.py:991 +msgid "Reload skins" +msgstr "重新加载皮肤" + +#: MCprep_addon/mcprep_ui.py:1011 +msgid "No skins found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1013 +msgid "Skin from file" +msgstr "从文件导入皮肤" + +#: MCprep_addon/mcprep_ui.py:1015 +msgid "Skin from username" +msgstr "从用户名导入皮肤" + +#: MCprep_addon/mcprep_ui.py:1036 +msgid "Skin path" +msgstr "皮肤路径" + +#: MCprep_addon/mcprep_ui.py:1050 +msgid "Reload mobs below" +msgstr "重新加载下方的生物" + +#: MCprep_addon/mcprep_ui.py:1054 +msgid "Reload skins above" +msgstr "重新加载上方的皮肤" + +#: MCprep_addon/mcprep_ui.py:1064 +msgid "MCprep materials" +msgstr "MCprep 材质" + +#: MCprep_addon/mcprep_ui.py:1098 +msgid "No materials loaded" +msgstr "未加载材质" + +#: MCprep_addon/mcprep_ui.py:1107 +msgid "Load material" +msgstr "加载材质" + +#: MCprep_addon/mcprep_ui.py:1125 MCprep_addon/mcprep_ui.py:1398 +#: MCprep_addon/mcprep_ui.py:1557 +msgid "Resource pack" +msgstr "资源包" + +#: MCprep_addon/mcprep_ui.py:1141 +msgid "Enter object mode" +msgstr "进入对象模式" + +#: MCprep_addon/mcprep_ui.py:1142 +msgid "to use spawner" +msgstr "以使用生成器" + +#: MCprep_addon/mcprep_ui.py:1151 +msgid "Import pre-rigged mobs & players" +msgstr "导入预设置的生物和玩家" + +#: MCprep_addon/mcprep_ui.py:1170 +msgid "No mobs in category," +msgstr "该类别中没有生物," + +#: MCprep_addon/mcprep_ui.py:1171 +msgid "install a rig below or" +msgstr "安装一个下方的预设或" + +#: MCprep_addon/mcprep_ui.py:1172 +msgid "copy file to folder." +msgstr "将文件复制到文件夹中。" + +#: MCprep_addon/mcprep_ui.py:1178 +msgid "No mobs loaded" +msgstr "未加载生物" + +#: MCprep_addon/mcprep_ui.py:1182 MCprep_addon/mcprep_ui.py:1291 +#: MCprep_addon/mcprep_ui.py:1373 MCprep_addon/mcprep_ui.py:1449 +#: MCprep_addon/mcprep_ui.py:1527 MCprep_addon/mcprep_ui.py:1604 +msgid "Reload assets" +msgstr "重新加载资源" + +#: MCprep_addon/mcprep_ui.py:1226 +msgid "Mob spawner folder" +msgstr "生物生成器文件夹" + +#: MCprep_addon/mcprep_ui.py:1233 +msgid "Open mob folder" +msgstr "打开生物文件夹" + +#: MCprep_addon/mcprep_ui.py:1242 +msgid "Change mob icon" +msgstr "更改生物图标" + +#: MCprep_addon/mcprep_ui.py:1246 +msgid "Reload mobs" +msgstr "重新加载生物" + +#: MCprep_addon/mcprep_ui.py:1254 +msgid "Import pre-made blocks (e.g. lights)" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1268 +msgid "Meshswap file must be a .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:1273 MCprep_addon/mcprep_ui.py:1282 +msgid "Reset meshswap path" +msgstr "重置网格变形路径" + +#: MCprep_addon/mcprep_ui.py:1277 +msgid "Meshswap file not found" +msgstr "未找到网格变形文件" + +#: MCprep_addon/mcprep_ui.py:1286 +msgid "No blocks loaded" +msgstr "未加载方块" + +#: MCprep_addon/mcprep_ui.py:1310 +msgid "Place block" +msgstr "放置方块2" + +#: MCprep_addon/mcprep_ui.py:1329 +msgid "Meshswap file" +msgstr "网格变形文件" + +#: MCprep_addon/mcprep_ui.py:1335 MCprep_addon/mcprep_ui.py:1483 +msgid "MeshSwap file must be a .blend" +msgstr "网格变形文件必须是.blend格式" + +#: MCprep_addon/mcprep_ui.py:1348 +msgid "Generate items from textures" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1368 +msgid "No items loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1379 +msgid "Place item" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1412 +msgid "Import pre-rigged entities" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1426 +msgid "Entity file must be a .blend" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1431 MCprep_addon/mcprep_ui.py:1440 +msgid "Reset entity path" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1444 +msgid "No entities loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1461 +msgid "Spawn Entity" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1478 +msgid "Entity file" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1497 +msgid "Generate models from .json files" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1522 +msgid "No models loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1573 +msgid "Load/generate effects" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1599 +msgid "No effects loaded" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1610 +msgid "Add effect" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1646 +msgid "Effects folder" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1660 +msgid "Effects/collection folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1662 +msgid "Effects/geonodes folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1664 +msgid "Effects/particle folder not found" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1672 +msgid "Spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1682 +msgid "Click triangle to open" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1691 +msgid "Mob spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1719 +msgid "Block (model) spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1747 +msgid "Item spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1776 +msgid "Effects + weather" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1804 +msgid "Entity spawner" +msgstr "" + +#: MCprep_addon/mcprep_ui.py:1832 +msgid "Meshswap spawner" +msgstr "" diff --git a/MCprep_addon/__init__.py b/MCprep_addon/__init__.py index f9aeea73..bf002dee 100755 --- a/MCprep_addon/__init__.py +++ b/MCprep_addon/__init__.py @@ -41,7 +41,7 @@ bl_info = { "name": "MCprep", "category": "Object", - "version": (3, 6, 1), + "version": (3, 6, 1, 3), "blender": (2, 80, 0), "location": "3D window toolshelf > MCprep tab", "description": "Minecraft workflow addon for rendering and animation", diff --git a/MCprep_addon/conf.py b/MCprep_addon/conf.py index 83ed86e6..24232102 100644 --- a/MCprep_addon/conf.py +++ b/MCprep_addon/conf.py @@ -28,6 +28,7 @@ import bpy from bpy.utils.previews import ImagePreviewCollection +import bpy.utils.previews # ----------------------------------------------------------------------------- @@ -58,19 +59,14 @@ class Engine(enum.Enum): Skin = Tuple[str, Path] Entity = Tuple[str, str, str] -# Represents an unknown location -# for MCprepError. Given a global +# Represents an unknown location +# for MCprepError. Given a global # constant to make it easier to use # and check for UNKNOWN_LOCATION = (-1, "UNKNOWN LOCATION") DEBUG_MODE = False -# check if custom preview icons available -try: - import bpy.utils.previews -except: - print("MCprep: No custom icons in this blender instance") - pass +MCPREP_RESOURCES: Path = Path(os.path.dirname(__file__), "MCprep_resources") # ----------------------------------------------------------------------------- # ADDON GLOBAL VARIABLES AND INITIAL SETTINGS @@ -81,11 +77,12 @@ class MCprepEnv: def __init__(self): self.data = None self.json_data: Optional[Dict] = None - self.json_path: Path = Path(os.path.dirname(__file__), "MCprep_resources", "mcprep_data.json") - self.json_path_update: Path = Path(os.path.dirname(__file__), "MCprep_resources", "mcprep_data_update.json") + self.json_path: Path = Path(MCPREP_RESOURCES, "mcprep_data.json") + self.json_path_update: Path = Path( + MCPREP_RESOURCES, "mcprep_data_update.json") self.dev_file: Path = Path(os.path.dirname(__file__), "mcprep_dev.txt") - self.languages_folder: Path = Path(os.path.dirname(__file__), "MCprep_resources", "Languages") + self.languages_folder: Path = Path(MCPREP_RESOURCES, "Languages") self.translations: Path = Path(os.path.dirname(__file__), "translations.py") self.last_check_for_updated = 0 @@ -137,21 +134,12 @@ def __init__(self): # that no reading has occurred. If lib not found, will update to []. # If ever changing the resource pack, should also reset to None. self.material_sync_cache: List = [] - + # Whether we use PO files directly or use the converted form self.use_direct_i18n = False - # i18n using Python's gettext module - # - # This only runs if translations.py does not exist - if not self.translations.exists(): - self.languages: dict[str, gettext.NullTranslations] = {} - for language in self.languages_folder.iterdir(): - self.languages[language.name] = gettext.translation("mcprep", - self.languages_folder, - fallback=True, - languages=[language.name]) - self.use_direct_i18n = True - self.log("Loaded direct i18n!") + + self.languages: dict[str, gettext.NullTranslations] = {} + self._load_translations() # Cache for Vivy materials. Identical to self.material_sync_cache, but # as a seperate variable to avoid conflicts @@ -170,8 +158,25 @@ def reload_vivy_json(self) -> None: with open(json_path, 'r') as f: self.vivy_material_json = json.load(f) if json_path.stat().st_size != 0 else {} - # This allows us to translate strings on the fly + + def _load_translations(self) -> None: + """Loads in mo file translation maps""" + try: + if not self.translations.exists(): + for language in self.languages_folder.iterdir(): + self.languages[language.name] = gettext.translation( + "mcprep", + localedir=self.languages_folder, + fallback=True, + languages=[language.name]) + self.use_direct_i18n = True + self.log("Loaded direct i18n!") + except Exception as e: + self.languages = {} + self.log(f"Exception occured while loading translations! {e}") + def _(self, msg: str) -> str: + """Allows us to translate strings on the fly""" if not self.use_direct_i18n: return msg if bpy.context.preferences.view.language in self.languages: @@ -268,14 +273,14 @@ def current_line_and_file(self) -> Tuple[int, str]: MCprepError. This function can not return an MCprepError value as doing - so would be more complicated for the caller. As such, if - this fails, we return values -1 and "UNKNOWN LOCATION" to - indicate that we do not know the line number or file path + so would be more complicated for the caller. As such, if + this fails, we return values -1 and "UNKNOWN LOCATION" to + indicate that we do not know the line number or file path the error occured on. Returns: - - If success: Tuple[int, str] representing the current - line and file path + - If success: Tuple[int, str] representing the current + line and file path - If fail: (-1, "UNKNOWN LOCATION") """ @@ -284,10 +289,10 @@ def current_line_and_file(self) -> Tuple[int, str]: cur_frame = inspect.currentframe() if not cur_frame: return UNKNOWN_LOCATION - + # Get the previous frame since the # current frame is made for this function, - # not the function/code that called + # not the function/code that called # this function prev_frame = cur_frame.f_back if not prev_frame: @@ -296,50 +301,45 @@ def current_line_and_file(self) -> Tuple[int, str]: frame_info = inspect.getframeinfo(prev_frame) return frame_info.lineno, frame_info.filename + @dataclass class MCprepError(object): """ - Object that is returned when + Object that is returned when an error occurs. This is meant - to give more information to the - caller so that a better error + to give more information to the + caller so that a better error message can be made Attributes ------------ err_type: BaseException - The error type; uses standard + The error type; uses standard Python exceptions - + line: int - Line the exception object was - created on. The preferred method - to do this is to use currentframe - and getframeinfo from the inspect + Line the exception object was + created on. The preferred method + to do this is to use currentframe + and getframeinfo from the inspect module file: str Path of file the exception object - was created in. The preferred way + was created in. The preferred way to get this is __file__ msg: Optional[str] - Optional message to display for an - exception. Use this if the exception + Optional message to display for an + exception. Use this if the exception type may not be so clear cut """ err_type: BaseException - line: int + line: int file: str msg: Optional[str] = None -# Requires Extension support and building with the proper wheels -if DEBUG_MODE and bpy.app.version >= (4, 2, 0): - import debugpy - debugpy.listen(("localhost", 5678)) - -env = MCprepEnv() def updater_select_link_function(self, tag): """Indicates what zip file to use for updating from a tag structure. @@ -358,6 +358,16 @@ def updater_select_link_function(self, tag): # GLOBAL REGISTRATOR INIT # ----------------------------------------------------------------------------- + +# Requires Extension support and building with the proper wheels +if DEBUG_MODE and bpy.app.version >= (4, 2, 0): + import debugpy + debugpy.listen(("localhost", 5678)) + + +env = MCprepEnv() + + def register(): global env if not env.json_data: diff --git a/bpy-build.yaml b/bpy-build.yaml index c3f6d68a..60a8551a 100644 --- a/bpy-build.yaml +++ b/bpy-build.yaml @@ -2,6 +2,7 @@ addon_folder: MCprep_addon build_name: MCprep_addon install_versions: + - 4.3 - 4.2 - 4.1 - 4.0 diff --git a/push_latest.sh b/push_latest.sh index 885618e4..d5b033ac 100755 --- a/push_latest.sh +++ b/push_latest.sh @@ -55,8 +55,14 @@ rm MCprep_addon/mcprep_addon_tracker.json rm mcprep_addon_trackerid.json echo "Building prod addon..." -bpy-addon-build -b translate # No --during-build dev to make it prod. -ls build/MCprep_addon.zip +bab -b translate # No --during-build dev to make it prod. +if [ $? -eq 0 ]; then + echo "Build complete" + ls build/MCprep_addon.zip +else + echo "Build failed" + exit +fi # ----------------------------------------------------------------------------- # Cross check no local changes, such as updated translations diff --git a/run_tests.py b/run_tests.py index 2ca36091..e1201794 100644 --- a/run_tests.py +++ b/run_tests.py @@ -41,7 +41,7 @@ import time -COMPILE_CMD = ["bab", "-b", "dev"] +COMPILE_CMD = ["bab", "-b", "dev", "translate"] DATA_CMD = ["python", "mcprep_data_refresh.py", "-auto"] # TODO, include in build DCC_EXES = "blender_execs.txt" TEST_RUNNER = os.path.join("test_files", "test_runner.py") @@ -60,6 +60,7 @@ def __str__(self): def main(): + t0 = time.time() args = get_args() # Read arguments @@ -69,12 +70,21 @@ def main(): return # Compile the addon + if args.version: + # Just install into the only blender version we'll test anyways + COMPILE_CMD.extend(["-v", args.version]) + elif not args.all_execs: + # Just install into the first blender binary listed to match the tests + # TODO: get Blender version from the binary path at blender_execs[0] + # default_v = x + # COMPILE_CMD.extend(["-v", default_v]) + pass res = subprocess.check_output(COMPILE_CMD) print("Compile output:", res.decode("utf-8")) reset_test_file() # Loop over all binaries and run tests. - t0 = time.time() + t1 = time.time() any_failures = False for ind, binary in enumerate(blender_execs): run_all = args.all_execs is True @@ -104,15 +114,17 @@ def main(): if child.returncode != 0: any_failures = True - t1 = time.time() + t2 = time.time() # Especially ensure tracker files are removed after tests complete. remove_tracker_files() output_results() - round_s = round(t1 - t0) + compile_time = t1 - t0 + test_time = t2 - t1 exit_code = 1 if any_failures else 0 - print(f"tests took {round_s}s to run, ending with code {exit_code}") + print(f"Compiled in {compile_time:.1f}s + tests ran in {test_time:.1f}s") + print(f"Total of {t2-t0:.1f}s with exit code {exit_code}") sys.exit(exit_code) diff --git a/test_files/addon_test.py b/test_files/addon_test.py index 60ab2bf2..211f0a2a 100644 --- a/test_files/addon_test.py +++ b/test_files/addon_test.py @@ -16,14 +16,23 @@ # # ##### END GPL LICENSE BLOCK ##### +from pathlib import Path +import os import unittest import bpy +from MCprep_addon import conf + class AddonTest(unittest.TestCase): """Create addon level tests, and ensures enabled for later tests.""" + @staticmethod + def addon_path() -> Path: + scripts = bpy.utils.user_resource("SCRIPTS") + return Path(scripts, "addons", "MCprep_addon") + def test_enable(self): """Ensure the addon can be directly enabled.""" bpy.ops.preferences.addon_enable(module="MCprep_addon") @@ -33,6 +42,58 @@ def test_disable_enable(self): bpy.ops.preferences.addon_disable(module="MCprep_addon") bpy.ops.preferences.addon_enable(module="MCprep_addon") + def test_translations(self): + """Safely ensures translations are working fine still. + + Something go wrong, blender stuck in another language? Run in console: + bpy.context.preferences.view.language = "en_US" + """ + init_lang = bpy.context.preferences.view.language + try: + self._test_translation() + except Exception: + raise + finally: + bpy.context.preferences.view.language = init_lang + + def _test_translation(self): + """Ensure that creating the MCprep environment is error-free.""" + test_env = conf.MCprepEnv() + mcprep_dir = self.addon_path() + lang_folder = mcprep_dir / "MCprep_resources" / "Languages" + test_env.languages_folder = lang_folder + + # Don't assign translations, to force building the map in memory + # translations_py = mcprep_dir / "translations.py" + # test_env.translations = translations_py + + # Force load translations into this instance of MCprepEnv + test_env._load_translations() + + self.assertIn( + "en_US", test_env.languages, "Missing default translation key") + self.assertTrue( + test_env.use_direct_i18n, "use_direct_i18n should be True") + + # Magic string evaluations, will break if source po's change + test_translations = [ + ("ru_RU", "Restart blender", "Перезапустите блендер"), + # Blender 4.0+ only has 'zh_HANS', 'zh_HANT' + ("zh_HANS" if bpy.app.version > (4, 0) else "zh_CN", "Texture pack folder", "材质包文件夹"), + ("en_US", "Mob Spawner", "Mob Spawner"), + ] + for lang, src, dst in test_translations: + with self.subTest(lang): + # First ensure the mo files exist + self.assertTrue( + os.path.isfile( + lang_folder / lang / "LC_MESSAGES" / "mcprep.mo"), + f"Missing {lang}'s mo file") + + bpy.context.preferences.view.language = lang + res = test_env._(src) + self.assertEqual(res, dst, f"Unexpected {lang} translation)") + if __name__ == '__main__': unittest.main(exit=False)