mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Merge branch 'mc-1.16.x' into mc-1.17.x
This commit is contained in:
		| @@ -156,9 +156,13 @@ | |||||||
|             <property name="tokens" value="COMMA" /> |             <property name="tokens" value="COMMA" /> | ||||||
|         </module> |         </module> | ||||||
|         <module name="WhitespaceAround"> |         <module name="WhitespaceAround"> | ||||||
|  |             <property name="ignoreEnhancedForColon" value="false" /> | ||||||
|  |             <!-- Allow empty functions --> | ||||||
|  |             <property name="allowEmptyLambdas" value="true" /> | ||||||
|  |             <property name="allowEmptyMethods" value="true" /> | ||||||
|             <property name="allowEmptyConstructors" value="true" /> |             <property name="allowEmptyConstructors" value="true" /> | ||||||
|             <property name="allowEmptyTypes" value="true" /> |             <property name="allowEmptyTypes" value="true" /> | ||||||
|             <property name="ignoreEnhancedForColon" value="false" /> |  | ||||||
|             <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" /> |             <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" /> | ||||||
|         </module> |         </module> | ||||||
|     </module> |     </module> | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| # See https://pre-commit.com/hooks.html for more hooks | # See https://pre-commit.com/hooks.html for more hooks | ||||||
| repos: | repos: | ||||||
| - repo: https://github.com/pre-commit/pre-commit-hooks | - repo: https://github.com/pre-commit/pre-commit-hooks | ||||||
|   rev: v3.2.0 |   rev: v4.0.1 | ||||||
|   hooks: |   hooks: | ||||||
|   - id: trailing-whitespace |   - id: trailing-whitespace | ||||||
|   - id: end-of-file-fixer |   - id: end-of-file-fixer | ||||||
| @@ -16,7 +16,7 @@ repos: | |||||||
|     exclude: "tsconfig\\.json$" |     exclude: "tsconfig\\.json$" | ||||||
|  |  | ||||||
| - repo: https://github.com/editorconfig-checker/editorconfig-checker.python | - repo: https://github.com/editorconfig-checker/editorconfig-checker.python | ||||||
|   rev: 2.3.5 |   rev: 2.3.54 | ||||||
|   hooks: |   hooks: | ||||||
|   - id: editorconfig-checker |   - id: editorconfig-checker | ||||||
|     args: ['-disable-indentation'] |     args: ['-disable-indentation'] | ||||||
|   | |||||||
							
								
								
									
										96
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										96
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -21,9 +21,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@rollup/plugin-typescript": { |     "node_modules/@rollup/plugin-typescript": { | ||||||
|       "version": "8.2.5", |       "version": "8.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz", |       "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", | ||||||
|       "integrity": "sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==", |       "integrity": "sha512-I5FpSvLbtAdwJ+naznv+B4sjXZUcIvLLceYpITAn7wAP8W0wqc5noLdGIp9HGVntNhRWXctwPYrSSFQxtl0FPA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@rollup/pluginutils": "^3.1.0", |         "@rollup/pluginutils": "^3.1.0", | ||||||
| @@ -112,9 +112,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/is-core-module": { |     "node_modules/is-core-module": { | ||||||
|       "version": "2.6.0", |       "version": "2.8.0", | ||||||
|       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", | ||||||
|       "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", |       "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "has": "^1.0.3" |         "has": "^1.0.3" | ||||||
| @@ -142,9 +142,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/preact": { |     "node_modules/preact": { | ||||||
|       "version": "10.5.14", |       "version": "10.5.15", | ||||||
|       "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.14.tgz", |       "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.15.tgz", | ||||||
|       "integrity": "sha512-KojoltCrshZ099ksUZ2OQKfbH66uquFoxHSbnwKbTJHeQNvx42EmC7wQVWNuDt6vC5s3nudRHFtKbpY4ijKlaQ==", |       "integrity": "sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA==", | ||||||
|       "funding": { |       "funding": { | ||||||
|         "type": "opencollective", |         "type": "opencollective", | ||||||
|         "url": "https://opencollective.com/preact" |         "url": "https://opencollective.com/preact" | ||||||
| @@ -177,9 +177,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/rollup": { |     "node_modules/rollup": { | ||||||
|       "version": "2.56.2", |       "version": "2.60.0", | ||||||
|       "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz", |       "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.0.tgz", | ||||||
|       "integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==", |       "integrity": "sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "rollup": "dist/bin/rollup" |         "rollup": "dist/bin/rollup" | ||||||
| @@ -201,9 +201,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/source-map-support": { |     "node_modules/source-map-support": { | ||||||
|       "version": "0.5.19", |       "version": "0.5.21", | ||||||
|       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", |       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", | ||||||
|       "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", |       "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "buffer-from": "^1.0.0", |         "buffer-from": "^1.0.0", | ||||||
| @@ -220,20 +220,28 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/terser": { |     "node_modules/terser": { | ||||||
|       "version": "5.7.1", |       "version": "5.10.0", | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|       "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", |       "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "commander": "^2.20.0", |         "commander": "^2.20.0", | ||||||
|         "source-map": "~0.7.2", |         "source-map": "~0.7.2", | ||||||
|         "source-map-support": "~0.5.19" |         "source-map-support": "~0.5.20" | ||||||
|       }, |       }, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "terser": "bin/terser" |         "terser": "bin/terser" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=10" |         "node": ">=10" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "acorn": "^8.5.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "acorn": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/tslib": { |     "node_modules/tslib": { | ||||||
| @@ -242,9 +250,9 @@ | |||||||
|       "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" |       "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" | ||||||
|     }, |     }, | ||||||
|     "node_modules/typescript": { |     "node_modules/typescript": { | ||||||
|       "version": "4.3.5", |       "version": "4.5.2", | ||||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", |       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", | ||||||
|       "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", |       "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "bin": { |       "bin": { | ||||||
|         "tsc": "bin/tsc", |         "tsc": "bin/tsc", | ||||||
| @@ -257,9 +265,9 @@ | |||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@rollup/plugin-typescript": { |     "@rollup/plugin-typescript": { | ||||||
|       "version": "8.2.5", |       "version": "8.3.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.2.5.tgz", |       "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", | ||||||
|       "integrity": "sha512-QL/LvDol/PAGB2O0S7/+q2HpSUNodpw7z6nGn9BfoVCPOZ0r4EALrojFU29Bkoi2Hr2jgTocTejJ5GGWZfOxbQ==", |       "integrity": "sha512-I5FpSvLbtAdwJ+naznv+B4sjXZUcIvLLceYpITAn7wAP8W0wqc5noLdGIp9HGVntNhRWXctwPYrSSFQxtl0FPA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@rollup/pluginutils": "^3.1.0", |         "@rollup/pluginutils": "^3.1.0", | ||||||
| @@ -324,9 +332,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "is-core-module": { |     "is-core-module": { | ||||||
|       "version": "2.6.0", |       "version": "2.8.0", | ||||||
|       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", | ||||||
|       "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", |       "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "has": "^1.0.3" |         "has": "^1.0.3" | ||||||
| @@ -345,9 +353,9 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "preact": { |     "preact": { | ||||||
|       "version": "10.5.14", |       "version": "10.5.15", | ||||||
|       "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.14.tgz", |       "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.15.tgz", | ||||||
|       "integrity": "sha512-KojoltCrshZ099ksUZ2OQKfbH66uquFoxHSbnwKbTJHeQNvx42EmC7wQVWNuDt6vC5s3nudRHFtKbpY4ijKlaQ==" |       "integrity": "sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA==" | ||||||
|     }, |     }, | ||||||
|     "requirejs": { |     "requirejs": { | ||||||
|       "version": "2.3.6", |       "version": "2.3.6", | ||||||
| @@ -366,9 +374,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "rollup": { |     "rollup": { | ||||||
|       "version": "2.56.2", |       "version": "2.60.0", | ||||||
|       "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz", |       "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.0.tgz", | ||||||
|       "integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==", |       "integrity": "sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "fsevents": "~2.3.2" |         "fsevents": "~2.3.2" | ||||||
| @@ -381,9 +389,9 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "source-map-support": { |     "source-map-support": { | ||||||
|       "version": "0.5.19", |       "version": "0.5.21", | ||||||
|       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", |       "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", | ||||||
|       "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", |       "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "buffer-from": "^1.0.0", |         "buffer-from": "^1.0.0", | ||||||
| @@ -399,14 +407,14 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "terser": { |     "terser": { | ||||||
|       "version": "5.7.1", |       "version": "5.10.0", | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz", |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", | ||||||
|       "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==", |       "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "commander": "^2.20.0", |         "commander": "^2.20.0", | ||||||
|         "source-map": "~0.7.2", |         "source-map": "~0.7.2", | ||||||
|         "source-map-support": "~0.5.19" |         "source-map-support": "~0.5.20" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "tslib": { |     "tslib": { | ||||||
| @@ -415,9 +423,9 @@ | |||||||
|       "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" |       "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" | ||||||
|     }, |     }, | ||||||
|     "typescript": { |     "typescript": { | ||||||
|       "version": "4.3.5", |       "version": "4.5.2", | ||||||
|       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", |       "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", | ||||||
|       "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==", |       "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", | ||||||
|       "dev": true |       "dev": true | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ import net.minecraft.core.BlockPos; | |||||||
| import net.minecraft.core.Direction; | import net.minecraft.core.Direction; | ||||||
| import net.minecraft.resources.ResourceLocation; | import net.minecraft.resources.ResourceLocation; | ||||||
| import net.minecraft.server.packs.resources.ReloadableResourceManager; | import net.minecraft.server.packs.resources.ReloadableResourceManager; | ||||||
|  | import net.minecraft.server.packs.resources.ResourceManager; | ||||||
| import net.minecraft.world.level.BlockGetter; | import net.minecraft.world.level.BlockGetter; | ||||||
| import net.minecraft.world.level.Level; | import net.minecraft.world.level.Level; | ||||||
| import net.minecraft.world.level.block.entity.BlockEntity; | import net.minecraft.world.level.block.entity.BlockEntity; | ||||||
| @@ -101,7 +102,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI | |||||||
|     @Override |     @Override | ||||||
|     public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) |     public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) | ||||||
|     { |     { | ||||||
|         ReloadableResourceManager manager = (ReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getResourceManager(); |         ResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); | ||||||
|         ResourceMount mount = ResourceMount.get( domain, subPath, manager ); |         ResourceMount mount = ResourceMount.get( domain, subPath, manager ); | ||||||
|         return mount.exists( "" ) ? mount : null; |         return mount.exists( "" ) ? mount : null; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -40,5 +40,8 @@ public interface ILuaContext | |||||||
|      * @throws LuaException If the task could not be queued, or if the task threw an exception. |      * @throws LuaException If the task could not be queued, or if the task threw an exception. | ||||||
|      */ |      */ | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; |     default MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException | ||||||
|  |     { | ||||||
|  |         return TaskCallback.make( this, task ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,16 +1,14 @@ | |||||||
| /* | /* | ||||||
|  * This file is part of ComputerCraft - http://www.computercraft.info |  * This file is part of the public ComputerCraft API - http://www.computercraft.info | ||||||
|  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. |  * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. | ||||||
|  * Send enquiries to dratcliffe@gmail.com |  * For help using the API, and posting your mods, visit the forums at computercraft.info. | ||||||
|  */ |  */ | ||||||
| package dan200.computercraft.core.asm; | package dan200.computercraft.api.lua; | ||||||
| 
 |  | ||||||
| import dan200.computercraft.api.lua.*; |  | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| 
 | 
 | ||||||
| public final class TaskCallback implements ILuaCallback | final class TaskCallback implements ILuaCallback | ||||||
| { | { | ||||||
|     private final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); |     private final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); | ||||||
|     private final long task; |     private final long task; | ||||||
| @@ -47,19 +45,7 @@ public final class TaskCallback implements ILuaCallback | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static Object[] checkUnwrap( MethodResult result ) |     static MethodResult make( ILuaContext context, ILuaTask func ) throws LuaException | ||||||
|     { |  | ||||||
|         if( result.getCallback() != null ) |  | ||||||
|         { |  | ||||||
|             // Due to how tasks are implemented, we can't currently return a MethodResult. This is an |  | ||||||
|             // entirely artificial limitation - we can remove it if it ever becomes an issue. |  | ||||||
|             throw new IllegalStateException( "Cannot return MethodResult for mainThread task." ); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return result.getResult(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static MethodResult make( ILuaContext context, ILuaTask func ) throws LuaException |  | ||||||
|     { |     { | ||||||
|         long task = context.issueMainThreadTask( func ); |         long task = context.issueMainThreadTask( func ); | ||||||
|         return new TaskCallback( task ).pull; |         return new TaskCallback( task ).pull; | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of the public ComputerCraft API - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. | ||||||
|  |  * For help using the API, and posting your mods, visit the forums at computercraft.info. | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.api.peripheral; | ||||||
|  | 
 | ||||||
|  | import dan200.computercraft.api.lua.GenericSource; | ||||||
|  | import net.minecraft.world.level.block.entity.BlockEntity; | ||||||
|  | import net.minecraftforge.items.IItemHandler; | ||||||
|  | 
 | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * A {@link GenericSource} which provides methods for a peripheral. | ||||||
|  |  * | ||||||
|  |  * Unlike a {@link GenericSource}, all methods <strong>should</strong> target the same type, for instance a | ||||||
|  |  * {@link BlockEntity} subclass or a capability interface. This is not currently enforced. | ||||||
|  |  */ | ||||||
|  | public interface GenericPeripheral extends GenericSource | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Get the type of the exposed peripheral. | ||||||
|  |      * | ||||||
|  |      * Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the | ||||||
|  |      * resulting peripheral uses the resource name of the wrapped {@link BlockEntity} (for instance {@literal minecraft:chest}). | ||||||
|  |      * | ||||||
|  |      * However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows | ||||||
|  |      * you to do so. | ||||||
|  |      * | ||||||
|  |      * When multiple {@link GenericPeripheral}s return a non-empty peripheral type for a single tile entity, the | ||||||
|  |      * lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be | ||||||
|  |      * implemented when your peripheral targets a single tile entity <strong>AND</strong> it's likely that you're the | ||||||
|  |      * only mod to do so. Similarly this should <strong>NOT</strong> be implemented when your methods target a | ||||||
|  |      * capability or other interface (i.e. {@link IItemHandler}). | ||||||
|  |      * | ||||||
|  |      * @return The type of this peripheral or {@link PeripheralType#untyped()}. | ||||||
|  |      * @see IPeripheral#getType() | ||||||
|  |      */ | ||||||
|  |     @Nonnull | ||||||
|  |     default PeripheralType getType() | ||||||
|  |     { | ||||||
|  |         return PeripheralType.untyped(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,62 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of the public ComputerCraft API - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. | ||||||
|  |  * For help using the API, and posting your mods, visit the forums at computercraft.info. | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.api.peripheral; | ||||||
|  | 
 | ||||||
|  | import com.google.common.base.Strings; | ||||||
|  | 
 | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import javax.annotation.Nullable; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * The type of a {@link GenericPeripheral}. | ||||||
|  |  * | ||||||
|  |  * When determining the final type of the resulting peripheral, the union of all types is taken, with the | ||||||
|  |  * lexicographically smallest non-empty name being chosen. | ||||||
|  |  */ | ||||||
|  | public final class PeripheralType | ||||||
|  | { | ||||||
|  |     private static final PeripheralType UNTYPED = new PeripheralType( null ); | ||||||
|  | 
 | ||||||
|  |     private final String type; | ||||||
|  | 
 | ||||||
|  |     public PeripheralType( String type ) | ||||||
|  |     { | ||||||
|  |         this.type = type; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * An empty peripheral type, used when a {@link GenericPeripheral} does not have an explicit type. | ||||||
|  |      * | ||||||
|  |      * @return The empty peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType untyped() | ||||||
|  |     { | ||||||
|  |         return UNTYPED; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new non-empty peripheral type. | ||||||
|  |      * | ||||||
|  |      * @param type The name of the type. | ||||||
|  |      * @return The constructed peripheral type. | ||||||
|  |      */ | ||||||
|  |     public static PeripheralType ofType( @Nonnull String type ) | ||||||
|  |     { | ||||||
|  |         if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); | ||||||
|  |         return new PeripheralType( type ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get the name of this peripheral type. This may be {@literal null}. | ||||||
|  |      * | ||||||
|  |      * @return The type of this peripheral. | ||||||
|  |      */ | ||||||
|  |     @Nullable | ||||||
|  |     public String getPrimaryType() | ||||||
|  |     { | ||||||
|  |         return type; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,58 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.client.render; | ||||||
|  | 
 | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  | import dan200.computercraft.api.turtle.ITurtleUpgrade; | ||||||
|  | import dan200.computercraft.api.turtle.TurtleSide; | ||||||
|  | import dan200.computercraft.shared.peripheral.monitor.TileMonitor; | ||||||
|  | import dan200.computercraft.shared.turtle.blocks.TileTurtle; | ||||||
|  | import net.minecraft.client.Minecraft; | ||||||
|  | import net.minecraft.world.level.block.entity.BlockEntity; | ||||||
|  | import net.minecraft.world.phys.BlockHitResult; | ||||||
|  | import net.minecraft.world.phys.HitResult; | ||||||
|  | import net.minecraftforge.api.distmarker.Dist; | ||||||
|  | import net.minecraftforge.client.event.RenderGameOverlayEvent; | ||||||
|  | import net.minecraftforge.eventbus.api.SubscribeEvent; | ||||||
|  | import net.minecraftforge.fml.common.Mod; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) | ||||||
|  | public class DebugOverlay | ||||||
|  | { | ||||||
|  |     @SubscribeEvent | ||||||
|  |     public static void onRenderText( RenderGameOverlayEvent.Text event ) | ||||||
|  |     { | ||||||
|  |         Minecraft minecraft = Minecraft.getInstance(); | ||||||
|  |         if( !minecraft.options.renderDebug || minecraft.level == null ) return; | ||||||
|  |         if( minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK ) return; | ||||||
|  | 
 | ||||||
|  |         BlockEntity tile = minecraft.level.getBlockEntity( ((BlockHitResult) minecraft.hitResult).getBlockPos() ); | ||||||
|  | 
 | ||||||
|  |         if( tile instanceof TileMonitor monitor ) | ||||||
|  |         { | ||||||
|  |             event.getRight().add( "" ); | ||||||
|  |             event.getRight().add( | ||||||
|  |                 String.format( "Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight() ) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         else if( tile instanceof TileTurtle turtle ) | ||||||
|  |         { | ||||||
|  |             event.getRight().add( "" ); | ||||||
|  |             event.getRight().add( "Targeted turtle:" ); | ||||||
|  |             event.getRight().add( String.format( "Id: %d", turtle.getComputerID() ) ); | ||||||
|  |             addTurtleUpgrade( event.getRight(), turtle, TurtleSide.LEFT ); | ||||||
|  |             addTurtleUpgrade( event.getRight(), turtle, TurtleSide.RIGHT ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void addTurtleUpgrade( List<String> out, TileTurtle turtle, TurtleSide side ) | ||||||
|  |     { | ||||||
|  |         ITurtleUpgrade upgrade = turtle.getUpgrade( side ); | ||||||
|  |         if( upgrade != null ) out.add( String.format( "Upgrade[%s]: %s", side, upgrade.getUpgradeID() ) ); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -15,6 +15,7 @@ import dan200.computercraft.api.lua.IArguments; | |||||||
| import dan200.computercraft.api.lua.LuaException; | import dan200.computercraft.api.lua.LuaException; | ||||||
| import dan200.computercraft.api.lua.LuaFunction; | import dan200.computercraft.api.lua.LuaFunction; | ||||||
| import dan200.computercraft.api.lua.MethodResult; | import dan200.computercraft.api.lua.MethodResult; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| import org.objectweb.asm.ClassWriter; | import org.objectweb.asm.ClassWriter; | ||||||
| import org.objectweb.asm.MethodVisitor; | import org.objectweb.asm.MethodVisitor; | ||||||
| import org.objectweb.asm.Type; | import org.objectweb.asm.Type; | ||||||
| @@ -108,7 +109,7 @@ public final class Generator<T> | |||||||
|             if( instance == null ) continue; |             if( instance == null ) continue; | ||||||
| 
 | 
 | ||||||
|             if( methods == null ) methods = new ArrayList<>(); |             if( methods == null ) methods = new ArrayList<>(); | ||||||
|             addMethod( methods, method, annotation, instance ); |             addMethod( methods, method, annotation, null, instance ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for( GenericMethod method : GenericMethod.all() ) |         for( GenericMethod method : GenericMethod.all() ) | ||||||
| @@ -119,7 +120,7 @@ public final class Generator<T> | |||||||
|             if( instance == null ) continue; |             if( instance == null ) continue; | ||||||
| 
 | 
 | ||||||
|             if( methods == null ) methods = new ArrayList<>(); |             if( methods == null ) methods = new ArrayList<>(); | ||||||
|             addMethod( methods, method.method, method.annotation, instance ); |             addMethod( methods, method.method, method.annotation, method.peripheralType, instance ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if( methods == null ) return Collections.emptyList(); |         if( methods == null ) return Collections.emptyList(); | ||||||
| @@ -127,7 +128,7 @@ public final class Generator<T> | |||||||
|         return Collections.unmodifiableList( methods ); |         return Collections.unmodifiableList( methods ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void addMethod( List<NamedMethod<T>> methods, Method method, LuaFunction annotation, T instance ) |     private void addMethod( List<NamedMethod<T>> methods, Method method, LuaFunction annotation, PeripheralType genericType, T instance ) | ||||||
|     { |     { | ||||||
|         if( annotation.mainThread() ) instance = wrap.apply( instance ); |         if( annotation.mainThread() ) instance = wrap.apply( instance ); | ||||||
| 
 | 
 | ||||||
| @@ -135,13 +136,13 @@ public final class Generator<T> | |||||||
|         boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); |         boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); | ||||||
|         if( names.length == 0 ) |         if( names.length == 0 ) | ||||||
|         { |         { | ||||||
|             methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); |             methods.add( new NamedMethod<>( method.getName(), instance, isSimple, genericType ) ); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             for( String name : names ) |             for( String name : names ) | ||||||
|             { |             { | ||||||
|                 methods.add( new NamedMethod<>( name, instance, isSimple ) ); |                 methods.add( new NamedMethod<>( name, instance, isSimple, genericType ) ); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ package dan200.computercraft.core.asm; | |||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.api.lua.GenericSource; | import dan200.computercraft.api.lua.GenericSource; | ||||||
| import dan200.computercraft.api.lua.LuaFunction; | import dan200.computercraft.api.lua.LuaFunction; | ||||||
|  | import dan200.computercraft.api.peripheral.GenericPeripheral; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||||
| @@ -18,6 +20,7 @@ import java.util.Arrays; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; | import java.util.Objects; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.Stream; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A generic method is a method belonging to a {@link GenericSource} with a known target. |  * A generic method is a method belonging to a {@link GenericSource} with a known target. | ||||||
| @@ -27,15 +30,17 @@ public class GenericMethod | |||||||
|     final Method method; |     final Method method; | ||||||
|     final LuaFunction annotation; |     final LuaFunction annotation; | ||||||
|     final Class<?> target; |     final Class<?> target; | ||||||
|  |     final PeripheralType peripheralType; | ||||||
| 
 | 
 | ||||||
|     private static final List<GenericSource> sources = new ArrayList<>(); |     private static final List<GenericSource> sources = new ArrayList<>(); | ||||||
|     private static List<GenericMethod> cache; |     private static List<GenericMethod> cache; | ||||||
| 
 | 
 | ||||||
|     GenericMethod( Method method, LuaFunction annotation, Class<?> target ) |     GenericMethod( Method method, LuaFunction annotation, Class<?> target, PeripheralType peripheralType ) | ||||||
|     { |     { | ||||||
|         this.method = method; |         this.method = method; | ||||||
|         this.annotation = annotation; |         this.annotation = annotation; | ||||||
|         this.target = target; |         this.target = target; | ||||||
|  |         this.peripheralType = peripheralType; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @@ -46,10 +51,28 @@ public class GenericMethod | |||||||
|     static List<GenericMethod> all() |     static List<GenericMethod> all() | ||||||
|     { |     { | ||||||
|         if( cache != null ) return cache; |         if( cache != null ) return cache; | ||||||
|         return cache = sources.stream() |         return cache = sources.stream().flatMap( GenericMethod::getMethods ).collect( Collectors.toList() ); | ||||||
|             .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) |     } | ||||||
|             .map( method -> | 
 | ||||||
|             { |     public static synchronized void register( @Nonnull GenericSource source ) | ||||||
|  |     { | ||||||
|  |         Objects.requireNonNull( source, "Source cannot be null" ); | ||||||
|  | 
 | ||||||
|  |         if( cache != null ) | ||||||
|  |         { | ||||||
|  |             ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         sources.add( source ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static Stream<GenericMethod> getMethods( GenericSource source ) | ||||||
|  |     { | ||||||
|  |         Class<?> klass = source.getClass(); | ||||||
|  |         PeripheralType type = source instanceof GenericPeripheral ? ((GenericPeripheral) source).getType() : null; | ||||||
|  | 
 | ||||||
|  |         return Arrays.stream( klass.getDeclaredMethods() ) | ||||||
|  |             .map( method -> { | ||||||
|                 LuaFunction annotation = method.getAnnotation( LuaFunction.class ); |                 LuaFunction annotation = method.getAnnotation( LuaFunction.class ); | ||||||
|                 if( annotation == null ) return null; |                 if( annotation == null ) return null; | ||||||
| 
 | 
 | ||||||
| @@ -69,22 +92,8 @@ public class GenericMethod | |||||||
|                 Class<?> target = Reflect.getRawType( method, types[0], false ); |                 Class<?> target = Reflect.getRawType( method, types[0], false ); | ||||||
|                 if( target == null ) return null; |                 if( target == null ) return null; | ||||||
| 
 | 
 | ||||||
|                 return new GenericMethod( method, annotation, target ); |                 return new GenericMethod( method, annotation, target, type ); | ||||||
|             } ) |             } ) | ||||||
|             .filter( Objects::nonNull ) |             .filter( Objects::nonNull ); | ||||||
|             .collect( Collectors.toList() ); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     public static synchronized void register( @Nonnull GenericSource source ) |  | ||||||
|     { |  | ||||||
|         Objects.requireNonNull( source, "Source cannot be null" ); |  | ||||||
| 
 |  | ||||||
|         if( cache != null ) |  | ||||||
|         { |  | ||||||
|             ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         sources.add( source ); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ import java.util.Collections; | |||||||
| public interface LuaMethod | public interface LuaMethod | ||||||
| { | { | ||||||
|     Generator<LuaMethod> GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), |     Generator<LuaMethod> GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), | ||||||
|         m -> ( target, context, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ) |         m -> ( target, context, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, args ) ) ) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     IntCache<LuaMethod> DYNAMIC = new IntCache<>( |     IntCache<LuaMethod> DYNAMIC = new IntCache<>( | ||||||
|   | |||||||
| @@ -5,7 +5,10 @@ | |||||||
|  */ |  */ | ||||||
| package dan200.computercraft.core.asm; | package dan200.computercraft.core.asm; | ||||||
| 
 | 
 | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
|  | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
|  | import javax.annotation.Nullable; | ||||||
| 
 | 
 | ||||||
| public final class NamedMethod<T> | public final class NamedMethod<T> | ||||||
| { | { | ||||||
| @@ -13,11 +16,14 @@ public final class NamedMethod<T> | |||||||
|     private final T method; |     private final T method; | ||||||
|     private final boolean nonYielding; |     private final boolean nonYielding; | ||||||
| 
 | 
 | ||||||
|     NamedMethod( String name, T method, boolean nonYielding ) |     private final PeripheralType genericType; | ||||||
|  | 
 | ||||||
|  |     NamedMethod( String name, T method, boolean nonYielding, PeripheralType genericType ) | ||||||
|     { |     { | ||||||
|         this.name = name; |         this.name = name; | ||||||
|         this.method = method; |         this.method = method; | ||||||
|         this.nonYielding = nonYielding; |         this.nonYielding = nonYielding; | ||||||
|  |         this.genericType = genericType; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
| @@ -36,4 +42,10 @@ public final class NamedMethod<T> | |||||||
|     { |     { | ||||||
|         return nonYielding; |         return nonYielding; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     public PeripheralType getGenericType() | ||||||
|  |     { | ||||||
|  |         return genericType; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ import java.util.Arrays; | |||||||
| public interface PeripheralMethod | public interface PeripheralMethod | ||||||
| { | { | ||||||
|     Generator<PeripheralMethod> GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), |     Generator<PeripheralMethod> GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), | ||||||
|         m -> ( target, context, computer, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ) |         m -> ( target, context, computer, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, computer, args ) ) ) | ||||||
|     ); |     ); | ||||||
| 
 | 
 | ||||||
|     IntCache<PeripheralMethod> DYNAMIC = new IntCache<>( |     IntCache<PeripheralMethod> DYNAMIC = new IntCache<>( | ||||||
|   | |||||||
| @@ -0,0 +1,27 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.core.asm; | ||||||
|  | 
 | ||||||
|  | import dan200.computercraft.api.lua.MethodResult; | ||||||
|  | 
 | ||||||
|  | final class ResultHelpers | ||||||
|  | { | ||||||
|  |     private ResultHelpers() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     static Object[] checkNormalResult( MethodResult result ) | ||||||
|  |     { | ||||||
|  |         if( result.getCallback() != null ) | ||||||
|  |         { | ||||||
|  |             // Due to how tasks are implemented, we can't currently return a MethodResult. This is an | ||||||
|  |             // entirely artificial limitation - we can remove it if it ever becomes an issue. | ||||||
|  |             throw new IllegalStateException( "Must return MethodResult.of from mainThread function." ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result.getResult(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -93,7 +93,7 @@ public final class MainThread | |||||||
|             executor.updateTime(); |             executor.updateTime(); | ||||||
| 
 | 
 | ||||||
|             // We're not currently on the queue, so update its current execution time to |             // We're not currently on the queue, so update its current execution time to | ||||||
|             // ensure its at least as high as the minimum. |             // ensure it's at least as high as the minimum. | ||||||
|             long newRuntime = minimumTime; |             long newRuntime = minimumTime; | ||||||
| 
 | 
 | ||||||
|             // Slow down new computers a little bit. |             // Slow down new computers a little bit. | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ package dan200.computercraft.core.filesystem; | |||||||
| 
 | 
 | ||||||
| import com.google.common.cache.Cache; | import com.google.common.cache.Cache; | ||||||
| import com.google.common.cache.CacheBuilder; | import com.google.common.cache.CacheBuilder; | ||||||
| import com.google.common.collect.MapMaker; |  | ||||||
| import com.google.common.io.ByteStreams; | import com.google.common.io.ByteStreams; | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.api.filesystem.IMount; | import dan200.computercraft.api.filesystem.IMount; | ||||||
| @@ -15,10 +14,11 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel; | |||||||
| import dan200.computercraft.shared.util.IoUtil; | import dan200.computercraft.shared.util.IoUtil; | ||||||
| import net.minecraft.ResourceLocationException; | import net.minecraft.ResourceLocationException; | ||||||
| import net.minecraft.resources.ResourceLocation; | import net.minecraft.resources.ResourceLocation; | ||||||
| import net.minecraft.server.packs.resources.ReloadableResourceManager; | import net.minecraft.server.packs.resources.PreparableReloadListener; | ||||||
| import net.minecraft.server.packs.resources.Resource; | import net.minecraft.server.packs.resources.Resource; | ||||||
| import net.minecraft.server.packs.resources.ResourceManager; | import net.minecraft.server.packs.resources.ResourceManager; | ||||||
| import net.minecraft.server.packs.resources.ResourceManagerReloadListener; | import net.minecraft.server.packs.resources.SimplePreparableReloadListener; | ||||||
|  | import net.minecraft.util.profiling.ProfilerFiller; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| @@ -27,7 +27,9 @@ import java.io.IOException; | |||||||
| import java.io.InputStream; | import java.io.InputStream; | ||||||
| import java.nio.channels.Channels; | import java.nio.channels.Channels; | ||||||
| import java.nio.channels.ReadableByteChannel; | import java.nio.channels.ReadableByteChannel; | ||||||
| import java.util.*; | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| 
 | 
 | ||||||
| public final class ResourceMount implements IMount | public final class ResourceMount implements IMount | ||||||
| @@ -56,50 +58,37 @@ public final class ResourceMount implements IMount | |||||||
|         .<FileEntry, byte[]>weigher( ( k, v ) -> v.length ) |         .<FileEntry, byte[]>weigher( ( k, v ) -> v.length ) | ||||||
|         .build(); |         .build(); | ||||||
| 
 | 
 | ||||||
|     private static final MapMaker CACHE_TEMPLATE = new MapMaker().weakValues().concurrencyLevel( 1 ); |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes. |      * Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes. | ||||||
|      */ |      */ | ||||||
|     private static final Map<ReloadableResourceManager, Map<ResourceLocation, ResourceMount>> MOUNT_CACHE = new WeakHashMap<>( 2 ); |     private static final Map<ResourceLocation, ResourceMount> MOUNT_CACHE = new HashMap<>( 2 ); | ||||||
| 
 | 
 | ||||||
|     private final String namespace; |     private final String namespace; | ||||||
|     private final String subPath; |     private final String subPath; | ||||||
|     private final ReloadableResourceManager manager; |     private ResourceManager manager; | ||||||
| 
 | 
 | ||||||
|     @Nullable |     @Nullable | ||||||
|     private FileEntry root; |     private FileEntry root; | ||||||
| 
 | 
 | ||||||
|     public static ResourceMount get( String namespace, String subPath, ReloadableResourceManager manager ) |     public static ResourceMount get( String namespace, String subPath, ResourceManager manager ) | ||||||
|     { |     { | ||||||
|         Map<ResourceLocation, ResourceMount> cache; |         ResourceLocation path = new ResourceLocation( namespace, subPath ); | ||||||
| 
 |  | ||||||
|         synchronized( MOUNT_CACHE ) |         synchronized( MOUNT_CACHE ) | ||||||
|         { |         { | ||||||
|             cache = MOUNT_CACHE.get( manager ); |             ResourceMount mount = MOUNT_CACHE.get( path ); | ||||||
|             if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() ); |             if( mount == null ) MOUNT_CACHE.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         ResourceLocation path = new ResourceLocation( namespace, subPath ); |  | ||||||
|         synchronized( cache ) |  | ||||||
|         { |  | ||||||
|             ResourceMount mount = cache.get( path ); |  | ||||||
|             if( mount == null ) cache.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); |  | ||||||
|             return mount; |             return mount; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private ResourceMount( String namespace, String subPath, ReloadableResourceManager manager ) |     private ResourceMount( String namespace, String subPath, ResourceManager manager ) | ||||||
|     { |     { | ||||||
|         this.namespace = namespace; |         this.namespace = namespace; | ||||||
|         this.subPath = subPath; |         this.subPath = subPath; | ||||||
|         this.manager = manager; |         load( manager ); | ||||||
| 
 |  | ||||||
|         Listener.INSTANCE.add( manager, this ); |  | ||||||
|         if( root == null ) load(); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void load() |     private void load( ResourceManager manager ) | ||||||
|     { |     { | ||||||
|         boolean hasAny = false; |         boolean hasAny = false; | ||||||
|         String existingNamespace = null; |         String existingNamespace = null; | ||||||
| @@ -117,6 +106,7 @@ public final class ResourceMount implements IMount | |||||||
|             hasAny = true; |             hasAny = true; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.manager = manager; | ||||||
|         root = hasAny ? newRoot : null; |         root = hasAny ? newRoot : null; | ||||||
| 
 | 
 | ||||||
|         if( !hasAny ) |         if( !hasAny ) | ||||||
| @@ -292,28 +282,30 @@ public final class ResourceMount implements IMount | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * A {@link ResourceManagerReloadListener} which reloads any associated mounts. |      * A {@link PreparableReloadListener} which reloads any associated mounts and correctly updates the resource manager | ||||||
|      * |      * they point to. | ||||||
|      * While people should really be keeping a permanent reference to this, some people construct it every |  | ||||||
|      * method call, so let's make this as small as possible. |  | ||||||
|      */ |      */ | ||||||
|     static class Listener implements ResourceManagerReloadListener |     public static final SimplePreparableReloadListener<Void> RELOAD_LISTENER = new SimplePreparableReloadListener<>() | ||||||
|     { |     { | ||||||
|         private static final Listener INSTANCE = new Listener(); |         @Nonnull | ||||||
| 
 |         @Override | ||||||
|         private final Set<ResourceMount> mounts = Collections.newSetFromMap( new WeakHashMap<>() ); |         protected Void prepare( @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) | ||||||
|         private final Set<ReloadableResourceManager> managers = Collections.newSetFromMap( new WeakHashMap<>() ); |         { | ||||||
|  |             profiler.push( "Reloading ComputerCraft mounts" ); | ||||||
|  |             try | ||||||
|  |             { | ||||||
|  |                 for( ResourceMount mount : MOUNT_CACHE.values() ) mount.load( manager ); | ||||||
|  |             } | ||||||
|  |             finally | ||||||
|  |             { | ||||||
|  |                 profiler.pop(); | ||||||
|  |             } | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|         public void onResourceManagerReload( @Nonnull ResourceManager manager ) |         protected void apply( @Nonnull Void result, @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) | ||||||
|         { |         { | ||||||
|             for( ResourceMount mount : mounts ) mount.load(); |  | ||||||
|         } |         } | ||||||
| 
 |     }; | ||||||
|         synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) |  | ||||||
|         { |  | ||||||
|             if( managers.add( manager ) ) manager.registerReloadListener( this ); |  | ||||||
|             mounts.add( mount ); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,8 +9,6 @@ import dan200.computercraft.ComputerCraft; | |||||||
| import dan200.computercraft.api.lua.ILuaContext; | import dan200.computercraft.api.lua.ILuaContext; | ||||||
| import dan200.computercraft.api.lua.ILuaTask; | import dan200.computercraft.api.lua.ILuaTask; | ||||||
| import dan200.computercraft.api.lua.LuaException; | import dan200.computercraft.api.lua.LuaException; | ||||||
| import dan200.computercraft.api.lua.MethodResult; |  | ||||||
| import dan200.computercraft.core.asm.TaskCallback; |  | ||||||
| import dan200.computercraft.core.computer.Computer; | import dan200.computercraft.core.computer.Computer; | ||||||
| import dan200.computercraft.core.computer.MainThread; | import dan200.computercraft.core.computer.MainThread; | ||||||
| 
 | 
 | ||||||
| @@ -68,11 +66,4 @@ class LuaContext implements ILuaContext | |||||||
|             throw new LuaException( "Task limit exceeded" ); |             throw new LuaException( "Task limit exceeded" ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     @Nonnull |  | ||||||
|     @Override |  | ||||||
|     public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException |  | ||||||
|     { |  | ||||||
|         return TaskCallback.make( this, task ); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ package dan200.computercraft.shared; | |||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
| import dan200.computercraft.core.apis.http.NetworkUtils; | import dan200.computercraft.core.apis.http.NetworkUtils; | ||||||
| import dan200.computercraft.core.computer.MainThread; | import dan200.computercraft.core.computer.MainThread; | ||||||
|  | import dan200.computercraft.core.filesystem.ResourceMount; | ||||||
| import dan200.computercraft.core.tracking.ComputerMBean; | import dan200.computercraft.core.tracking.ComputerMBean; | ||||||
| import dan200.computercraft.core.tracking.Tracking; | import dan200.computercraft.core.tracking.Tracking; | ||||||
| import dan200.computercraft.shared.command.CommandComputerCraft; | import dan200.computercraft.shared.command.CommandComputerCraft; | ||||||
| @@ -23,6 +24,7 @@ import net.minecraft.world.level.storage.loot.BuiltInLootTables; | |||||||
| import net.minecraft.world.level.storage.loot.LootPool; | import net.minecraft.world.level.storage.loot.LootPool; | ||||||
| import net.minecraft.world.level.storage.loot.entries.LootTableReference; | import net.minecraft.world.level.storage.loot.entries.LootTableReference; | ||||||
| import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; | import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; | ||||||
|  | import net.minecraftforge.event.AddReloadListenerEvent; | ||||||
| import net.minecraftforge.event.LootTableLoadEvent; | import net.minecraftforge.event.LootTableLoadEvent; | ||||||
| import net.minecraftforge.event.RegisterCommandsEvent; | import net.minecraftforge.event.RegisterCommandsEvent; | ||||||
| import net.minecraftforge.event.TickEvent; | import net.minecraftforge.event.TickEvent; | ||||||
| @@ -138,4 +140,10 @@ public final class CommonHooks | |||||||
|             .name( "computercraft_treasure" ) |             .name( "computercraft_treasure" ) | ||||||
|             .build() ); |             .build() ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @SubscribeEvent | ||||||
|  |     public static void onAddReloadListeners( AddReloadListenerEvent event ) | ||||||
|  |     { | ||||||
|  |         event.addListener( ResourceMount.RELOAD_LISTENER ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; | |||||||
| import net.minecraft.world.level.block.entity.BlockEntityType; | import net.minecraft.world.level.block.entity.BlockEntityType; | ||||||
| import net.minecraft.world.level.block.state.BlockState; | import net.minecraft.world.level.block.state.BlockState; | ||||||
| import net.minecraft.world.phys.BlockHitResult; | import net.minecraft.world.phys.BlockHitResult; | ||||||
|  | import net.minecraftforge.common.util.Constants; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| 
 | 
 | ||||||
| @@ -35,7 +36,7 @@ public abstract class TileGeneric extends BlockEntity | |||||||
|         setChanged(); |         setChanged(); | ||||||
|         BlockPos pos = getBlockPos(); |         BlockPos pos = getBlockPos(); | ||||||
|         BlockState state = getBlockState(); |         BlockState state = getBlockState(); | ||||||
|         getLevel().sendBlockUpdated( pos, state, state, 3 ); |         getLevel().sendBlockUpdated( pos, state, state, Constants.BlockFlags.DEFAULT ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|   | |||||||
| @@ -15,12 +15,16 @@ import dan200.computercraft.shared.util.NBTUtil; | |||||||
| import net.minecraft.commands.CommandSourceStack; | import net.minecraft.commands.CommandSourceStack; | ||||||
| import net.minecraft.commands.Commands; | import net.minecraft.commands.Commands; | ||||||
| import net.minecraft.core.BlockPos; | import net.minecraft.core.BlockPos; | ||||||
|  | import net.minecraft.core.Registry; | ||||||
| import net.minecraft.nbt.CompoundTag; | import net.minecraft.nbt.CompoundTag; | ||||||
|  | import net.minecraft.resources.ResourceKey; | ||||||
|  | import net.minecraft.resources.ResourceLocation; | ||||||
| import net.minecraft.server.MinecraftServer; | import net.minecraft.server.MinecraftServer; | ||||||
| import net.minecraft.world.level.Level; | import net.minecraft.world.level.Level; | ||||||
| import net.minecraft.world.level.block.entity.BlockEntity; | import net.minecraft.world.level.block.entity.BlockEntity; | ||||||
| import net.minecraft.world.level.block.state.BlockState; | import net.minecraft.world.level.block.state.BlockState; | ||||||
| 
 | 
 | ||||||
|  | import javax.annotation.Nonnull; | ||||||
| import java.util.*; | import java.util.*; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @@ -187,22 +191,24 @@ public class CommandAPI implements ILuaAPI | |||||||
|      * Blocks are traversed by ascending y level, followed by z and x - the returned |      * Blocks are traversed by ascending y level, followed by z and x - the returned | ||||||
|      * table may be indexed using `x + z*width + y*depth*depth`. |      * table may be indexed using `x + z*width + y*depth*depth`. | ||||||
|      * |      * | ||||||
|      * @param minX The start x coordinate of the range to query. |      * @param minX      The start x coordinate of the range to query. | ||||||
|      * @param minY The start y coordinate of the range to query. |      * @param minY      The start y coordinate of the range to query. | ||||||
|      * @param minZ The start z coordinate of the range to query. |      * @param minZ      The start z coordinate of the range to query. | ||||||
|      * @param maxX The end x coordinate of the range to query. |      * @param maxX      The end x coordinate of the range to query. | ||||||
|      * @param maxY The end y coordinate of the range to query. |      * @param maxY      The end y coordinate of the range to query. | ||||||
|      * @param maxZ The end z coordinate of the range to query. |      * @param maxZ      The end z coordinate of the range to query. | ||||||
|  |      * @param dimension The dimension to query (e.g. "minecraft:overworld"). Defaults to the current dimension. | ||||||
|      * @return A list of information about each block. |      * @return A list of information about each block. | ||||||
|      * @throws LuaException If the coordinates are not within the world. |      * @throws LuaException If the coordinates are not within the world. | ||||||
|      * @throws LuaException If trying to get information about more than 4096 blocks. |      * @throws LuaException If trying to get information about more than 4096 blocks. | ||||||
|      * @cc.since 1.76 |      * @cc.since 1.76 | ||||||
|  |      * @cc.changed 1.99 Added {@code dimension} argument. | ||||||
|      */ |      */ | ||||||
|     @LuaFunction( mainThread = true ) |     @LuaFunction( mainThread = true ) | ||||||
|     public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException |     public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ, Optional<String> dimension ) throws LuaException | ||||||
|     { |     { | ||||||
|         // Get the details of the block |         // Get the details of the block | ||||||
|         Level world = computer.getLevel(); |         Level world = getLevel( dimension ); | ||||||
|         BlockPos min = new BlockPos( |         BlockPos min = new BlockPos( | ||||||
|             Math.min( minX, maxX ), |             Math.min( minX, maxX ), | ||||||
|             Math.min( minY, maxY ), |             Math.min( minY, maxY ), | ||||||
| @@ -244,26 +250,38 @@ public class CommandAPI implements ILuaAPI | |||||||
|      * with @{turtle.inspect}). If there is a tile entity for that block, its NBT |      * with @{turtle.inspect}). If there is a tile entity for that block, its NBT | ||||||
|      * will also be returned. |      * will also be returned. | ||||||
|      * |      * | ||||||
|      * @param x The x position of the block to query. |      * @param x         The x position of the block to query. | ||||||
|      * @param y The y position of the block to query. |      * @param y         The y position of the block to query. | ||||||
|      * @param z The z position of the block to query. |      * @param z         The z position of the block to query. | ||||||
|  |      * @param dimension The dimension to query (e.g. "minecraft:overworld"). Defaults to the current dimension. | ||||||
|      * @return The given block's information. |      * @return The given block's information. | ||||||
|      * @throws LuaException If the coordinates are not within the world, or are not currently loaded. |      * @throws LuaException If the coordinates are not within the world, or are not currently loaded. | ||||||
|      * @cc.changed 1.76 Added block state info to return value |      * @cc.changed 1.76 Added block state info to return value | ||||||
|  |      * @cc.changed 1.99 Added {@code dimension} argument. | ||||||
|      */ |      */ | ||||||
|     @LuaFunction( mainThread = true ) |     @LuaFunction( mainThread = true ) | ||||||
|     public final Map<?, ?> getBlockInfo( int x, int y, int z ) throws LuaException |     public final Map<?, ?> getBlockInfo( int x, int y, int z, Optional<String> dimension ) throws LuaException | ||||||
|     { |     { | ||||||
|         // Get the details of the block |         Level level = getLevel( dimension ); | ||||||
|         Level world = computer.getLevel(); |  | ||||||
|         BlockPos position = new BlockPos( x, y, z ); |         BlockPos position = new BlockPos( x, y, z ); | ||||||
|         if( world != null && world.isInWorldBounds( position ) ) |         if( !level.isInWorldBounds( position ) ) throw new LuaException( "Co-ordinates out of range" ); | ||||||
|         { |         return getBlockInfo( level, position ); | ||||||
|             return getBlockInfo( world, position ); |     } | ||||||
|         } | 
 | ||||||
|         else |     @Nonnull | ||||||
|         { |     private Level getLevel( @Nonnull Optional<String> id ) throws LuaException | ||||||
|             throw new LuaException( "Co-ordinates out of range" ); |     { | ||||||
|         } |         Level currentLevel = computer.getLevel(); | ||||||
|  |         if( currentLevel == null ) throw new LuaException( "No world exists" ); | ||||||
|  | 
 | ||||||
|  |         if( !id.isPresent() ) return currentLevel; | ||||||
|  | 
 | ||||||
|  |         ResourceLocation dimensionId = ResourceLocation.tryParse( id.get() ); | ||||||
|  |         if( dimensionId == null ) throw new LuaException( "Invalid dimension name" ); | ||||||
|  | 
 | ||||||
|  |         Level level = currentLevel.getServer().getLevel( ResourceKey.create( Registry.DIMENSION_REGISTRY, dimensionId ) ); | ||||||
|  |         if( level == null ) throw new LuaException( "Unknown dimension" ); | ||||||
|  | 
 | ||||||
|  |         return level; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -25,11 +25,11 @@ class GenericPeripheral implements IDynamicPeripheral | |||||||
|     private final BlockEntity tile; |     private final BlockEntity tile; | ||||||
|     private final List<SaturatedMethod> methods; |     private final List<SaturatedMethod> methods; | ||||||
| 
 | 
 | ||||||
|     GenericPeripheral( BlockEntity tile, List<SaturatedMethod> methods ) |     GenericPeripheral( BlockEntity tile, String name, List<SaturatedMethod> methods ) | ||||||
|     { |     { | ||||||
|         ResourceLocation type = tile.getType().getRegistryName(); |         ResourceLocation type = tile.getType().getRegistryName(); | ||||||
|         this.tile = tile; |         this.tile = tile; | ||||||
|         this.type = type == null ? "unknown" : type.toString(); |         this.type = name != null ? name : (type != null ? type.toString() : "unknown"); | ||||||
|         this.methods = methods; |         this.methods = methods; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
| package dan200.computercraft.shared.peripheral.generic; | package dan200.computercraft.shared.peripheral.generic; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.api.peripheral.IPeripheral; | import dan200.computercraft.api.peripheral.IPeripheral; | ||||||
|  | import dan200.computercraft.api.peripheral.PeripheralType; | ||||||
| import dan200.computercraft.core.asm.NamedMethod; | import dan200.computercraft.core.asm.NamedMethod; | ||||||
| import dan200.computercraft.core.asm.PeripheralMethod; | import dan200.computercraft.core.asm.PeripheralMethod; | ||||||
| import net.minecraft.core.BlockPos; | import net.minecraft.core.BlockPos; | ||||||
| @@ -38,10 +39,10 @@ public class GenericPeripheralProvider | |||||||
|         BlockEntity tile = world.getBlockEntity( pos ); |         BlockEntity tile = world.getBlockEntity( pos ); | ||||||
|         if( tile == null ) return null; |         if( tile == null ) return null; | ||||||
| 
 | 
 | ||||||
|         ArrayList<SaturatedMethod> saturated = new ArrayList<>( 0 ); |         GenericPeripheralBuilder saturated = new GenericPeripheralBuilder(); | ||||||
| 
 | 
 | ||||||
|         List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() ); |         List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() ); | ||||||
|         if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods ); |         if( !tileMethods.isEmpty() ) saturated.addMethods( tile, tileMethods ); | ||||||
| 
 | 
 | ||||||
|         for( Capability<?> capability : capabilities ) |         for( Capability<?> capability : capabilities ) | ||||||
|         { |         { | ||||||
| @@ -50,20 +51,44 @@ public class GenericPeripheralProvider | |||||||
|                 List<NamedMethod<PeripheralMethod>> capabilityMethods = PeripheralMethod.GENERATOR.getMethods( contents.getClass() ); |                 List<NamedMethod<PeripheralMethod>> capabilityMethods = PeripheralMethod.GENERATOR.getMethods( contents.getClass() ); | ||||||
|                 if( capabilityMethods.isEmpty() ) return; |                 if( capabilityMethods.isEmpty() ) return; | ||||||
| 
 | 
 | ||||||
|                 addSaturated( saturated, contents, capabilityMethods ); |                 saturated.addMethods( contents, capabilityMethods ); | ||||||
|                 wrapper.addListener( cast( invalidate ) ); |                 wrapper.addListener( cast( invalidate ) ); | ||||||
|             } ); |             } ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return saturated.isEmpty() ? null : new GenericPeripheral( tile, saturated ); |         return saturated.toPeripheral( tile ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static void addSaturated( ArrayList<SaturatedMethod> saturated, Object target, List<NamedMethod<PeripheralMethod>> methods ) |     private static class GenericPeripheralBuilder | ||||||
|     { |     { | ||||||
|         saturated.ensureCapacity( saturated.size() + methods.size() ); |         String name; | ||||||
|         for( NamedMethod<PeripheralMethod> method : methods ) |         final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 ); | ||||||
|  | 
 | ||||||
|  |         IPeripheral toPeripheral( BlockEntity tile ) | ||||||
|         { |         { | ||||||
|             saturated.add( new SaturatedMethod( target, method ) ); |             if( methods.isEmpty() ) return null; | ||||||
|  | 
 | ||||||
|  |             methods.trimToSize(); | ||||||
|  |             return new GenericPeripheral( tile, name, methods ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods ) | ||||||
|  |         { | ||||||
|  |             ArrayList<SaturatedMethod> saturatedMethods = this.methods; | ||||||
|  |             saturatedMethods.ensureCapacity( saturatedMethods.size() + methods.size() ); | ||||||
|  |             for( NamedMethod<PeripheralMethod> method : methods ) | ||||||
|  |             { | ||||||
|  |                 saturatedMethods.add( new SaturatedMethod( target, method ) ); | ||||||
|  | 
 | ||||||
|  |                 // If we have a peripheral type, use it. Always pick the smallest one, so it's consistent (assuming mods | ||||||
|  |                 // don't change). | ||||||
|  |                 PeripheralType type = method.getGenericType(); | ||||||
|  |                 if( type != null && type.getPrimaryType() != null ) | ||||||
|  |                 { | ||||||
|  |                     String name = type.getPrimaryType(); | ||||||
|  |                     if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -92,7 +92,7 @@ public class BlockMonitor extends BlockGeneric | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             monitor.updateNeighbors(); |             monitor.expand(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,108 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.peripheral.monitor; | ||||||
|  | 
 | ||||||
|  | import dan200.computercraft.ComputerCraft; | ||||||
|  | import net.minecraft.core.BlockPos; | ||||||
|  | import net.minecraft.core.Direction; | ||||||
|  | import net.minecraft.world.level.Level; | ||||||
|  | import net.minecraft.world.level.block.entity.BlockEntity; | ||||||
|  | 
 | ||||||
|  | import java.util.Objects; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Expands a monitor into available space. This tries to expand in each direction until a fixed point is reached. | ||||||
|  |  */ | ||||||
|  | class Expander | ||||||
|  | { | ||||||
|  |     private final Level level; | ||||||
|  |     private final Direction down; | ||||||
|  |     private final Direction right; | ||||||
|  | 
 | ||||||
|  |     private TileMonitor origin; | ||||||
|  |     private int width; | ||||||
|  |     private int height; | ||||||
|  | 
 | ||||||
|  |     Expander( TileMonitor origin ) | ||||||
|  |     { | ||||||
|  |         this.origin = origin; | ||||||
|  |         width = origin.getWidth(); | ||||||
|  |         height = origin.getHeight(); | ||||||
|  | 
 | ||||||
|  |         level = Objects.requireNonNull( origin.getLevel(), "level cannot be null" ); | ||||||
|  |         down = origin.getDown(); | ||||||
|  |         right = origin.getRight(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void expand() | ||||||
|  |     { | ||||||
|  |         int changedCount = 0; | ||||||
|  | 
 | ||||||
|  |         // Impose a limit on the number of resizes we can attempt. There's a risk of getting into an infinite loop | ||||||
|  |         // if we merge right/down and the next monitor has a width/height of 0. This /should/ never happen - validation | ||||||
|  |         // will catch it - but I also have a complete lack of faith in the code. | ||||||
|  |         // As an aside, I think the actual limit is width+height resizes, but again - complete lack of faith. | ||||||
|  |         int changeLimit = ComputerCraft.monitorWidth * ComputerCraft.monitorHeight + 1; | ||||||
|  |         while( expandIn( true, false ) || expandIn( true, true ) || | ||||||
|  |             expandIn( false, false ) || expandIn( false, true ) | ||||||
|  |         ) | ||||||
|  |         { | ||||||
|  |             changedCount++; | ||||||
|  |             if( changedCount > changeLimit ) | ||||||
|  |             { | ||||||
|  |                 ComputerCraft.log.error( "Monitor has grown too much. This suggests there's an empty monitor in the world." ); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if( changedCount > 0 ) origin.resize( width, height ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Attempt to expand a monitor in a particular direction as much as possible. | ||||||
|  |      * | ||||||
|  |      * @param useXAxis   {@literal true} if we're expanding on the X Axis, {@literal false} if on the Y. | ||||||
|  |      * @param isPositive {@literal true} if we're expanding in the positive direction, {@literal false} if negative. | ||||||
|  |      * @return If the monitor changed. | ||||||
|  |      */ | ||||||
|  |     private boolean expandIn( boolean useXAxis, boolean isPositive ) | ||||||
|  |     { | ||||||
|  |         BlockPos pos = origin.getBlockPos(); | ||||||
|  |         int height = this.height, width = this.width; | ||||||
|  | 
 | ||||||
|  |         int otherOffset = isPositive ? (useXAxis ? width : height) : -1; | ||||||
|  |         BlockPos otherPos = useXAxis ? pos.relative( right, otherOffset ) : pos.relative( down, otherOffset ); | ||||||
|  |         BlockEntity other = level.getBlockEntity( otherPos ); | ||||||
|  |         if( !(other instanceof TileMonitor otherMonitor) || !origin.isCompatible( otherMonitor ) ) return false; | ||||||
|  | 
 | ||||||
|  |         if( useXAxis ) | ||||||
|  |         { | ||||||
|  |             if( otherMonitor.getYIndex() != 0 || otherMonitor.getHeight() != height ) return false; | ||||||
|  |             width += otherMonitor.getWidth(); | ||||||
|  |             if( width > ComputerCraft.monitorWidth ) return false; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             if( otherMonitor.getXIndex() != 0 || otherMonitor.getWidth() != width ) return false; | ||||||
|  |             height += otherMonitor.getHeight(); | ||||||
|  |             if( height > ComputerCraft.monitorHeight ) return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if( !isPositive ) | ||||||
|  |         { | ||||||
|  |             BlockEntity otherOrigin = level.getBlockEntity( otherMonitor.toWorldPos( 0, 0 ) ); | ||||||
|  |             if( otherOrigin == null || !origin.isCompatible( (TileMonitor) otherOrigin ) ) return false; | ||||||
|  | 
 | ||||||
|  |             origin = (TileMonitor) otherOrigin; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.width = width; | ||||||
|  |         this.height = height; | ||||||
|  | 
 | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @@ -33,6 +33,7 @@ import javax.annotation.Nonnull; | |||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import java.util.HashSet; | import java.util.HashSet; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
|  | import java.util.function.Consumer; | ||||||
| 
 | 
 | ||||||
| import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; | import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; | ||||||
| 
 | 
 | ||||||
| @@ -58,7 +59,6 @@ public class TileMonitor extends TileGeneric | |||||||
|     private boolean needsUpdate = false; |     private boolean needsUpdate = false; | ||||||
|     private boolean needsValidating = false; |     private boolean needsValidating = false; | ||||||
|     private boolean destroyed = false; |     private boolean destroyed = false; | ||||||
|     private boolean visiting = false; |  | ||||||
| 
 | 
 | ||||||
|     // MonitorWatcher state. |     // MonitorWatcher state. | ||||||
|     boolean enqueued; |     boolean enqueued; | ||||||
| @@ -79,7 +79,7 @@ public class TileMonitor extends TileGeneric | |||||||
|     public void clearRemoved() // TODO: Switch back to onLood |     public void clearRemoved() // TODO: Switch back to onLood | ||||||
|     { |     { | ||||||
|         super.clearRemoved(); |         super.clearRemoved(); | ||||||
|         needsValidating = true; |         needsValidating = true; // Same, tbh | ||||||
|         TickScheduler.schedule( this ); |         TickScheduler.schedule( this ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -160,30 +160,14 @@ public class TileMonitor extends TileGeneric | |||||||
|         if( needsUpdate ) |         if( needsUpdate ) | ||||||
|         { |         { | ||||||
|             needsUpdate = false; |             needsUpdate = false; | ||||||
|             updateNeighbors(); |             expand(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return; |         if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return; | ||||||
| 
 | 
 | ||||||
|         serverMonitor.clearChanged(); |         serverMonitor.clearChanged(); | ||||||
| 
 | 
 | ||||||
|         if( serverMonitor.pollResized() ) |         if( serverMonitor.pollResized() ) eachComputer( c -> c.queueEvent( "monitor_resize", c.getAttachmentName() ) ); | ||||||
|         { |  | ||||||
|             for( int x = 0; x < width; x++ ) |  | ||||||
|             { |  | ||||||
|                 for( int y = 0; y < height; y++ ) |  | ||||||
|                 { |  | ||||||
|                     TileMonitor monitor = getNeighbour( x, y ).getMonitor(); |  | ||||||
|                     if( monitor == null ) continue; |  | ||||||
| 
 |  | ||||||
|                     for( IComputerAccess computer : monitor.computers ) |  | ||||||
|                     { |  | ||||||
|                         computer.queueEvent( "monitor_resize", computer.getAttachmentName() ); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if( serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this ); |         if( serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @@ -208,11 +192,13 @@ public class TileMonitor extends TileGeneric | |||||||
|         return super.getCapability( cap, side ); |         return super.getCapability( cap, side ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Nullable | ||||||
|     public ServerMonitor getCachedServerMonitor() |     public ServerMonitor getCachedServerMonitor() | ||||||
|     { |     { | ||||||
|         return serverMonitor; |         return serverMonitor; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Nullable | ||||||
|     private ServerMonitor getServerMonitor() |     private ServerMonitor getServerMonitor() | ||||||
|     { |     { | ||||||
|         if( serverMonitor != null ) return serverMonitor; |         if( serverMonitor != null ) return serverMonitor; | ||||||
| @@ -223,6 +209,7 @@ public class TileMonitor extends TileGeneric | |||||||
|         return serverMonitor = origin.serverMonitor; |         return serverMonitor = origin.serverMonitor; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Nullable | ||||||
|     private ServerMonitor createServerMonitor() |     private ServerMonitor createServerMonitor() | ||||||
|     { |     { | ||||||
|         if( serverMonitor != null ) return serverMonitor; |         if( serverMonitor != null ) return serverMonitor; | ||||||
| @@ -238,7 +225,7 @@ public class TileMonitor extends TileGeneric | |||||||
|             { |             { | ||||||
|                 for( int y = 0; y < height; y++ ) |                 for( int y = 0; y < height; y++ ) | ||||||
|                 { |                 { | ||||||
|                     TileMonitor monitor = getNeighbour( x, y ).getMonitor(); |                     TileMonitor monitor = getLoadedMonitor( x, y ).getMonitor(); | ||||||
|                     if( monitor != null ) monitor.serverMonitor = serverMonitor; |                     if( monitor != null ) monitor.serverMonitor = serverMonitor; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -250,19 +237,20 @@ public class TileMonitor extends TileGeneric | |||||||
|             // Otherwise fetch the origin and attempt to get its monitor |             // Otherwise fetch the origin and attempt to get its monitor | ||||||
|             // Note this may load chunks, but we don't really have a choice here. |             // Note this may load chunks, but we don't really have a choice here. | ||||||
|             BlockPos pos = getBlockPos(); |             BlockPos pos = getBlockPos(); | ||||||
|             BlockEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) ); |             BlockEntity te = level.getBlockEntity( toWorldPos( 0, 0 ) ); | ||||||
|             if( !(te instanceof TileMonitor) ) return null; |             if( !(te instanceof TileMonitor) ) return null; | ||||||
| 
 | 
 | ||||||
|             return serverMonitor = ((TileMonitor) te).createServerMonitor(); |             return serverMonitor = ((TileMonitor) te).createServerMonitor(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Nullable | ||||||
|     public ClientMonitor getClientMonitor() |     public ClientMonitor getClientMonitor() | ||||||
|     { |     { | ||||||
|         if( clientMonitor != null ) return clientMonitor; |         if( clientMonitor != null ) return clientMonitor; | ||||||
| 
 | 
 | ||||||
|         BlockPos pos = getBlockPos(); |         BlockPos pos = getBlockPos(); | ||||||
|         BlockEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) ); |         BlockEntity te = level.getBlockEntity( toWorldPos( 0, 0 ) ); | ||||||
|         if( !(te instanceof TileMonitor) ) return null; |         if( !(te instanceof TileMonitor) ) return null; | ||||||
| 
 | 
 | ||||||
|         return clientMonitor = ((TileMonitor) te).clientMonitor; |         return clientMonitor = ((TileMonitor) te).clientMonitor; | ||||||
| @@ -383,10 +371,23 @@ public class TileMonitor extends TileGeneric | |||||||
|         return yIndex; |         return yIndex; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nonnull |     boolean isCompatible( TileMonitor other ) | ||||||
|     private MonitorState getSimilarMonitorAt( BlockPos pos ) |  | ||||||
|     { |     { | ||||||
|         if( pos.equals( getBlockPos() ) ) return MonitorState.present( this ); |         return !other.destroyed && advanced == other.advanced && getOrientation() == other.getOrientation() && getDirection() == other.getDirection(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get a tile within the current monitor only if it is loaded and compatible. | ||||||
|  |      * | ||||||
|  |      * @param x Absolute X position in monitor coordinates | ||||||
|  |      * @param y Absolute Y position in monitor coordinates | ||||||
|  |      * @return The located monitor | ||||||
|  |      */ | ||||||
|  |     @Nonnull | ||||||
|  |     private MonitorState getLoadedMonitor( int x, int y ) | ||||||
|  |     { | ||||||
|  |         if( x == xIndex && y == yIndex ) return MonitorState.present( this ); | ||||||
|  |         BlockPos pos = toWorldPos( x, y ); | ||||||
| 
 | 
 | ||||||
|         Level world = getLevel(); |         Level world = getLevel(); | ||||||
|         if( world == null || !world.isAreaLoaded( pos, 0 ) ) return MonitorState.UNLOADED; |         if( world == null || !world.isAreaLoaded( pos, 0 ) ) return MonitorState.UNLOADED; | ||||||
| @@ -394,27 +395,28 @@ public class TileMonitor extends TileGeneric | |||||||
|         BlockEntity tile = world.getBlockEntity( pos ); |         BlockEntity tile = world.getBlockEntity( pos ); | ||||||
|         if( !(tile instanceof TileMonitor monitor) ) return MonitorState.MISSING; |         if( !(tile instanceof TileMonitor monitor) ) return MonitorState.MISSING; | ||||||
| 
 | 
 | ||||||
|         return !monitor.visiting && !monitor.destroyed && advanced == monitor.advanced |         return isCompatible( monitor ) ? MonitorState.present( monitor ) : MonitorState.MISSING; | ||||||
|             && getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation() |  | ||||||
|             ? MonitorState.present( monitor ) : MonitorState.MISSING; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private MonitorState getNeighbour( int x, int y ) |  | ||||||
|     { |  | ||||||
|         BlockPos pos = getBlockPos(); |  | ||||||
|         Direction right = getRight(); |  | ||||||
|         Direction down = getDown(); |  | ||||||
|         int xOffset = -xIndex + x; |  | ||||||
|         int yOffset = -yIndex + y; |  | ||||||
|         return getSimilarMonitorAt( pos.relative( right, xOffset ).relative( down, yOffset ) ); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private MonitorState getOrigin() |     private MonitorState getOrigin() | ||||||
|     { |     { | ||||||
|         return getNeighbour( 0, 0 ); |         return getLoadedMonitor( 0, 0 ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void resize( int width, int height ) |     /** | ||||||
|  |      * Convert monitor coordinates to world coordinates. | ||||||
|  |      * | ||||||
|  |      * @param x Absolute X position in monitor coordinates | ||||||
|  |      * @param y Absolute Y position in monitor coordinates | ||||||
|  |      * @return The monitor's position. | ||||||
|  |      */ | ||||||
|  |     BlockPos toWorldPos( int x, int y ) | ||||||
|  |     { | ||||||
|  |         if( xIndex == x && yIndex == y ) return getBlockPos(); | ||||||
|  |         return getBlockPos().relative( getRight(), -xIndex + x ).relative( getDown(), -yIndex + y ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void resize( int width, int height ) | ||||||
|     { |     { | ||||||
|         // If we're not already the origin then we'll need to generate a new terminal. |         // If we're not already the origin then we'll need to generate a new terminal. | ||||||
|         if( xIndex != 0 || yIndex != 0 ) serverMonitor = null; |         if( xIndex != 0 || yIndex != 0 ) serverMonitor = null; | ||||||
| @@ -433,7 +435,7 @@ public class TileMonitor extends TileGeneric | |||||||
|         { |         { | ||||||
|             for( int y = 0; y < height; y++ ) |             for( int y = 0; y < height; y++ ) | ||||||
|             { |             { | ||||||
|                 TileMonitor monitor = getNeighbour( x, y ).getMonitor(); |                 TileMonitor monitor = getLoadedMonitor( x, y ).getMonitor(); | ||||||
|                 if( monitor != null && monitor.peripheral != null ) |                 if( monitor != null && monitor.peripheral != null ) | ||||||
|                 { |                 { | ||||||
|                     needsTerminal = true; |                     needsTerminal = true; | ||||||
| @@ -457,190 +459,78 @@ public class TileMonitor extends TileGeneric | |||||||
|         if( serverMonitor != null ) serverMonitor.rebuild(); |         if( serverMonitor != null ) serverMonitor.rebuild(); | ||||||
| 
 | 
 | ||||||
|         // Update the other monitors, setting coordinates, dimensions and the server terminal |         // Update the other monitors, setting coordinates, dimensions and the server terminal | ||||||
|  |         BlockPos pos = getBlockPos(); | ||||||
|  |         Direction down = getDown(), right = getRight(); | ||||||
|         for( int x = 0; x < width; x++ ) |         for( int x = 0; x < width; x++ ) | ||||||
|         { |         { | ||||||
|             for( int y = 0; y < height; y++ ) |             for( int y = 0; y < height; y++ ) | ||||||
|             { |             { | ||||||
|                 TileMonitor monitor = getNeighbour( x, y ).getMonitor(); |                 BlockEntity other = getLevel().getBlockEntity( pos.relative( right, x ).relative( down, y ) ); | ||||||
|                 if( monitor == null ) continue; |                 if( !(other instanceof TileMonitor monitor) || !isCompatible( monitor ) ) continue; | ||||||
| 
 | 
 | ||||||
|                 monitor.xIndex = x; |                 monitor.xIndex = x; | ||||||
|                 monitor.yIndex = y; |                 monitor.yIndex = y; | ||||||
|                 monitor.width = width; |                 monitor.width = width; | ||||||
|                 monitor.height = height; |                 monitor.height = height; | ||||||
|                 monitor.serverMonitor = serverMonitor; |                 monitor.serverMonitor = serverMonitor; | ||||||
|  |                 monitor.needsUpdate = monitor.needsValidating = false; | ||||||
|                 monitor.updateBlockState(); |                 monitor.updateBlockState(); | ||||||
|                 monitor.updateBlock(); |                 monitor.updateBlock(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean mergeLeft() |  | ||||||
|     { |  | ||||||
|         TileMonitor left = getNeighbour( -1, 0 ).getMonitor(); |  | ||||||
|         if( left == null || left.yIndex != 0 || left.height != height ) return false; |  | ||||||
| 
 |  | ||||||
|         int width = left.width + this.width; |  | ||||||
|         if( width > ComputerCraft.monitorWidth ) return false; |  | ||||||
| 
 |  | ||||||
|         TileMonitor origin = left.getOrigin().getMonitor(); |  | ||||||
|         if( origin != null ) origin.resize( width, height ); |  | ||||||
|         left.expand(); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private boolean mergeRight() |  | ||||||
|     { |  | ||||||
|         TileMonitor right = getNeighbour( width, 0 ).getMonitor(); |  | ||||||
|         if( right == null || right.yIndex != 0 || right.height != height ) return false; |  | ||||||
| 
 |  | ||||||
|         int width = this.width + right.width; |  | ||||||
|         if( width > ComputerCraft.monitorWidth ) return false; |  | ||||||
| 
 |  | ||||||
|         TileMonitor origin = getOrigin().getMonitor(); |  | ||||||
|         if( origin != null ) origin.resize( width, height ); |  | ||||||
|         expand(); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private boolean mergeUp() |  | ||||||
|     { |  | ||||||
|         TileMonitor above = getNeighbour( 0, height ).getMonitor(); |  | ||||||
|         if( above == null || above.xIndex != 0 || above.width != width ) return false; |  | ||||||
| 
 |  | ||||||
|         int height = above.height + this.height; |  | ||||||
|         if( height > ComputerCraft.monitorHeight ) return false; |  | ||||||
| 
 |  | ||||||
|         TileMonitor origin = getOrigin().getMonitor(); |  | ||||||
|         if( origin != null ) origin.resize( width, height ); |  | ||||||
|         expand(); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private boolean mergeDown() |  | ||||||
|     { |  | ||||||
|         TileMonitor below = getNeighbour( 0, -1 ).getMonitor(); |  | ||||||
|         if( below == null || below.xIndex != 0 || below.width != width ) return false; |  | ||||||
| 
 |  | ||||||
|         int height = this.height + below.height; |  | ||||||
|         if( height > ComputerCraft.monitorHeight ) return false; |  | ||||||
| 
 |  | ||||||
|         TileMonitor origin = below.getOrigin().getMonitor(); |  | ||||||
|         if( origin != null ) origin.resize( width, height ); |  | ||||||
|         below.expand(); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void updateNeighborsDeferred() |     void updateNeighborsDeferred() | ||||||
|     { |     { | ||||||
|         needsUpdate = true; |         needsUpdate = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void updateNeighbors() |  | ||||||
|     { |  | ||||||
|         contractNeighbours(); |  | ||||||
|         contract(); |  | ||||||
|         expand(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @SuppressWarnings( "StatementWithEmptyBody" ) |  | ||||||
|     void expand() |     void expand() | ||||||
|     { |     { | ||||||
|         while( mergeLeft() || mergeRight() || mergeUp() || mergeDown() ) ; |         TileMonitor monitor = getOrigin().getMonitor(); | ||||||
|  |         if( monitor != null && monitor.xIndex == 0 && monitor.yIndex == 0 ) new Expander( monitor ).expand(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void contractNeighbours() |     private void contractNeighbours() | ||||||
|     { |     { | ||||||
|         visiting = true; |         if( width == 1 && height == 1 ) return; | ||||||
|         if( xIndex > 0 ) | 
 | ||||||
|  |         BlockPos pos = getBlockPos(); | ||||||
|  |         Direction down = getDown(), right = getRight(); | ||||||
|  |         BlockPos origin = toWorldPos( 0, 0 ); | ||||||
|  | 
 | ||||||
|  |         TileMonitor toLeft = null, toAbove = null, toRight = null, toBelow = null; | ||||||
|  |         if( xIndex > 0 ) toLeft = tryResizeAt( pos.relative( right, -xIndex ), xIndex, 1 ); | ||||||
|  |         if( yIndex > 0 ) toAbove = tryResizeAt( origin, width, yIndex ); | ||||||
|  |         if( xIndex < width - 1 ) toRight = tryResizeAt( pos.relative( right, 1 ), width - xIndex - 1, 1 ); | ||||||
|  |         if( yIndex < height - 1 ) | ||||||
|         { |         { | ||||||
|             TileMonitor left = getNeighbour( xIndex - 1, yIndex ).getMonitor(); |             toBelow = tryResizeAt( origin.relative( down, yIndex + 1 ), width, height - yIndex - 1 ); | ||||||
|             if( left != null ) left.contract(); |  | ||||||
|         } |         } | ||||||
|         if( xIndex + 1 < width ) | 
 | ||||||
|         { |         if( toLeft != null ) toLeft.expand(); | ||||||
|             TileMonitor right = getNeighbour( xIndex + 1, yIndex ).getMonitor(); |         if( toAbove != null ) toAbove.expand(); | ||||||
|             if( right != null ) right.contract(); |         if( toRight != null ) toRight.expand(); | ||||||
|         } |         if( toBelow != null ) toBelow.expand(); | ||||||
|         if( yIndex > 0 ) |  | ||||||
|         { |  | ||||||
|             TileMonitor below = getNeighbour( xIndex, yIndex - 1 ).getMonitor(); |  | ||||||
|             if( below != null ) below.contract(); |  | ||||||
|         } |  | ||||||
|         if( yIndex + 1 < height ) |  | ||||||
|         { |  | ||||||
|             TileMonitor above = getNeighbour( xIndex, yIndex + 1 ).getMonitor(); |  | ||||||
|             if( above != null ) above.contract(); |  | ||||||
|         } |  | ||||||
|         visiting = false; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void contract() |     @Nullable | ||||||
|  |     private TileMonitor tryResizeAt( BlockPos pos, int width, int height ) | ||||||
|     { |     { | ||||||
|         int height = this.height; |         BlockEntity tile = level.getBlockEntity( pos ); | ||||||
|         int width = this.width; |         if( tile instanceof TileMonitor monitor && isCompatible( monitor ) ) | ||||||
| 
 |  | ||||||
|         TileMonitor origin = getOrigin().getMonitor(); |  | ||||||
|         if( origin == null ) |  | ||||||
|         { |         { | ||||||
|             TileMonitor right = width > 1 ? getNeighbour( 1, 0 ).getMonitor() : null; |             monitor.resize( width, height ); | ||||||
|             TileMonitor below = height > 1 ? getNeighbour( 0, 1 ).getMonitor() : null; |             return monitor; | ||||||
| 
 |  | ||||||
|             if( right != null ) right.resize( width - 1, 1 ); |  | ||||||
|             if( below != null ) below.resize( width, height - 1 ); |  | ||||||
|             if( right != null ) right.expand(); |  | ||||||
|             if( below != null ) below.expand(); |  | ||||||
| 
 |  | ||||||
|             return; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         for( int y = 0; y < height; y++ ) |         return null; | ||||||
|         { |  | ||||||
|             for( int x = 0; x < width; x++ ) |  | ||||||
|             { |  | ||||||
|                 TileMonitor monitor = origin.getNeighbour( x, y ).getMonitor(); |  | ||||||
|                 if( monitor != null ) continue; |  | ||||||
| 
 |  | ||||||
|                 // Decompose |  | ||||||
|                 TileMonitor above = null; |  | ||||||
|                 TileMonitor left = null; |  | ||||||
|                 TileMonitor right = null; |  | ||||||
|                 TileMonitor below = null; |  | ||||||
| 
 |  | ||||||
|                 if( y > 0 ) |  | ||||||
|                 { |  | ||||||
|                     above = origin; |  | ||||||
|                     above.resize( width, y ); |  | ||||||
|                 } |  | ||||||
|                 if( x > 0 ) |  | ||||||
|                 { |  | ||||||
|                     left = origin.getNeighbour( 0, y ).getMonitor(); |  | ||||||
|                     left.resize( x, 1 ); |  | ||||||
|                 } |  | ||||||
|                 if( x + 1 < width ) |  | ||||||
|                 { |  | ||||||
|                     right = origin.getNeighbour( x + 1, y ).getMonitor(); |  | ||||||
|                     right.resize( width - (x + 1), 1 ); |  | ||||||
|                 } |  | ||||||
|                 if( y + 1 < height ) |  | ||||||
|                 { |  | ||||||
|                     below = origin.getNeighbour( 0, y + 1 ).getMonitor(); |  | ||||||
|                     below.resize( width, height - (y + 1) ); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 // Re-expand |  | ||||||
|                 if( above != null ) above.expand(); |  | ||||||
|                 if( left != null ) left.expand(); |  | ||||||
|                 if( right != null ) right.expand(); |  | ||||||
|                 if( below != null ) below.expand(); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     private boolean checkMonitorAt( int xIndex, int yIndex ) |     private boolean checkMonitorAt( int xIndex, int yIndex ) | ||||||
|     { |     { | ||||||
|         MonitorState state = getNeighbour( xIndex, yIndex ); |         MonitorState state = getLoadedMonitor( xIndex, yIndex ); | ||||||
|         if( state.isMissing() ) return false; |         if( state.isMissing() ) return false; | ||||||
| 
 | 
 | ||||||
|         TileMonitor monitor = state.getMonitor(); |         TileMonitor monitor = state.getMonitor(); | ||||||
| @@ -651,9 +541,11 @@ public class TileMonitor extends TileGeneric | |||||||
| 
 | 
 | ||||||
|     private void validate() |     private void validate() | ||||||
|     { |     { | ||||||
|         if( xIndex == 0 && yIndex == 0 && width == 1 || height == 1 ) return; |         if( xIndex == 0 && yIndex == 0 && width == 1 && height == 1 ) return; | ||||||
| 
 | 
 | ||||||
|         if( checkMonitorAt( 0, 0 ) && checkMonitorAt( 0, height - 1 ) && |         if( xIndex >= 0 && xIndex <= width && width > 0 && width <= ComputerCraft.monitorWidth && | ||||||
|  |             yIndex >= 0 && yIndex <= height && height > 0 && height <= ComputerCraft.monitorHeight && | ||||||
|  |             checkMonitorAt( 0, 0 ) && checkMonitorAt( 0, height - 1 ) && | ||||||
|             checkMonitorAt( width - 1, 0 ) && checkMonitorAt( width - 1, height - 1 ) ) |             checkMonitorAt( width - 1, 0 ) && checkMonitorAt( width - 1, height - 1 ) ) | ||||||
|         { |         { | ||||||
|             return; |             return; | ||||||
| @@ -665,6 +557,7 @@ public class TileMonitor extends TileGeneric | |||||||
|         resize( 1, 1 ); |         resize( 1, 1 ); | ||||||
|         needsUpdate = true; |         needsUpdate = true; | ||||||
|     } |     } | ||||||
|  |     // endregion | ||||||
| 
 | 
 | ||||||
|     private void monitorTouched( float xPos, float yPos, float zPos ) |     private void monitorTouched( float xPos, float yPos, float zPos ) | ||||||
|     { |     { | ||||||
| @@ -689,21 +582,22 @@ public class TileMonitor extends TileGeneric | |||||||
|         int xCharPos = (int) Math.min( originTerminal.getWidth(), Math.max( (pair.x - RENDER_BORDER - RENDER_MARGIN) / xCharWidth + 1.0, 1.0 ) ); |         int xCharPos = (int) Math.min( originTerminal.getWidth(), Math.max( (pair.x - RENDER_BORDER - RENDER_MARGIN) / xCharWidth + 1.0, 1.0 ) ); | ||||||
|         int yCharPos = (int) Math.min( originTerminal.getHeight(), Math.max( (pair.y - RENDER_BORDER - RENDER_MARGIN) / yCharHeight + 1.0, 1.0 ) ); |         int yCharPos = (int) Math.min( originTerminal.getHeight(), Math.max( (pair.y - RENDER_BORDER - RENDER_MARGIN) / yCharHeight + 1.0, 1.0 ) ); | ||||||
| 
 | 
 | ||||||
|         for( int y = 0; y < height; y++ ) |         eachComputer( c -> c.queueEvent( "monitor_touch", c.getAttachmentName(), xCharPos, yCharPos ) ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void eachComputer( Consumer<IComputerAccess> fun ) | ||||||
|  |     { | ||||||
|  |         for( int x = 0; x < width; x++ ) | ||||||
|         { |         { | ||||||
|             for( int x = 0; x < width; x++ ) |             for( int y = 0; y < height; y++ ) | ||||||
|             { |             { | ||||||
|                 TileMonitor monitor = getNeighbour( x, y ).getMonitor(); |                 TileMonitor monitor = getLoadedMonitor( x, y ).getMonitor(); | ||||||
|                 if( monitor == null ) continue; |                 if( monitor == null ) continue; | ||||||
| 
 | 
 | ||||||
|                 for( IComputerAccess computer : monitor.computers ) |                 for( IComputerAccess computer : monitor.computers ) fun.accept( computer ); | ||||||
|                 { |  | ||||||
|                     computer.queueEvent( "monitor_touch", computer.getAttachmentName(), xCharPos, yCharPos ); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     // endregion |  | ||||||
| 
 | 
 | ||||||
|     void addComputer( IComputerAccess computer ) |     void addComputer( IComputerAccess computer ) | ||||||
|     { |     { | ||||||
| @@ -719,24 +613,15 @@ public class TileMonitor extends TileGeneric | |||||||
|     @Override |     @Override | ||||||
|     public AABB getRenderBoundingBox() |     public AABB getRenderBoundingBox() | ||||||
|     { |     { | ||||||
|         TileMonitor start = getNeighbour( 0, 0 ).getMonitor(); |         BlockPos startPos = toWorldPos( 0, 0 ); | ||||||
|         TileMonitor end = getNeighbour( width - 1, height - 1 ).getMonitor(); |         BlockPos endPos = toWorldPos( width, height ); | ||||||
|         if( start != null && end != null ) |         return new AABB( | ||||||
|         { |             Math.min( startPos.getX(), endPos.getX() ), | ||||||
|             BlockPos startPos = start.getBlockPos(); |             Math.min( startPos.getY(), endPos.getY() ), | ||||||
|             BlockPos endPos = end.getBlockPos(); |             Math.min( startPos.getZ(), endPos.getZ() ), | ||||||
|             int minX = Math.min( startPos.getX(), endPos.getX() ); |             Math.max( startPos.getX(), endPos.getX() ) + 1, | ||||||
|             int minY = Math.min( startPos.getY(), endPos.getY() ); |             Math.max( startPos.getY(), endPos.getY() ) + 1, | ||||||
|             int minZ = Math.min( startPos.getZ(), endPos.getZ() ); |             Math.max( startPos.getZ(), endPos.getZ() ) + 1 | ||||||
|             int maxX = Math.max( startPos.getX(), endPos.getX() ) + 1; |         ); | ||||||
|             int maxY = Math.max( startPos.getY(), endPos.getY() ) + 1; |  | ||||||
|             int maxZ = Math.max( startPos.getZ(), endPos.getZ() ) + 1; |  | ||||||
|             return new AABB( minX, minY, minZ, maxX, maxY, maxZ ); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             BlockPos pos = getBlockPos(); |  | ||||||
|             return new AABB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 ); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,6 +8,9 @@ package dan200.computercraft.shared.peripheral.speaker; | |||||||
| import dan200.computercraft.api.peripheral.IComputerAccess; | import dan200.computercraft.api.peripheral.IComputerAccess; | ||||||
| import dan200.computercraft.shared.network.NetworkHandler; | import dan200.computercraft.shared.network.NetworkHandler; | ||||||
| import dan200.computercraft.shared.network.client.SpeakerStopClientMessage; | import dan200.computercraft.shared.network.client.SpeakerStopClientMessage; | ||||||
|  | import net.minecraft.server.MinecraftServer; | ||||||
|  | import net.minecraftforge.fml.LogicalSide; | ||||||
|  | import net.minecraftforge.fmllegacy.LogicalSidedProvider; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| @@ -28,6 +31,10 @@ public abstract class UpgradeSpeakerPeripheral extends SpeakerPeripheral | |||||||
|     @Override |     @Override | ||||||
|     public void detach( @Nonnull IComputerAccess computer ) |     public void detach( @Nonnull IComputerAccess computer ) | ||||||
|     { |     { | ||||||
|  |         // We could be in the process of shutting down the server, so we can't send packets in this case. | ||||||
|  |         MinecraftServer server = LogicalSidedProvider.INSTANCE.get( LogicalSide.SERVER ); | ||||||
|  |         if( server == null || server.isStopped() ) return; | ||||||
|  | 
 | ||||||
|         NetworkHandler.sendToAllPlayers( new SpeakerStopClientMessage( source ) ); |         NetworkHandler.sendToAllPlayers( new SpeakerStopClientMessage( source ) ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleCommand; | |||||||
| import dan200.computercraft.api.turtle.TurtleCommandResult; | import dan200.computercraft.api.turtle.TurtleCommandResult; | ||||||
| import dan200.computercraft.api.turtle.TurtleSide; | import dan200.computercraft.api.turtle.TurtleSide; | ||||||
| import dan200.computercraft.core.apis.IAPIEnvironment; | import dan200.computercraft.core.apis.IAPIEnvironment; | ||||||
| import dan200.computercraft.core.asm.TaskCallback; |  | ||||||
| import dan200.computercraft.core.tracking.TrackingField; | import dan200.computercraft.core.tracking.TrackingField; | ||||||
| import dan200.computercraft.shared.peripheral.generic.data.ItemData; | import dan200.computercraft.shared.peripheral.generic.data.ItemData; | ||||||
| import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; | import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; | ||||||
| @@ -767,7 +766,7 @@ public class TurtleAPI implements ILuaAPI | |||||||
|     { |     { | ||||||
|         int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); |         int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); | ||||||
|         return detailed.orElse( false ) |         return detailed.orElse( false ) | ||||||
|             ? TaskCallback.make( context, () -> getItemDetail( actualSlot, true ) ) |             ? context.executeMainThreadTask( () -> getItemDetail( actualSlot, true ) ) | ||||||
|             : MethodResult.of( getItemDetail( actualSlot, false ) ); |             : MethodResult.of( getItemDetail( actualSlot, false ) ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ import net.minecraft.world.level.block.state.BlockState; | |||||||
| import net.minecraft.world.phys.BlockHitResult; | import net.minecraft.world.phys.BlockHitResult; | ||||||
| import net.minecraft.world.phys.Vec3; | import net.minecraft.world.phys.Vec3; | ||||||
| import net.minecraftforge.common.ForgeHooks; | import net.minecraftforge.common.ForgeHooks; | ||||||
|  | import net.minecraftforge.common.util.Constants; | ||||||
| import net.minecraftforge.event.entity.player.PlayerInteractEvent; | import net.minecraftforge.event.entity.player.PlayerInteractEvent; | ||||||
| import net.minecraftforge.eventbus.api.Event.Result; | import net.minecraftforge.eventbus.api.Event.Result; | ||||||
| import net.minecraftforge.items.IItemHandler; | import net.minecraftforge.items.IItemHandler; | ||||||
| @@ -320,7 +321,7 @@ public class TurtlePlaceCommand implements ITurtleCommand | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         signTile.setChanged(); |         signTile.setChanged(); | ||||||
|         world.sendBlockUpdated( tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), 3 ); |         world.sendBlockUpdated( tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), Constants.BlockFlags.DEFAULT ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static class ErrorMessage |     private static class ErrorMessage | ||||||
|   | |||||||
| @@ -48,6 +48,7 @@ | |||||||
|     "commands.computercraft.dump.synopsis": "Affiche le statut des ordinateurs.", |     "commands.computercraft.dump.synopsis": "Affiche le statut des ordinateurs.", | ||||||
|     "commands.computercraft.dump.desc": "Affiche les statuts de tous les ordinateurs, ou des information spécifiques sur un ordinateur. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", |     "commands.computercraft.dump.desc": "Affiche les statuts de tous les ordinateurs, ou des information spécifiques sur un ordinateur. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", | ||||||
|     "commands.computercraft.dump.action": "Voir plus d'informations à propos de cet ordinateur", |     "commands.computercraft.dump.action": "Voir plus d'informations à propos de cet ordinateur", | ||||||
|  |     "commands.computercraft.dump.open_path": "Voir les fichiers de cet ordinateur", | ||||||
|     "commands.computercraft.shutdown.synopsis": "Éteindre des ordinateurs à distance.", |     "commands.computercraft.shutdown.synopsis": "Éteindre des ordinateurs à distance.", | ||||||
|     "commands.computercraft.shutdown.desc": "Éteint les ordinateurs dans la liste ou tous, si aucun n'est spécifié dans cette liste. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", |     "commands.computercraft.shutdown.desc": "Éteint les ordinateurs dans la liste ou tous, si aucun n'est spécifié dans cette liste. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", | ||||||
|     "commands.computercraft.shutdown.done": "%s/%s ordinateurs arrêté", |     "commands.computercraft.shutdown.done": "%s/%s ordinateurs arrêté", | ||||||
| @@ -110,14 +111,12 @@ | |||||||
|     "gui.computercraft.tooltip.copy": "Copier dans le Presse-Papiers", |     "gui.computercraft.tooltip.copy": "Copier dans le Presse-Papiers", | ||||||
|     "gui.computercraft.tooltip.computer_id": "ID d'ordinateur : %s", |     "gui.computercraft.tooltip.computer_id": "ID d'ordinateur : %s", | ||||||
|     "gui.computercraft.tooltip.disk_id": "ID de disque : %s", |     "gui.computercraft.tooltip.disk_id": "ID de disque : %s", | ||||||
|  |     "gui.computercraft.tooltip.turn_on": "Allumer cet ordinateur", | ||||||
|     "gui.computercraft.tooltip.turn_on.key": "Ternir Ctrl+R", |     "gui.computercraft.tooltip.turn_on.key": "Ternir Ctrl+R", | ||||||
|     "gui.computercraft.tooltip.turn_off": "Éteindre cet ordinateur", |     "gui.computercraft.tooltip.turn_off": "Éteindre cet ordinateur", | ||||||
|     "gui.computercraft.tooltip.turn_off.key": "Tenir Ctrl+S", |     "gui.computercraft.tooltip.turn_off.key": "Tenir Ctrl+S", | ||||||
|     "gui.computercraft.tooltip.terminate": "Arrêter le programme en cours d'éxecution", |     "gui.computercraft.tooltip.terminate": "Arrêter le programme en cours d'éxecution", | ||||||
|     "gui.computercraft.tooltip.terminate.key": "Tenir Ctrl+T", |     "gui.computercraft.tooltip.terminate.key": "Tenir Ctrl+T", | ||||||
|     "gui.computercraft.upload.overwrite": "Les fichiers seraient écrasés", |  | ||||||
|     "gui.computercraft.upload.overwrite.detail": "Les fichiers suivants seront écrasés lors de l'envoie. Continuer?%s", |  | ||||||
|     "gui.computercraft.upload.overwrite_button": "Écraser", |  | ||||||
|     "gui.computercraft.upload.success": "Envoie avec succès", |     "gui.computercraft.upload.success": "Envoie avec succès", | ||||||
|     "gui.computercraft.upload.success.msg": "Le fichier %d est envoyé.", |     "gui.computercraft.upload.success.msg": "Le fichier %d est envoyé.", | ||||||
|     "gui.computercraft.upload.failed": "Echec de l'envoie", |     "gui.computercraft.upload.failed": "Echec de l'envoie", | ||||||
| @@ -126,6 +125,7 @@ | |||||||
|     "gui.computercraft.upload.failed.too_much": "Votre fichier est trop lourd pour être envoyé.", |     "gui.computercraft.upload.failed.too_much": "Votre fichier est trop lourd pour être envoyé.", | ||||||
|     "gui.computercraft.upload.failed.overwrite_dir": "%s ne peut pas être envoyé, il y a déjà un dossier avec le même nom.", |     "gui.computercraft.upload.failed.overwrite_dir": "%s ne peut pas être envoyé, il y a déjà un dossier avec le même nom.", | ||||||
|     "gui.computercraft.upload.failed.generic": "Echec de l'envoie des fichiers (%s)", |     "gui.computercraft.upload.failed.generic": "Echec de l'envoie des fichiers (%s)", | ||||||
|     "commands.computercraft.dump.open_path": "Voir les fichiers de cet ordinateur", |     "gui.computercraft.upload.overwrite": "Les fichiers seraient écrasés", | ||||||
|     "gui.computercraft.tooltip.turn_on": "Allumer cet ordinateur" |     "gui.computercraft.upload.overwrite.detail": "Les fichiers suivants seront écrasés lors de l'envoie. Continuer?%s", | ||||||
|  |     "gui.computercraft.upload.overwrite_button": "Écraser" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
|     "block.computercraft.monitor_normal": "Monitor", |     "block.computercraft.monitor_normal": "Monitor", | ||||||
|     "block.computercraft.monitor_advanced": "Monitor Avanzato", |     "block.computercraft.monitor_advanced": "Monitor Avanzato", | ||||||
|     "block.computercraft.wireless_modem_normal": "Modem Wireless", |     "block.computercraft.wireless_modem_normal": "Modem Wireless", | ||||||
|     "block.computercraft.wireless_modem_advanced": "Modem di Ender", |     "block.computercraft.wireless_modem_advanced": "Modem Dell'Ender", | ||||||
|     "block.computercraft.wired_modem": "Modem Cablato", |     "block.computercraft.wired_modem": "Modem Cablato", | ||||||
|     "block.computercraft.cable": "Cavo Di Rete", |     "block.computercraft.cable": "Cavo Di Rete", | ||||||
|     "block.computercraft.wired_modem_full": "Modem Cablato", |     "block.computercraft.wired_modem_full": "Modem Cablato", | ||||||
| @@ -48,6 +48,7 @@ | |||||||
|     "commands.computercraft.dump.synopsis": "Mostra lo stato dei computer.", |     "commands.computercraft.dump.synopsis": "Mostra lo stato dei computer.", | ||||||
|     "commands.computercraft.dump.desc": "Mostra lo stato di tutti i computer o informazioni specifiche su un computer. Puoi specificare l'instance id di un computer (e.g. 123), l'id di un computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", |     "commands.computercraft.dump.desc": "Mostra lo stato di tutti i computer o informazioni specifiche su un computer. Puoi specificare l'instance id di un computer (e.g. 123), l'id di un computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", | ||||||
|     "commands.computercraft.dump.action": "Mostra più informazioni su questo computer", |     "commands.computercraft.dump.action": "Mostra più informazioni su questo computer", | ||||||
|  |     "commands.computercraft.dump.open_path": "Mostra i file di questo computer", | ||||||
|     "commands.computercraft.shutdown.synopsis": "Spegne i computer da remoto.", |     "commands.computercraft.shutdown.synopsis": "Spegne i computer da remoto.", | ||||||
|     "commands.computercraft.shutdown.desc": "Spegne i computer specificati o tutti se non specificati. Puoi specificare l'instance id del computer (e.g. 123), l'id del computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", |     "commands.computercraft.shutdown.desc": "Spegne i computer specificati o tutti se non specificati. Puoi specificare l'instance id del computer (e.g. 123), l'id del computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", | ||||||
|     "commands.computercraft.shutdown.done": "Spenti %s/%s computer", |     "commands.computercraft.shutdown.done": "Spenti %s/%s computer", | ||||||
| @@ -109,5 +110,26 @@ | |||||||
|     "tracking_field.computercraft.coroutines_dead.name": "Coroutine cancellate", |     "tracking_field.computercraft.coroutines_dead.name": "Coroutine cancellate", | ||||||
|     "gui.computercraft.tooltip.copy": "Copia negli appunti", |     "gui.computercraft.tooltip.copy": "Copia negli appunti", | ||||||
|     "gui.computercraft.tooltip.computer_id": "ID Computer: %s", |     "gui.computercraft.tooltip.computer_id": "ID Computer: %s", | ||||||
|     "gui.computercraft.tooltip.disk_id": "ID Disco: %s" |     "gui.computercraft.tooltip.disk_id": "ID Disco: %s", | ||||||
|  |     "gui.computercraft.tooltip.turn_on": "Accendi questo computer", | ||||||
|  |     "gui.computercraft.tooltip.turn_on.key": "Tieni premuto Ctrl+R", | ||||||
|  |     "gui.computercraft.tooltip.turn_off": "Spegni questo computer", | ||||||
|  |     "gui.computercraft.tooltip.turn_off.key": "Tieni premuto Ctrl+S", | ||||||
|  |     "gui.computercraft.tooltip.terminate": "Ferma il codice in esecuzione", | ||||||
|  |     "gui.computercraft.tooltip.terminate.key": "Tieni premuto Ctrl+T", | ||||||
|  |     "gui.computercraft.upload.success": "Caricato con successo", | ||||||
|  |     "gui.computercraft.upload.success.msg": "%d file caricati.", | ||||||
|  |     "gui.computercraft.upload.failed": "Caricamento fallito", | ||||||
|  |     "gui.computercraft.upload.failed.out_of_space": "Non c'è abbastanza spazio nel computer per questi file.", | ||||||
|  |     "gui.computercraft.upload.failed.computer_off": "Devi accendere il computer prima di caricare file.", | ||||||
|  |     "gui.computercraft.upload.failed.too_much": "I tuoi file sono troppo grandi per essere caricati.", | ||||||
|  |     "gui.computercraft.upload.failed.name_too_long": "I nomi dei file sono troppo lunghi per essere caricati.", | ||||||
|  |     "gui.computercraft.upload.failed.too_many_files": "Non puoi caricare troppi file.", | ||||||
|  |     "gui.computercraft.upload.failed.overwrite_dir": "Non puoi caricare %s perché esiste una cartella con lo stesso nome.", | ||||||
|  |     "gui.computercraft.upload.failed.generic": "Impossibile inviare i file (%s)", | ||||||
|  |     "gui.computercraft.upload.failed.corrupted": "File corrotti durante il caricamento. Riprova.", | ||||||
|  |     "gui.computercraft.upload.overwrite": "Alcuni file saranno sovrascritti", | ||||||
|  |     "gui.computercraft.upload.overwrite.detail": "I seguenti file saranno sovrascritti durante il caricamento. Continuare?%s", | ||||||
|  |     "gui.computercraft.upload.overwrite_button": "Sovrascrivi", | ||||||
|  |     "gui.computercraft.pocket_computer_overlay": "Computer tascabile aperto. Premi ESC per chiudere." | ||||||
| } | } | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|     "block.computercraft.speaker": "スピーカー", |     "block.computercraft.speaker": "スピーカー", | ||||||
|     "block.computercraft.monitor_normal": "モニター", |     "block.computercraft.monitor_normal": "モニター", | ||||||
|     "block.computercraft.monitor_advanced": "高度なモニター", |     "block.computercraft.monitor_advanced": "高度なモニター", | ||||||
|  |     "block.computercraft.wireless_modem_normal": "無線モデム", | ||||||
|     "block.computercraft.wireless_modem_advanced": "エンダーモデム", |     "block.computercraft.wireless_modem_advanced": "エンダーモデム", | ||||||
|     "block.computercraft.wired_modem": "有線モデム", |     "block.computercraft.wired_modem": "有線モデム", | ||||||
|     "block.computercraft.cable": "ネットワークケーブル", |     "block.computercraft.cable": "ネットワークケーブル", | ||||||
| @@ -17,6 +18,7 @@ | |||||||
|     "block.computercraft.turtle_normal.upgraded_twice": "%s%sタートル", |     "block.computercraft.turtle_normal.upgraded_twice": "%s%sタートル", | ||||||
|     "block.computercraft.turtle_advanced": "高度なタートル", |     "block.computercraft.turtle_advanced": "高度なタートル", | ||||||
|     "block.computercraft.turtle_advanced.upgraded": "高度な%sタートル", |     "block.computercraft.turtle_advanced.upgraded": "高度な%sタートル", | ||||||
|  |     "block.computercraft.turtle_advanced.upgraded_twice": "高度な%s%sタートル", | ||||||
|     "item.computercraft.disk": "フロッピーディスク", |     "item.computercraft.disk": "フロッピーディスク", | ||||||
|     "item.computercraft.treasure_disk": "フロッピーディスク", |     "item.computercraft.treasure_disk": "フロッピーディスク", | ||||||
|     "item.computercraft.printed_page": "印刷された紙", |     "item.computercraft.printed_page": "印刷された紙", | ||||||
| @@ -24,52 +26,66 @@ | |||||||
|     "item.computercraft.printed_book": "印刷された本", |     "item.computercraft.printed_book": "印刷された本", | ||||||
|     "item.computercraft.pocket_computer_normal": "ポケットコンピュータ", |     "item.computercraft.pocket_computer_normal": "ポケットコンピュータ", | ||||||
|     "item.computercraft.pocket_computer_normal.upgraded": "%sポケットコンピュータ", |     "item.computercraft.pocket_computer_normal.upgraded": "%sポケットコンピュータ", | ||||||
|  |     "item.computercraft.pocket_computer_advanced": "高度なポケットコンピュータ", | ||||||
|     "item.computercraft.pocket_computer_advanced.upgraded": "高度な%sポケットコンピュータ", |     "item.computercraft.pocket_computer_advanced.upgraded": "高度な%sポケットコンピュータ", | ||||||
|  |     "upgrade.minecraft.diamond_sword.adjective": "攻撃", | ||||||
|     "upgrade.minecraft.diamond_shovel.adjective": "掘削", |     "upgrade.minecraft.diamond_shovel.adjective": "掘削", | ||||||
|     "upgrade.minecraft.diamond_pickaxe.adjective": "採掘", |     "upgrade.minecraft.diamond_pickaxe.adjective": "採掘", | ||||||
|     "upgrade.minecraft.diamond_axe.adjective": "伐採", |     "upgrade.minecraft.diamond_axe.adjective": "伐採", | ||||||
|     "upgrade.minecraft.diamond_hoe.adjective": "農耕", |     "upgrade.minecraft.diamond_hoe.adjective": "農耕", | ||||||
|     "upgrade.minecraft.crafting_table.adjective": "クラフト", |     "upgrade.minecraft.crafting_table.adjective": "クラフト", | ||||||
|  |     "upgrade.computercraft.wireless_modem_normal.adjective": "無線", | ||||||
|     "upgrade.computercraft.wireless_modem_advanced.adjective": "エンダー", |     "upgrade.computercraft.wireless_modem_advanced.adjective": "エンダー", | ||||||
|     "upgrade.computercraft.speaker.adjective": "騒音", |     "upgrade.computercraft.speaker.adjective": "騒音", | ||||||
|     "chat.computercraft.wired_modem.peripheral_connected": "周辺の\"%s\"のネットワークに接続されました", |     "chat.computercraft.wired_modem.peripheral_connected": "周辺の\"%s\"のネットワークに接続されました", | ||||||
|  |     "chat.computercraft.wired_modem.peripheral_disconnected": "周辺の\"%s\"のネットワークから切断されました", | ||||||
|     "commands.computercraft.synopsis": "コンピュータを制御するためのさまざまなコマンド。", |     "commands.computercraft.synopsis": "コンピュータを制御するためのさまざまなコマンド。", | ||||||
|  |     "commands.computercraft.desc": "/computercraft コマンドは、コンピュータとの制御および対話するためのさまざまなデバッグツールと管理者ツールを提供します。", | ||||||
|     "commands.computercraft.help.synopsis": "特定のコマンドのヘルプを提供します", |     "commands.computercraft.help.synopsis": "特定のコマンドのヘルプを提供します", | ||||||
|     "commands.computercraft.help.desc": "このヘルプメッセージを表示します", |     "commands.computercraft.help.desc": "このヘルプメッセージを表示します", | ||||||
|     "commands.computercraft.help.no_children": "%s にサブコマンドはありません", |     "commands.computercraft.help.no_children": "%s にサブコマンドはありません", | ||||||
|     "commands.computercraft.help.no_command": "%s というコマンドはありません", |     "commands.computercraft.help.no_command": "%s というコマンドはありません", | ||||||
|     "commands.computercraft.dump.synopsis": "コンピュータの状態を表示します。", |     "commands.computercraft.dump.synopsis": "コンピュータの状態を表示します。", | ||||||
|  |     "commands.computercraft.dump.desc": "すべてのコンピューターの状態、または一台のコンピューターの特定の情報を表示する。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", | ||||||
|     "commands.computercraft.dump.action": "このコンピュータの詳細を表示します", |     "commands.computercraft.dump.action": "このコンピュータの詳細を表示します", | ||||||
|     "commands.computercraft.dump.open_path": "このコンピュータのファイルを表示します", |     "commands.computercraft.dump.open_path": "このコンピュータのファイルを表示します", | ||||||
|     "commands.computercraft.shutdown.synopsis": "コンピュータをリモートでシャットダウンする。", |     "commands.computercraft.shutdown.synopsis": "コンピュータをリモートでシャットダウンする。", | ||||||
|  |     "commands.computercraft.shutdown.desc": "指定されたコンピュータ、指定されていない場合はすべてのコンピュータをシャットダウンします。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", | ||||||
|     "commands.computercraft.shutdown.done": "%s/%s コンピューターをシャットダウンしました", |     "commands.computercraft.shutdown.done": "%s/%s コンピューターをシャットダウンしました", | ||||||
|  |     "commands.computercraft.turn_on.synopsis": "コンピューターをリモートで起動します。", | ||||||
|     "commands.computercraft.turn_on.desc": "指定されているコンピュータを起動します。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", |     "commands.computercraft.turn_on.desc": "指定されているコンピュータを起動します。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", | ||||||
|     "commands.computercraft.turn_on.done": "%s/%s コンピューターを起動しました", |     "commands.computercraft.turn_on.done": "%s/%s コンピューターを起動しました", | ||||||
|     "commands.computercraft.tp.synopsis": "特定のコンピュータにテレポート。", |     "commands.computercraft.tp.synopsis": "特定のコンピュータにテレポート。", | ||||||
|  |     "commands.computercraft.tp.desc": "コンピュータの場所にテレポート.コンピュータのインスタンスID(例えば 123)またはコンピュータID(例えば #123)を指定することができます。", | ||||||
|     "commands.computercraft.tp.action": "このコンピューターへテレポートします", |     "commands.computercraft.tp.action": "このコンピューターへテレポートします", | ||||||
|     "commands.computercraft.tp.not_player": "非プレイヤー用のターミナルを開くことができません", |     "commands.computercraft.tp.not_player": "非プレイヤー用のターミナルを開くことができません", | ||||||
|     "commands.computercraft.tp.not_there": "世界でコンピュータを見つけることができませんでした", |     "commands.computercraft.tp.not_there": "世界でコンピュータを見つけることができませんでした", | ||||||
|     "commands.computercraft.view.synopsis": "コンピュータのターミナルを表示します。", |     "commands.computercraft.view.synopsis": "コンピュータのターミナルを表示します。", | ||||||
|     "commands.computercraft.turn_on.synopsis": "コンピューターをリモートで起動します。", |     "commands.computercraft.view.desc": "コンピュータのターミナルを開き、コンピュータのリモートコントロールを可能にします。 これはタートルのインベントリへのアクセスを提供しません。 コンピュータのインスタンスID(例えば 123)またはコンピュータID(例えば #123)を指定することができます。", | ||||||
|     "commands.computercraft.view.action": "このコンピュータを見ます", |     "commands.computercraft.view.action": "このコンピュータを見ます", | ||||||
|     "commands.computercraft.view.not_player": "非プレイヤー用のターミナルを開くことができません", |     "commands.computercraft.view.not_player": "非プレイヤー用のターミナルを開くことができません", | ||||||
|     "commands.computercraft.track.synopsis": "コンピュータの実行時間を追跡します。", |     "commands.computercraft.track.synopsis": "コンピュータの実行時間を追跡します。", | ||||||
|  |     "commands.computercraft.track.desc": "コンピュータの実行時間を追跡するだけでなく、イベントを確認することができます。 これは /forge と同様の方法で情報を提示し、遅れを診断するのに役立ちます。", | ||||||
|     "commands.computercraft.track.start.synopsis": "すべてのコンピュータの追跡を開始します", |     "commands.computercraft.track.start.synopsis": "すべてのコンピュータの追跡を開始します", | ||||||
|     "commands.computercraft.track.start.desc": "すべてのコンピュータの実行時間とイベント数の追跡を開始します。 これにより、以前の実行結果が破棄されます。", |     "commands.computercraft.track.start.desc": "すべてのコンピュータの実行時間とイベント数の追跡を開始します。 これにより、以前の実行結果が破棄されます。", | ||||||
|  |     "commands.computercraft.track.start.stop": "トラッキングを停止して結果を表示するには %s を実行してください", | ||||||
|     "commands.computercraft.track.stop.synopsis": "すべてのコンピュータの追跡を停止します", |     "commands.computercraft.track.stop.synopsis": "すべてのコンピュータの追跡を停止します", | ||||||
|  |     "commands.computercraft.track.stop.desc": "すべてのコンピュータのイベントと実行時間の追跡を停止します", | ||||||
|     "commands.computercraft.track.stop.action": "追跡を中止するためにクリックしてください", |     "commands.computercraft.track.stop.action": "追跡を中止するためにクリックしてください", | ||||||
|     "commands.computercraft.track.stop.not_enabled": "現在コンピュータを追跡していません", |     "commands.computercraft.track.stop.not_enabled": "現在コンピュータを追跡していません", | ||||||
|     "commands.computercraft.track.dump.synopsis": "最新の追跡結果をダンプしてください", |     "commands.computercraft.track.dump.synopsis": "最新の追跡結果をダンプしてください", | ||||||
|     "commands.computercraft.track.dump.desc": "コンピュータの最新の追跡結果をダンプしてください。", |     "commands.computercraft.track.dump.desc": "コンピュータの最新の追跡結果をダンプしてください。", | ||||||
|     "commands.computercraft.track.dump.no_timings": "利用可能なタイミングはありません", |     "commands.computercraft.track.dump.no_timings": "利用可能なタイミングはありません", | ||||||
|  |     "commands.computercraft.track.dump.computer": "コンピューター", | ||||||
|     "commands.computercraft.reload.synopsis": "コンピュータークラフトのコンフィグファイルを再読み込みします", |     "commands.computercraft.reload.synopsis": "コンピュータークラフトのコンフィグファイルを再読み込みします", | ||||||
|  |     "commands.computercraft.reload.desc": "コンピュータークラフトのコンフィグファイルを再読み込みします", | ||||||
|     "commands.computercraft.reload.done": "コンフィグを再読み込みしました", |     "commands.computercraft.reload.done": "コンフィグを再読み込みしました", | ||||||
|     "commands.computercraft.queue.synopsis": "computer_command インベントをコマンドコンピューターに送信します", |     "commands.computercraft.queue.synopsis": "computer_command インベントをコマンドコンピューターに送信します", | ||||||
|  |     "commands.computercraft.queue.desc": "追加の引数を通過する computer_command インベントをコマンドコンピューターに送信します。これは主にマップメーカーのために設計されており、よりコンピュータフレンドリーバージョンの /trigger として機能します。 どのプレイヤーでもコマンドを実行できます。これは、テキストコンポーネントのクリックイベントを介して行われる可能性があります。", | ||||||
|     "commands.computercraft.generic.no_position": "<no pos>", |     "commands.computercraft.generic.no_position": "<no pos>", | ||||||
|     "commands.computercraft.generic.position": "%s, %s, %s", |     "commands.computercraft.generic.position": "%s, %s, %s", | ||||||
|     "commands.computercraft.generic.yes": "Y", |     "commands.computercraft.generic.yes": "Y", | ||||||
|     "commands.computercraft.generic.no": "N", |     "commands.computercraft.generic.no": "N", | ||||||
|     "commands.computercraft.track.start.stop": "トラッキングを停止して結果を表示するには %s を実行してください", |  | ||||||
|     "commands.computercraft.generic.exception": "未処理の例外 (%s)", |     "commands.computercraft.generic.exception": "未処理の例外 (%s)", | ||||||
|     "commands.computercraft.generic.additional_rows": "%d行を追加…", |     "commands.computercraft.generic.additional_rows": "%d行を追加…", | ||||||
|     "argument.computercraft.computer.no_matching": "'%s'に一致するコンピュータはありません", |     "argument.computercraft.computer.no_matching": "'%s'に一致するコンピュータはありません", | ||||||
| @@ -82,6 +98,7 @@ | |||||||
|     "tracking_field.computercraft.max.name": "最大時間", |     "tracking_field.computercraft.max.name": "最大時間", | ||||||
|     "tracking_field.computercraft.server_count.name": "サーバータスク数", |     "tracking_field.computercraft.server_count.name": "サーバータスク数", | ||||||
|     "tracking_field.computercraft.server_time.name": "サーバータスク時間", |     "tracking_field.computercraft.server_time.name": "サーバータスク時間", | ||||||
|  |     "tracking_field.computercraft.peripheral.name": "実行呼び出し", | ||||||
|     "tracking_field.computercraft.fs.name": "ファイルシステム演算", |     "tracking_field.computercraft.fs.name": "ファイルシステム演算", | ||||||
|     "tracking_field.computercraft.turtle.name": "タートル演算", |     "tracking_field.computercraft.turtle.name": "タートル演算", | ||||||
|     "tracking_field.computercraft.http.name": "HTTPリクエスト", |     "tracking_field.computercraft.http.name": "HTTPリクエスト", | ||||||
| @@ -89,43 +106,30 @@ | |||||||
|     "tracking_field.computercraft.http_download.name": "HTTPダウンロード", |     "tracking_field.computercraft.http_download.name": "HTTPダウンロード", | ||||||
|     "tracking_field.computercraft.websocket_incoming.name": "Websocket 受信", |     "tracking_field.computercraft.websocket_incoming.name": "Websocket 受信", | ||||||
|     "tracking_field.computercraft.websocket_outgoing.name": "Websocket 送信", |     "tracking_field.computercraft.websocket_outgoing.name": "Websocket 送信", | ||||||
|  |     "tracking_field.computercraft.coroutines_created.name": "コルーチン作成", | ||||||
|     "tracking_field.computercraft.coroutines_dead.name": "コルーチン削除", |     "tracking_field.computercraft.coroutines_dead.name": "コルーチン削除", | ||||||
|     "gui.computercraft.tooltip.copy": "クリップボードにコピー", |     "gui.computercraft.tooltip.copy": "クリップボードにコピー", | ||||||
|     "gui.computercraft.tooltip.computer_id": "コンピュータID: %s", |     "gui.computercraft.tooltip.computer_id": "コンピュータID: %s", | ||||||
|     "gui.computercraft.tooltip.disk_id": "ディスクID: %s", |     "gui.computercraft.tooltip.disk_id": "ディスクID: %s", | ||||||
|     "gui.computercraft.tooltip.turn_on": "このコンピュータをオンにする", |     "gui.computercraft.tooltip.turn_on": "このコンピュータをオンにする", | ||||||
|     "gui.computercraft.tooltip.turn_on.key": "Ctrl+R 長押し", |     "gui.computercraft.tooltip.turn_on.key": "Ctrl+R 長押し", | ||||||
|  |     "gui.computercraft.tooltip.turn_off": "このコンピュータをオフにする", | ||||||
|     "gui.computercraft.tooltip.turn_off.key": "Ctrl+S 長押し", |     "gui.computercraft.tooltip.turn_off.key": "Ctrl+S 長押し", | ||||||
|     "gui.computercraft.tooltip.terminate": "現在実行中のコードを停止する", |     "gui.computercraft.tooltip.terminate": "現在実行中のコードを停止する", | ||||||
|     "gui.computercraft.tooltip.terminate.key": "Ctrl+T 長押し", |     "gui.computercraft.tooltip.terminate.key": "Ctrl+T 長押し", | ||||||
|     "gui.computercraft.upload.success": "アップロードは成功しました", |     "gui.computercraft.upload.success": "アップロードは成功しました", | ||||||
|  |     "gui.computercraft.upload.success.msg": "%d個のファイルがアップロードされました。", | ||||||
|     "gui.computercraft.upload.failed": "アップロードに失敗しました", |     "gui.computercraft.upload.failed": "アップロードに失敗しました", | ||||||
|     "gui.computercraft.upload.failed.out_of_space": "これらのファイルに必要なスペースがコンピュータ上にありません。", |     "gui.computercraft.upload.failed.out_of_space": "これらのファイルに必要なスペースがコンピュータ上にありません。", | ||||||
|  |     "gui.computercraft.upload.failed.computer_off": "ファイルをアップロードする前にコンピュータを起動する必要があります。", | ||||||
|     "gui.computercraft.upload.failed.too_much": "アップロードするにはファイルが大きスギます。", |     "gui.computercraft.upload.failed.too_much": "アップロードするにはファイルが大きスギます。", | ||||||
|  |     "gui.computercraft.upload.failed.name_too_long": "ファイル名が長すぎてアップロードできません。", | ||||||
|  |     "gui.computercraft.upload.failed.too_many_files": "多くのファイルをアップロードできません。", | ||||||
|     "gui.computercraft.upload.failed.overwrite_dir": "同じ名前のディレクトリがすでにあるため、%s をアップロードできません。", |     "gui.computercraft.upload.failed.overwrite_dir": "同じ名前のディレクトリがすでにあるため、%s をアップロードできません。", | ||||||
|     "gui.computercraft.upload.failed.generic": "ファイルのアップロードに失敗しました(%s)", |     "gui.computercraft.upload.failed.generic": "ファイルのアップロードに失敗しました(%s)", | ||||||
|  |     "gui.computercraft.upload.failed.corrupted": "アップロード時にファイルが破損しました。 もう一度やり直してください。", | ||||||
|     "gui.computercraft.upload.overwrite": "ファイルは上書きされます", |     "gui.computercraft.upload.overwrite": "ファイルは上書きされます", | ||||||
|  |     "gui.computercraft.upload.overwrite.detail": "アップロード時に次のファイルが上書きされます。継続しますか?%s", | ||||||
|     "gui.computercraft.upload.overwrite_button": "上書き", |     "gui.computercraft.upload.overwrite_button": "上書き", | ||||||
|     "block.computercraft.wireless_modem_normal": "無線モデム", |     "gui.computercraft.pocket_computer_overlay": "ポケットコンピュータを開いています。 ESCを押して閉じます。" | ||||||
|     "block.computercraft.turtle_advanced.upgraded_twice": "高度な%s%sタートル", |  | ||||||
|     "item.computercraft.pocket_computer_advanced": "高度なポケットコンピュータ", |  | ||||||
|     "upgrade.minecraft.diamond_sword.adjective": "攻撃", |  | ||||||
|     "upgrade.computercraft.wireless_modem_normal.adjective": "無線", |  | ||||||
|     "chat.computercraft.wired_modem.peripheral_disconnected": "周辺の\"%s\"のネットワークから切断されました", |  | ||||||
|     "commands.computercraft.desc": "/computercraft コマンドは、コンピュータとの制御および対話するためのさまざまなデバッグツールと管理者ツールを提供します。", |  | ||||||
|     "commands.computercraft.dump.desc": "すべてのコンピューターの状態、または一台のコンピューターの特定の情報を表示する。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", |  | ||||||
|     "commands.computercraft.shutdown.desc": "指定されたコンピュータ、指定されていない場合はすべてのコンピュータをシャットダウンします。 コンピュータのインスタンスID (例えば 123), コンピュータID (例えば #123) またはラベル (例えば \\\"@My Computer\\\") を指定することができます。", |  | ||||||
|     "commands.computercraft.tp.desc": "コンピュータの場所にテレポート.コンピュータのインスタンスID(例えば 123)またはコンピュータID(例えば #123)を指定することができます。", |  | ||||||
|     "commands.computercraft.view.desc": "コンピュータのターミナルを開き、コンピュータのリモートコントロールを可能にします。 これはタートルのインベントリへのアクセスを提供しません。 コンピュータのインスタンスID(例えば 123)またはコンピュータID(例えば #123)を指定することができます。", |  | ||||||
|     "commands.computercraft.track.desc": "コンピュータの実行時間を追跡するだけでなく、イベントを確認することができます。 これは /forge と同様の方法で情報を提示し、遅れを診断するのに役立ちます。", |  | ||||||
|     "commands.computercraft.track.stop.desc": "すべてのコンピュータのイベントと実行時間の追跡を停止します", |  | ||||||
|     "commands.computercraft.track.dump.computer": "コンピューター", |  | ||||||
|     "commands.computercraft.reload.desc": "コンピュータークラフトのコンフィグファイルを再読み込みします", |  | ||||||
|     "commands.computercraft.queue.desc": "追加の引数を通過する computer_command インベントをコマンドコンピューターに送信します。これは主にマップメーカーのために設計されており、よりコンピュータフレンドリーバージョンの /trigger として機能します。 どのプレイヤーでもコマンドを実行できます。これは、テキストコンポーネントのクリックイベントを介して行われる可能性があります。", |  | ||||||
|     "tracking_field.computercraft.peripheral.name": "実行呼び出し", |  | ||||||
|     "tracking_field.computercraft.coroutines_created.name": "コルーチン作成", |  | ||||||
|     "gui.computercraft.tooltip.turn_off": "このコンピュータをオフにする", |  | ||||||
|     "gui.computercraft.upload.success.msg": "%d個のファイルがアップロードされました。", |  | ||||||
|     "gui.computercraft.upload.failed.computer_off": "ファイルをアップロードする前にコンピュータを起動する必要があります。", |  | ||||||
|     "gui.computercraft.upload.overwrite.detail": "アップロード時に次のファイルが上書きされます。継続しますか?%s" |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,6 +12,7 @@ | |||||||
|     "block.computercraft.wireless_modem_advanced": "엔더 모뎀", |     "block.computercraft.wireless_modem_advanced": "엔더 모뎀", | ||||||
|     "block.computercraft.wired_modem": "유선 모뎀", |     "block.computercraft.wired_modem": "유선 모뎀", | ||||||
|     "block.computercraft.cable": "네트워크 케이블", |     "block.computercraft.cable": "네트워크 케이블", | ||||||
|  |     "block.computercraft.wired_modem_full": "유선 모뎀", | ||||||
|     "block.computercraft.turtle_normal": "터틀", |     "block.computercraft.turtle_normal": "터틀", | ||||||
|     "block.computercraft.turtle_normal.upgraded": "%s 터틀", |     "block.computercraft.turtle_normal.upgraded": "%s 터틀", | ||||||
|     "block.computercraft.turtle_normal.upgraded_twice": "%s %s 터틀", |     "block.computercraft.turtle_normal.upgraded_twice": "%s %s 터틀", | ||||||
| @@ -41,11 +42,13 @@ | |||||||
|     "commands.computercraft.synopsis": "컴퓨터를 제어하기 위한 다양한 명령어", |     "commands.computercraft.synopsis": "컴퓨터를 제어하기 위한 다양한 명령어", | ||||||
|     "commands.computercraft.desc": "/computercraft 명령어는 컴퓨터를 제어하고 상호작용하기 위한 다양한 디버깅 및 관리자 도구를 제공합니다.", |     "commands.computercraft.desc": "/computercraft 명령어는 컴퓨터를 제어하고 상호작용하기 위한 다양한 디버깅 및 관리자 도구를 제공합니다.", | ||||||
|     "commands.computercraft.help.synopsis": "특정 명령어에 대한 도움말을 제공하기", |     "commands.computercraft.help.synopsis": "특정 명령어에 대한 도움말을 제공하기", | ||||||
|  |     "commands.computercraft.help.desc": "이 도움말 메시지를 표시합니다.", | ||||||
|     "commands.computercraft.help.no_children": "%s에는 하위 명령어가 없습니다.", |     "commands.computercraft.help.no_children": "%s에는 하위 명령어가 없습니다.", | ||||||
|     "commands.computercraft.help.no_command": "'%s'라는 명령어가 없습니다.", |     "commands.computercraft.help.no_command": "'%s'라는 명령어가 없습니다.", | ||||||
|     "commands.computercraft.dump.synopsis": "컴퓨터의 상태를 보여주기", |     "commands.computercraft.dump.synopsis": "컴퓨터의 상태를 보여주기", | ||||||
|     "commands.computercraft.dump.desc": "모든 시스템의 상태 또는 한 시스템에 대한 특정 정보를 표시합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.", |     "commands.computercraft.dump.desc": "모든 시스템의 상태 또는 한 시스템에 대한 특정 정보를 표시합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.", | ||||||
|     "commands.computercraft.dump.action": "이 컴퓨터에 대한 추가 정보를 봅니다.", |     "commands.computercraft.dump.action": "이 컴퓨터에 대한 추가 정보를 봅니다.", | ||||||
|  |     "commands.computercraft.dump.open_path": "이 컴퓨터의 파일을 봅니다.", | ||||||
|     "commands.computercraft.shutdown.synopsis": "시스템을 원격으로 종료하기", |     "commands.computercraft.shutdown.synopsis": "시스템을 원격으로 종료하기", | ||||||
|     "commands.computercraft.shutdown.desc": "나열된 시스템 또는 지정된 시스템이 없는 경우 모두 종료합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.", |     "commands.computercraft.shutdown.desc": "나열된 시스템 또는 지정된 시스템이 없는 경우 모두 종료합니다. 컴퓨터의 인스턴스 ID(예: 123)나 컴퓨터 ID(예: #123) 또는 라벨(예: \"@My Computer\")을 지정할 수 있습니다.", | ||||||
|     "commands.computercraft.shutdown.done": "%s/%s 컴퓨터 시스템 종료", |     "commands.computercraft.shutdown.done": "%s/%s 컴퓨터 시스템 종료", | ||||||
| @@ -55,6 +58,7 @@ | |||||||
|     "commands.computercraft.tp.synopsis": "특정 컴퓨터로 순간이동하기", |     "commands.computercraft.tp.synopsis": "특정 컴퓨터로 순간이동하기", | ||||||
|     "commands.computercraft.tp.desc": "컴퓨터의 위치로 순간이동합니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", |     "commands.computercraft.tp.desc": "컴퓨터의 위치로 순간이동합니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", | ||||||
|     "commands.computercraft.tp.action": "이 컴퓨터로 순간이동하기", |     "commands.computercraft.tp.action": "이 컴퓨터로 순간이동하기", | ||||||
|  |     "commands.computercraft.tp.not_player": "비플레이어용 터미널을 열 수 없습니다.", | ||||||
|     "commands.computercraft.tp.not_there": "월드에서 컴퓨터를 위치시킬 수 없습니다.", |     "commands.computercraft.tp.not_there": "월드에서 컴퓨터를 위치시킬 수 없습니다.", | ||||||
|     "commands.computercraft.view.synopsis": "컴퓨터의 터미널을 보기", |     "commands.computercraft.view.synopsis": "컴퓨터의 터미널을 보기", | ||||||
|     "commands.computercraft.view.desc": "컴퓨터의 원격 제어를 허용하는 컴퓨터의 터미널을 엽니다. 이것은 터틀의 인벤토리에 대한 접근을 제공하지 않습니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", |     "commands.computercraft.view.desc": "컴퓨터의 원격 제어를 허용하는 컴퓨터의 터미널을 엽니다. 이것은 터틀의 인벤토리에 대한 접근을 제공하지 않습니다. 컴퓨터의 인스턴스 ID(예: 123) 또는 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", | ||||||
| @@ -86,6 +90,8 @@ | |||||||
|     "commands.computercraft.generic.additional_rows": "%d개의 추가 행…", |     "commands.computercraft.generic.additional_rows": "%d개의 추가 행…", | ||||||
|     "argument.computercraft.computer.no_matching": "'%s'와 일치하는 컴퓨터가 없습니다.", |     "argument.computercraft.computer.no_matching": "'%s'와 일치하는 컴퓨터가 없습니다.", | ||||||
|     "argument.computercraft.computer.many_matching": "'%s'와 일치하는 여러 컴퓨터 (인스턴스 %s)", |     "argument.computercraft.computer.many_matching": "'%s'와 일치하는 여러 컴퓨터 (인스턴스 %s)", | ||||||
|  |     "argument.computercraft.tracking_field.no_field": "알 수 없는 필드 '%s'입니다.", | ||||||
|  |     "argument.computercraft.argument_expected": "인수가 필요합니다.", | ||||||
|     "tracking_field.computercraft.tasks.name": "작업", |     "tracking_field.computercraft.tasks.name": "작업", | ||||||
|     "tracking_field.computercraft.total.name": "전체 시간", |     "tracking_field.computercraft.total.name": "전체 시간", | ||||||
|     "tracking_field.computercraft.average.name": "평균 시간", |     "tracking_field.computercraft.average.name": "평균 시간", | ||||||
| @@ -104,5 +110,26 @@ | |||||||
|     "tracking_field.computercraft.coroutines_dead.name": "코루틴 처리됨", |     "tracking_field.computercraft.coroutines_dead.name": "코루틴 처리됨", | ||||||
|     "gui.computercraft.tooltip.copy": "클립보드에 복사", |     "gui.computercraft.tooltip.copy": "클립보드에 복사", | ||||||
|     "gui.computercraft.tooltip.computer_id": "컴퓨터 ID: %s", |     "gui.computercraft.tooltip.computer_id": "컴퓨터 ID: %s", | ||||||
|     "gui.computercraft.tooltip.disk_id": "디스크 ID: %s" |     "gui.computercraft.tooltip.disk_id": "디스크 ID: %s", | ||||||
|  |     "gui.computercraft.tooltip.turn_on": "이 컴퓨터를 켭니다.", | ||||||
|  |     "gui.computercraft.tooltip.turn_on.key": "Ctrl+R을 누르세요.", | ||||||
|  |     "gui.computercraft.tooltip.turn_off": "이 컴퓨터를 끕니다.", | ||||||
|  |     "gui.computercraft.tooltip.turn_off.key": "Ctrl+S를 누르세요.", | ||||||
|  |     "gui.computercraft.tooltip.terminate": "현재 실행 중인 코드를 중지합니다.", | ||||||
|  |     "gui.computercraft.tooltip.terminate.key": "Ctrl+T를 누르세요.", | ||||||
|  |     "gui.computercraft.upload.success": "업로드에 성공했습니다.", | ||||||
|  |     "gui.computercraft.upload.success.msg": "%d개의 파일이 업로드되었습니다.", | ||||||
|  |     "gui.computercraft.upload.failed": "업로드하지 못했습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.out_of_space": "컴퓨터에 공간이 부족하여 파일을 저장할 수 없습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.computer_off": "파일을 업로드하기 전에 컴퓨터를 켜야 합니다.", | ||||||
|  |     "gui.computercraft.upload.failed.too_much": "파일이 너무 커서 업로드할 수 없습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.name_too_long": "파일 이름이 너무 길어서 업로드할 수 없습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.too_many_files": "이렇게 많은 파일을 업로드할 수 없습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.overwrite_dir": "같은 이름의 디렉터리가 이미 있으므로 %s을 업로드할 수 없습니다.", | ||||||
|  |     "gui.computercraft.upload.failed.generic": "파일을 업로드하지 못했습니다. (%s)", | ||||||
|  |     "gui.computercraft.upload.failed.corrupted": "업로드할 때 파일이 손상되었습니다. 다시 시도하십시오.", | ||||||
|  |     "gui.computercraft.upload.overwrite": "파일을 덮어씁니다.", | ||||||
|  |     "gui.computercraft.upload.overwrite.detail": "업로드 시 다음 파일을 덮어씁니다. 계속할까요?%s", | ||||||
|  |     "gui.computercraft.upload.overwrite_button": "덮어쓰기", | ||||||
|  |     "gui.computercraft.pocket_computer_overlay": "포켓 컴퓨터가 열립니다. ESC를 눌러 닫습니다." | ||||||
| } | } | ||||||
|   | |||||||
| @@ -123,12 +123,12 @@ | |||||||
|     "gui.computercraft.upload.failed.out_of_space": "Недостаточно места в компьютере для этих файлов.", |     "gui.computercraft.upload.failed.out_of_space": "Недостаточно места в компьютере для этих файлов.", | ||||||
|     "gui.computercraft.upload.failed.computer_off": "Ты должен включить компьютер перед загрузой файлов.", |     "gui.computercraft.upload.failed.computer_off": "Ты должен включить компьютер перед загрузой файлов.", | ||||||
|     "gui.computercraft.upload.failed.too_much": "Твои файлы слишком большие для загрузки.", |     "gui.computercraft.upload.failed.too_much": "Твои файлы слишком большие для загрузки.", | ||||||
|     "gui.computercraft.upload.failed.overwrite_dir": "Нельзя загрузить %s, поскольку папка с таким же названием уже существует.", |  | ||||||
|     "gui.computercraft.upload.failed.generic": "Загрузка файлов не удалась (%s)", |  | ||||||
|     "gui.computercraft.upload.overwrite": "Файлы будут перезаписаны", |  | ||||||
|     "gui.computercraft.upload.overwrite.detail": "При загрузке следующие файлы будут перезаписаны. Продолжить?%s", |  | ||||||
|     "gui.computercraft.upload.overwrite_button": "Перезаписать", |  | ||||||
|     "gui.computercraft.upload.failed.name_too_long": "Названия файлов слишком длинны для загрузки.", |     "gui.computercraft.upload.failed.name_too_long": "Названия файлов слишком длинны для загрузки.", | ||||||
|     "gui.computercraft.upload.failed.too_many_files": "Нельзя загрузить столько файлов.", |     "gui.computercraft.upload.failed.too_many_files": "Нельзя загрузить столько файлов.", | ||||||
|     "gui.computercraft.upload.failed.corrupted": "Файлы повреждены при загрузки. Попробуй снова." |     "gui.computercraft.upload.failed.overwrite_dir": "Нельзя загрузить %s, поскольку папка с таким же названием уже существует.", | ||||||
|  |     "gui.computercraft.upload.failed.generic": "Загрузка файлов не удалась (%s)", | ||||||
|  |     "gui.computercraft.upload.failed.corrupted": "Файлы повреждены при загрузки. Попробуй снова.", | ||||||
|  |     "gui.computercraft.upload.overwrite": "Файлы будут перезаписаны", | ||||||
|  |     "gui.computercraft.upload.overwrite.detail": "При загрузке следующие файлы будут перезаписаны. Продолжить?%s", | ||||||
|  |     "gui.computercraft.upload.overwrite_button": "Перезаписать" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -403,10 +403,11 @@ function run() | |||||||
|         if sEvent == "modem_message" then |         if sEvent == "modem_message" then | ||||||
|             -- Got a modem message, process it and add it to the rednet event queue |             -- Got a modem message, process it and add it to the rednet event queue | ||||||
|             local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4 |             local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4 | ||||||
|             if isOpen(sModem) and (nChannel == id_as_channel() or nChannel == CHANNEL_BROADCAST) then |             if nChannel == id_as_channel() or nChannel == CHANNEL_BROADCAST then | ||||||
|                 if type(tMessage) == "table" and type(tMessage.nMessageID) == "number" |                 if type(tMessage) == "table" and type(tMessage.nMessageID) == "number" | ||||||
|                     and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID] |                     and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID] | ||||||
|                     and ((tMessage.nRecipient and tMessage.nRecipient == os.getComputerID()) or nChannel == CHANNEL_BROADCAST) |                     and ((tMessage.nRecipient and tMessage.nRecipient == os.getComputerID()) or nChannel == CHANNEL_BROADCAST) | ||||||
|  |                     and isOpen(sModem) | ||||||
|                 then |                 then | ||||||
|                     tReceivedMessages[tMessage.nMessageID] = os.clock() + 9.5 |                     tReceivedMessages[tMessage.nMessageID] = os.clock() + 9.5 | ||||||
|                     if not nClearTimer then nClearTimer = os.startTimer(10) end |                     if not nClearTimer then nClearTimer = os.startTimer(10) end | ||||||
|   | |||||||
| @@ -8,7 +8,6 @@ package dan200.computercraft.core.apis; | |||||||
| import dan200.computercraft.api.lua.*; | import dan200.computercraft.api.lua.*; | ||||||
| import dan200.computercraft.core.asm.LuaMethod; | import dan200.computercraft.core.asm.LuaMethod; | ||||||
| import dan200.computercraft.core.asm.NamedMethod; | import dan200.computercraft.core.asm.NamedMethod; | ||||||
| import dan200.computercraft.core.asm.TaskCallback; |  | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| @@ -65,11 +64,4 @@ public class ObjectWrapper implements ILuaContext | |||||||
|     { |     { | ||||||
|         throw new IllegalStateException( "Method should never queue events" ); |         throw new IllegalStateException( "Method should never queue events" ); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     @Nonnull |  | ||||||
|     @Override |  | ||||||
|     public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException |  | ||||||
|     { |  | ||||||
|         return TaskCallback.make( this, task ); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -124,7 +124,7 @@ public class GeneratorTest | |||||||
|     { |     { | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void go() |         public final void go() | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class Basic2 extends Basic |     public static class Basic2 extends Basic | ||||||
| @@ -139,14 +139,14 @@ public class GeneratorTest | |||||||
|     { |     { | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void go() |         public final void go() | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class NonInstance |     public static class NonInstance | ||||||
|     { |     { | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public static void go() |         public static void go() | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class IllegalThrows |     public static class IllegalThrows | ||||||
| @@ -162,42 +162,42 @@ public class GeneratorTest | |||||||
|     { |     { | ||||||
|         @LuaFunction( { "go1", "go2" } ) |         @LuaFunction( { "go1", "go2" } ) | ||||||
|         public final void go() |         public final void go() | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class ArgKinds |     public static class ArgKinds | ||||||
|     { |     { | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void objectArg( Object arg ) |         public final void objectArg( Object arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void intArg( int arg ) |         public final void intArg( int arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void optIntArg( Optional<Integer> arg ) |         public final void optIntArg( Optional<Integer> arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void context( ILuaContext arg ) |         public final void context( ILuaContext arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void arguments( IArguments arg ) |         public final void arguments( IArguments arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void unknown( IComputerAccess arg ) |         public final void unknown( IComputerAccess arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void illegalMap( Map<String, Integer> arg ) |         public final void illegalMap( Map<String, Integer> arg ) | ||||||
|         { } |         {} | ||||||
| 
 | 
 | ||||||
|         @LuaFunction |         @LuaFunction | ||||||
|         public final void optIllegalMap( Optional<Map<String, Integer>> arg ) |         public final void optIllegalMap( Optional<Map<String, Integer>> arg ) | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class EnumMethods |     public static class EnumMethods | ||||||
| @@ -219,7 +219,7 @@ public class GeneratorTest | |||||||
|     { |     { | ||||||
|         @LuaFunction( mainThread = true ) |         @LuaFunction( mainThread = true ) | ||||||
|         public final void go() |         public final void go() | ||||||
|         { } |         {} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static <T> T find( Collection<NamedMethod<T>> methods, String name ) |     private static <T> T find( Collection<NamedMethod<T>> methods, String name ) | ||||||
| @@ -256,12 +256,5 @@ public class GeneratorTest | |||||||
|         { |         { | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         @Nonnull |  | ||||||
|         @Override |  | ||||||
|         public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException |  | ||||||
|         { |  | ||||||
|             return TaskCallback.make( this, task ); |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -57,7 +57,7 @@ class Monitor_Test { | |||||||
|                 val monitor = helper.getBlockEntity(BlockPos(2, 2, 3), Registry.ModBlockEntities.MONITOR_ADVANCED.get()) |                 val monitor = helper.getBlockEntity(BlockPos(2, 2, 3), Registry.ModBlockEntities.MONITOR_ADVANCED.get()) | ||||||
|                 monitor.getCapability(Capabilities.CAPABILITY_PERIPHERAL) |                 monitor.getCapability(Capabilities.CAPABILITY_PERIPHERAL) | ||||||
| 
 | 
 | ||||||
|                 val terminal = monitor.cachedServerMonitor.terminal |                 val terminal = monitor.cachedServerMonitor!!.terminal | ||||||
|                 terminal.write("Hello, world!") |                 terminal.write("Hello, world!") | ||||||
|                 terminal.setCursorPos(1, 2) |                 terminal.setCursorPos(1, 2) | ||||||
|                 terminal.textColour = 2 |                 terminal.textColour = 2 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates