mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-11-03 23:22:59 +00:00 
			
		
		
		
	Compare commits
	
		
			261 Commits
		
	
	
		
			v1.20.4-1.
			...
			v1.20.1-1.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					18f3426f1d | ||
| 
						 | 
					0ec46fe38e | ||
| 
						 | 
					569de7fafb | ||
| 
						 | 
					157ce4fa55 | ||
| 
						 | 
					b9ed66983d | ||
| 
						 | 
					d0fbec6c6b | ||
| 
						 | 
					a683697e8c | ||
| 
						 | 
					9e233a916f | ||
| 
						 | 
					5a9e21ccc3 | ||
| 
						 | 
					5f16909d4b | ||
| 
						 | 
					00475b9bb0 | ||
| 
						 | 
					018ce7c8a5 | ||
| 
						 | 
					44726827b4 | ||
| 
						 | 
					3cf914cb4c | ||
| 
						 | 
					180156ff1c | ||
| 
						 | 
					c6ba753568 | ||
| 
						 | 
					9f45c91925 | ||
| 
						 | 
					8344c0a5c2 | ||
| 
						 | 
					a292d33830 | ||
| 
						 | 
					341d1c7bc2 | ||
| 
						 | 
					531eacfac7 | ||
| 
						 | 
					1f3da5205c | ||
| 
						 | 
					798ceefafe | ||
| 
						 | 
					7c0f79fc3c | ||
| 
						 | 
					b35cefc5dd | ||
| 
						 | 
					69353a4fcf | ||
| 
						 | 
					ff363dca5a | ||
| 
						 | 
					1c51282426 | ||
| 
						 | 
					4a3a1c9275 | ||
| 
						 | 
					2557dd0af9 | ||
| 
						 | 
					b5c0c6e104 | ||
| 
						 | 
					876fd8ddb8 | ||
| 
						 | 
					ee3b1343b5 | ||
| 
						 | 
					b440b964b7 | ||
| 
						 | 
					5dfc401b45 | ||
| 
						 | 
					4344c3072f | ||
| 
						 | 
					947001104d | ||
| 
						 | 
					8711512769 | ||
| 
						 | 
					9c0ce27ce6 | ||
| 
						 | 
					c458360b18 | ||
| 
						 | 
					09ad6c1905 | ||
| 
						 | 
					0e1e8a72d3 | ||
| 
						 | 
					7c1e8e1951 | ||
| 
						 | 
					b03546a158 | ||
| 
						 | 
					582713467f | ||
| 
						 | 
					b6f41a0df5 | ||
| 
						 | 
					594738a022 | ||
| 
						 | 
					27f2ab364c | ||
| 
						 | 
					5a43273757 | ||
| 
						 | 
					97e28516fb | ||
| 
						 | 
					676fb5fb53 | ||
| 
						 | 
					63ba3fe274 | ||
| 
						 | 
					749b3df227 | ||
| 
						 | 
					b97634b717 | ||
| 
						 | 
					1b8344d0a3 | ||
| 
						 | 
					b42bc0a01a | ||
| 
						 | 
					0cff73e2fc | ||
| 
						 | 
					a892739f8e | ||
| 
						 | 
					f8785a092f | ||
| 
						 | 
					dd7e8fcefc | ||
| 
						 | 
					29c8f96912 | ||
| 
						 | 
					b9267ecbfc | ||
| 
						 | 
					9d2c2db22b | ||
| 
						 | 
					6660966320 | ||
| 
						 | 
					16324e1eac | ||
| 
						 | 
					32f5c38485 | ||
| 
						 | 
					01fe949b3e | ||
| 
						 | 
					c03fce275e | ||
| 
						 | 
					0998acaa82 | ||
| 
						 | 
					12a44fed6f | ||
| 
						 | 
					0a8d505323 | ||
| 
						 | 
					237a0ac3bb | ||
| 
						 | 
					b185d088b3 | ||
| 
						 | 
					051c70a731 | ||
| 
						 | 
					2e2f308ff3 | ||
| 
						 | 
					0f123b5efd | ||
| 
						 | 
					88cb03be6b | ||
| 
						 | 
					4360485880 | ||
| 
						 | 
					b69a44a927 | ||
| 
						 | 
					7d8f609c49 | ||
| 
						 | 
					e7f56c4d25 | ||
| 
						 | 
					fa2140d00b | ||
| 
						 | 
					03388149b1 | ||
| 
						 | 
					f212861370 | ||
| 
						 | 
					55edced9de | ||
| 
						 | 
					dc969c5a78 | ||
| 
						 | 
					94ad6dab0e | ||
| 
						 | 
					938eb38ad5 | ||
| 
						 | 
					6739c4c6c0 | ||
| 
						 | 
					d6749f8461 | ||
| 
						 | 
					5ba7f99326 | ||
| 
						 | 
					62c9e5b08f | ||
| 
						 | 
					2ca5850060 | ||
| 
						 | 
					ed631b05e7 | ||
| 
						 | 
					a2b9490d5c | ||
| 
						 | 
					8204944b5f | ||
| 
						 | 
					ef0af67e96 | ||
| 
						 | 
					9a914e75c4 | ||
| 
						 | 
					546577041b | ||
| 
						 | 
					f881c0ced0 | ||
| 
						 | 
					0b389e04b0 | ||
| 
						 | 
					d3a3ab3c21 | ||
| 
						 | 
					22e6c06e59 | ||
| 
						 | 
					3c46b8acd7 | ||
| 
						 | 
					d9fc1c3a80 | ||
| 
						 | 
					479aabdd09 | ||
| 
						 | 
					ad74893058 | ||
| 
						 | 
					2ba6d5815b | ||
| 
						 | 
					7e2f490626 | ||
| 
						 | 
					4dc649d5e5 | ||
| 
						 | 
					5bab415790 | ||
| 
						 | 
					9bbf3f3e1d | ||
| 
						 | 
					7c02979c22 | ||
| 
						 | 
					fdb65c9368 | ||
| 
						 | 
					ea670cc358 | ||
| 
						 | 
					1963e0160f | ||
| 
						 | 
					9a06904634 | ||
| 
						 | 
					5e24ad17d7 | ||
| 
						 | 
					8b1cb09ddf | ||
| 
						 | 
					d1a6b043c2 | ||
| 
						 | 
					cddb8fec11 | ||
| 
						 | 
					1d7d8006d4 | ||
| 
						 | 
					63bdc2537c | ||
| 
						 | 
					f776b17150 | ||
| 
						 | 
					31da2555cb | ||
| 
						 | 
					9b19a93ab9 | ||
| 
						 | 
					ad52117f0f | ||
| 
						 | 
					bdffabc08e | ||
| 
						 | 
					87ce41f251 | ||
| 
						 | 
					e7c7919cad | ||
| 
						 | 
					4f66ac79d3 | ||
| 
						 | 
					ba6da3bc6c | ||
| 
						 | 
					b742745854 | ||
| 
						 | 
					3293639adf | ||
| 
						 | 
					064ff31830 | ||
| 
						 | 
					5d473725d5 | ||
| 
						 | 
					97a2f2dbdd | ||
| 
						 | 
					37c4789fa4 | ||
| 
						 | 
					0aaeeeee24 | ||
| 
						 | 
					2155ec3d63 | ||
| 
						 | 
					0da906fc93 | ||
| 
						 | 
					9e5e6a1b60 | ||
| 
						 | 
					dcc74e15c7 | ||
| 
						 | 
					c271ed7c7f | ||
| 
						 | 
					d6a246c122 | ||
| 
						 | 
					0bef3ee0d8 | ||
| 
						 | 
					bb04df7086 | ||
| 
						 | 
					a70baf0d74 | ||
| 
						 | 
					86e2f92493 | ||
| 
						 | 
					e9aceca1de | ||
| 
						 | 
					3042950507 | ||
| 
						 | 
					f7a6aac657 | ||
| 
						 | 
					782564e6ab | ||
| 
						 | 
					6b8ba8b80b | ||
| 
						 | 
					52b76d8886 | ||
| 
						 | 
					ba36c69583 | ||
| 
						 | 
					370e5f92a0 | ||
| 
						 | 
					36d05e4774 | ||
| 
						 | 
					89d1be17c9 | ||
| 
						 | 
					0069591af9 | ||
| 
						 | 
					c36c8605bf | ||
| 
						 | 
					3c72a00d46 | ||
| 
						 | 
					58aefc8df8 | ||
| 
						 | 
					97ddfc2794 | ||
| 
						 | 
					6e4ec86586 | ||
| 
						 | 
					d24984c1d5 | ||
| 
						 | 
					8080dcdd9e | ||
| 
						 | 
					d7cea55e2a | ||
| 
						 | 
					9b2f974a81 | ||
| 
						 | 
					43770fa9bd | ||
| 
						 | 
					80c7a54ad4 | ||
| 
						 | 
					e57b6fede2 | ||
| 
						 | 
					34a2fd039f | ||
| 
						 | 
					3299d0e72a | ||
| 
						 | 
					b89e2615db | ||
| 
						 | 
					cdcd82679c | ||
| 
						 | 
					cdfa866760 | ||
| 
						 | 
					aa8078ddeb | ||
| 
						 | 
					7e53c19d74 | ||
| 
						 | 
					b7a8432cfb | ||
| 
						 | 
					356c8e8aeb | ||
| 
						 | 
					ed283155f7 | ||
| 
						 | 
					87dfad026e | ||
| 
						 | 
					bb97c465d9 | ||
| 
						 | 
					9484315d37 | ||
| 
						 | 
					be59f1a875 | ||
| 
						 | 
					bfb28b4710 | ||
| 
						 | 
					216f0adb3c | ||
| 
						 | 
					77af4bc213 | ||
| 
						 | 
					5abab982c7 | ||
| 
						 | 
					764e1aa332 | ||
| 
						 | 
					c47718b09d | ||
| 
						 | 
					08d4f91c8b | ||
| 
						 | 
					b9eac4e509 | ||
| 
						 | 
					dc3d8ea198 | ||
| 
						 | 
					cbe075b001 | ||
| 
						 | 
					ed0b156e05 | ||
| 
						 | 
					4dd0735066 | ||
| 
						 | 
					38e516d7c7 | ||
| 
						 | 
					70a31855ac | ||
| 
						 | 
					6c8e64ffcd | ||
| 
						 | 
					7285c32d58 | ||
| 
						 | 
					99c60ac54b | ||
| 
						 | 
					63e40cf3cb | ||
| 
						 | 
					1d45935a25 | ||
| 
						 | 
					f80373e7a2 | ||
| 
						 | 
					63185629b7 | ||
| 
						 | 
					4bfb9ac323 | ||
| 
						 | 
					5926b6c994 | ||
| 
						 | 
					f5ed43584d | ||
| 
						 | 
					d77f5f135f | ||
| 
						 | 
					7744d2663b | ||
| 
						 | 
					4566cb8273 | ||
| 
						 | 
					052e7a7ae5 | ||
| 
						 | 
					0895200681 | ||
| 
						 | 
					09d0f563b7 | ||
| 
						 | 
					e188f1d3fa | ||
| 
						 | 
					819a4f7231 | ||
| 
						 | 
					898cb2a95d | ||
| 
						 | 
					03a8f83191 | ||
| 
						 | 
					aef92c8ebc | ||
| 
						 | 
					571ea794a8 | ||
| 
						 | 
					e81af93043 | ||
| 
						 | 
					25b8a65c5c | ||
| 
						 | 
					e4236824d7 | ||
| 
						 | 
					cfd11ffa92 | ||
| 
						 | 
					ce133a5e66 | ||
| 
						 | 
					038fbc1ed1 | ||
| 
						 | 
					c582fb521c | ||
| 
						 | 
					af21792844 | ||
| 
						 | 
					9fbb1070ef | ||
| 
						 | 
					1944995c33 | ||
| 
						 | 
					ac851a795b | ||
| 
						 | 
					334761788a | ||
| 
						 | 
					5af3e15dd5 | ||
| 
						 | 
					209b1ddbf9 | ||
| 
						 | 
					0c9f9a8652 | ||
| 
						 | 
					862d92785e | ||
| 
						 | 
					d48b85d50c | ||
| 
						 | 
					4d619de357 | ||
| 
						 | 
					57c289f173 | ||
| 
						 | 
					f63f85921f | ||
| 
						 | 
					c7e49d1929 | ||
| 
						 | 
					d9b0cc7075 | ||
| 
						 | 
					1e214f329e | ||
| 
						 | 
					de930c8d09 | ||
| 
						 | 
					735e7ce09b | ||
| 
						 | 
					6e9799316a | ||
| 
						 | 
					4e90240922 | ||
| 
						 | 
					1a87d1bf45 | ||
| 
						 | 
					00e2e2bd2d | ||
| 
						 | 
					7c1f40031b | ||
| 
						 | 
					929debd382 | ||
| 
						 | 
					4980b7355d | ||
| 
						 | 
					925092add3 | ||
| 
						 | 
					550296edc5 | ||
| 
						 | 
					0771c4891b | ||
| 
						 | 
					776fa00b94 | ||
| 
						 | 
					03bb279206 | ||
| 
						 | 
					fabd77132d | ||
| 
						 | 
					95be0a25bf | 
@@ -18,11 +18,6 @@ ij_any_if_brace_force = if_multiline
 | 
				
			|||||||
ij_any_for_brace_force = if_multiline
 | 
					ij_any_for_brace_force = if_multiline
 | 
				
			||||||
ij_any_spaces_within_array_initializer_braces = true
 | 
					ij_any_spaces_within_array_initializer_braces = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ij_kotlin_allow_trailing_comma = true
 | 
					 | 
				
			||||||
ij_kotlin_allow_trailing_comma_on_call_site = true
 | 
					 | 
				
			||||||
ij_kotlin_method_parameters_wrap = off
 | 
					 | 
				
			||||||
ij_kotlin_call_parameters_wrap = off
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[*.md]
 | 
					[*.md]
 | 
				
			||||||
trim_trailing_whitespace = false
 | 
					trim_trailing_whitespace = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,3 +26,27 @@ indent_size = 2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[*.yml]
 | 
					[*.yml]
 | 
				
			||||||
indent_size = 2
 | 
					indent_size = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[*.{kt,kts}]
 | 
				
			||||||
 | 
					ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
 | 
				
			||||||
 | 
					ij_kotlin_continuation_indent_size = 4
 | 
				
			||||||
 | 
					ij_kotlin_spaces_around_equality_operators = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ij_kotlin_allow_trailing_comma = true
 | 
				
			||||||
 | 
					ij_kotlin_allow_trailing_comma_on_call_site = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Prefer to handle these manually
 | 
				
			||||||
 | 
					ij_kotlin_method_parameters_wrap = off
 | 
				
			||||||
 | 
					ij_kotlin_call_parameters_wrap = off
 | 
				
			||||||
 | 
					ij_kotlin_extends_list_wrap = off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ktlint_code_style = intellij_idea
 | 
				
			||||||
 | 
					ktlint_standard_class-naming = disabled
 | 
				
			||||||
 | 
					ktlint_standard_class-signature = disabled
 | 
				
			||||||
 | 
					ktlint_standard_function-naming = disabled
 | 
				
			||||||
 | 
					ktlint_standard_no-wildcard-imports = disabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: These two are disable right now as they're over-eager in putting things
 | 
				
			||||||
 | 
					#  on the same line. We should set max_line_length and handle this properly.
 | 
				
			||||||
 | 
					ktlint_standard_function-signature = disabled
 | 
				
			||||||
 | 
					ktlint_standard_function-expression-body = disabled
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/ISSUE_TEMPLATE/bug_report.yaml
									
									
									
									
										vendored
									
									
								
							@@ -1,17 +1,18 @@
 | 
				
			|||||||
name: Bug report
 | 
					name: Bug report
 | 
				
			||||||
description: Report some misbehaviour in the mod
 | 
					description: Report some misbehaviour in the mod
 | 
				
			||||||
labels: [ bug ]
 | 
					labels: [ bug ]
 | 
				
			||||||
 | 
					type: bug
 | 
				
			||||||
body:
 | 
					body:
 | 
				
			||||||
- type: dropdown
 | 
					- type: dropdown
 | 
				
			||||||
  id: mc-version
 | 
					  id: mc-version
 | 
				
			||||||
  attributes:
 | 
					  attributes:
 | 
				
			||||||
    label: Minecraft Version
 | 
					    label: Minecraft Version
 | 
				
			||||||
    description: What version of Minecraft are you using?
 | 
					    description: |
 | 
				
			||||||
 | 
					        What version of Minecraft are you using? If your version is not listed, please try to reproduce on one of the supported versions.
 | 
				
			||||||
    options:
 | 
					    options:
 | 
				
			||||||
      - 1.16.x
 | 
					      - 1.20.1
 | 
				
			||||||
      - 1.18.x
 | 
					      - 1.21.1
 | 
				
			||||||
      - 1.19.x
 | 
					      - 1.21.7
 | 
				
			||||||
      - 1.20.x
 | 
					 | 
				
			||||||
  validations:
 | 
					  validations:
 | 
				
			||||||
    required: true
 | 
					    required: true
 | 
				
			||||||
- type: input
 | 
					- type: input
 | 
				
			||||||
@@ -28,8 +29,7 @@ body:
 | 
				
			|||||||
    label: Details
 | 
					    label: Details
 | 
				
			||||||
    description: |
 | 
					    description: |
 | 
				
			||||||
      Description of the bug. Please include the following:
 | 
					      Description of the bug. Please include the following:
 | 
				
			||||||
      - Logs: These will be located in the `logs/` directory of your Minecraft
 | 
					      - Logs: These will be located in the `logs/` directory of your Minecraft instance. This is always useful, even if it doesn't include errors, so please upload this!
 | 
				
			||||||
        instance. Please upload them as a gist or directly into this editor.
 | 
					      - Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.
 | 
				
			||||||
      - Detailed reproduction steps: sometimes I can spot a bug pretty easily,
 | 
					
 | 
				
			||||||
        but often it's much more obscure. The more information I have to help
 | 
					      
 | 
				
			||||||
        reproduce it, the quicker it'll get fixed.
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
								
							@@ -2,6 +2,7 @@
 | 
				
			|||||||
name: Feature request
 | 
					name: Feature request
 | 
				
			||||||
about: Suggest an idea or improvement
 | 
					about: Suggest an idea or improvement
 | 
				
			||||||
labels: enhancement
 | 
					labels: enhancement
 | 
				
			||||||
 | 
					type: feature
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!--
 | 
					<!--
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										60
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@ jobs:
 | 
				
			|||||||
    - name: 📥 Set up Java
 | 
					    - name: 📥 Set up Java
 | 
				
			||||||
      uses: actions/setup-java@v4
 | 
					      uses: actions/setup-java@v4
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        java-version: 17
 | 
					        java-version: 21
 | 
				
			||||||
        distribution: 'temurin'
 | 
					        distribution: 'temurin'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: 📥 Setup Gradle
 | 
					    - name: 📥 Setup Gradle
 | 
				
			||||||
@@ -30,8 +30,28 @@ jobs:
 | 
				
			|||||||
    - name: ⚒️ Build
 | 
					    - name: ⚒️ Build
 | 
				
			||||||
      run: ./gradlew assemble || ./gradlew assemble
 | 
					      run: ./gradlew assemble || ./gradlew assemble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: 📦 Prepare Jars
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        # Find the main jar and append the git hash onto it.
 | 
				
			||||||
 | 
					        mkdir -p jars
 | 
				
			||||||
 | 
					        find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: 📤 Upload Jar
 | 
				
			||||||
 | 
					      uses: actions/upload-artifact@v4
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: CC-Tweaked
 | 
				
			||||||
 | 
					        path: ./jars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Cache pre-commit
 | 
				
			||||||
 | 
					      uses: actions/cache@v4
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        path: ~/.cache/pre-commit
 | 
				
			||||||
 | 
					        key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: 💡 Lint
 | 
					    - name: 💡 Lint
 | 
				
			||||||
      uses: pre-commit/action@v3.0.0
 | 
					      run: |
 | 
				
			||||||
 | 
					        pipx install pre-commit
 | 
				
			||||||
 | 
					        pre-commit run --show-diff-on-failure --color=always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: 🧪 Run tests
 | 
					    - name: 🧪 Run tests
 | 
				
			||||||
      run: ./gradlew test validateMixinNames checkChangelog
 | 
					      run: ./gradlew test validateMixinNames checkChangelog
 | 
				
			||||||
@@ -42,30 +62,10 @@ jobs:
 | 
				
			|||||||
    - name: 🧪 Run integration tests
 | 
					    - name: 🧪 Run integration tests
 | 
				
			||||||
      run: ./gradlew runGametest
 | 
					      run: ./gradlew runGametest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: 🧪 Run client tests
 | 
					 | 
				
			||||||
      run: ./gradlew runGametestClient # Not checkClient, as no point running rendering tests.
 | 
					 | 
				
			||||||
      # These are a little flaky on GH actions: its useful to run them, but don't break the build.
 | 
					 | 
				
			||||||
      continue-on-error: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: 🧪 Parse test reports
 | 
					    - name: 🧪 Parse test reports
 | 
				
			||||||
      run: ./tools/parse-reports.py
 | 
					      run: ./tools/parse-reports.py
 | 
				
			||||||
      if: ${{ failure() }}
 | 
					      if: ${{ failure() }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: 📦 Prepare Jars
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        # Find the main jar and append the git hash onto it.
 | 
					 | 
				
			||||||
        mkdir -p jars
 | 
					 | 
				
			||||||
        find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: 📤 Upload Jar
 | 
					 | 
				
			||||||
      uses: actions/upload-artifact@v3
 | 
					 | 
				
			||||||
      with:
 | 
					 | 
				
			||||||
        name: CC-Tweaked
 | 
					 | 
				
			||||||
        path: ./jars
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: 📤 Upload coverage
 | 
					 | 
				
			||||||
      uses: codecov/codecov-action@v3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  build-core:
 | 
					  build-core:
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
@@ -81,24 +81,28 @@ jobs:
 | 
				
			|||||||
    runs-on: ${{ matrix.uses }}
 | 
					    runs-on: ${{ matrix.uses }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Clone repository
 | 
					    - name: 📥 Clone repository
 | 
				
			||||||
      uses: actions/checkout@v4
 | 
					      uses: actions/checkout@v4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Set up Java
 | 
					    - name: 📥 Set up Java
 | 
				
			||||||
      uses: actions/setup-java@v4
 | 
					      uses: actions/setup-java@v4
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        java-version: 17
 | 
					        java-version: 21
 | 
				
			||||||
        distribution: 'temurin'
 | 
					        distribution: 'temurin'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Setup Gradle
 | 
					    - name: 📥 Setup Gradle
 | 
				
			||||||
      uses: gradle/actions/setup-gradle@v3
 | 
					      uses: gradle/actions/setup-gradle@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
 | 
					        cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Run tests
 | 
					    - name: ⚒️ Build
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        ./gradlew --configure-on-demand :core:assemble
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: 🧪 Run tests
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        ./gradlew --configure-on-demand :core:test
 | 
					        ./gradlew --configure-on-demand :core:test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Parse test reports
 | 
					    - name: 🧪 Parse test reports
 | 
				
			||||||
      run: python3 ./tools/parse-reports.py
 | 
					      run: python3 ./tools/parse-reports.py
 | 
				
			||||||
      if: ${{ failure() }}
 | 
					      if: ${{ failure() }}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								.github/workflows/make-doc.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/make-doc.sh
									
									
									
									
										vendored
									
									
								
							@@ -1,19 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/env bash
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set -eu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
DEST="${GITHUB_REF#refs/*/}"
 | 
					 | 
				
			||||||
echo "Uploading docs to https://tweaked.cc/$DEST"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Setup ssh key
 | 
					 | 
				
			||||||
mkdir -p "$HOME/.ssh/"
 | 
					 | 
				
			||||||
echo "$SSH_KEY" > "$HOME/.ssh/key"
 | 
					 | 
				
			||||||
chmod 600 "$HOME/.ssh/key"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# And upload
 | 
					 | 
				
			||||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
 | 
					 | 
				
			||||||
      "$GITHUB_WORKSPACE/projects/web/build/site/" \
 | 
					 | 
				
			||||||
      "$SSH_USER@$SSH_HOST:/$DEST"
 | 
					 | 
				
			||||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
 | 
					 | 
				
			||||||
      "$GITHUB_WORKSPACE/projects/common-api/build/docs/javadoc/" \
 | 
					 | 
				
			||||||
      "$SSH_USER@$SSH_HOST:/$DEST/javadoc"
 | 
					 | 
				
			||||||
							
								
								
									
										30
									
								
								.github/workflows/make-doc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								.github/workflows/make-doc.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,8 +3,7 @@ name: Build documentation
 | 
				
			|||||||
on:
 | 
					on:
 | 
				
			||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches:
 | 
					    branches:
 | 
				
			||||||
    - mc-1.19.x
 | 
					    - mc-*
 | 
				
			||||||
    - mc-1.20.x
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  make_doc:
 | 
					  make_doc:
 | 
				
			||||||
@@ -12,30 +11,25 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Clone repository
 | 
					    - name: 📥 Clone repository
 | 
				
			||||||
      uses: actions/checkout@v4
 | 
					      uses: actions/checkout@v4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Set up Java
 | 
					    - name: 📥 Set up Java
 | 
				
			||||||
      uses: actions/setup-java@v4
 | 
					      uses: actions/setup-java@v4
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        java-version: 17
 | 
					        java-version: 21
 | 
				
			||||||
        distribution: 'temurin'
 | 
					        distribution: 'temurin'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Setup Gradle
 | 
					    - name: 📥 Setup Gradle
 | 
				
			||||||
      uses: gradle/actions/setup-gradle@v3
 | 
					      uses: gradle/actions/setup-gradle@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
 | 
					        cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Build with Gradle
 | 
					    - name: ⚒️ Generate documentation
 | 
				
			||||||
      run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon
 | 
					      run: ./gradlew docWebsite --no-daemon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Generate documentation
 | 
					    - name: 📤 Upload Jar
 | 
				
			||||||
      run: ./gradlew docWebsite :common-api:javadoc  --no-daemon
 | 
					      uses: actions/upload-artifact@v4
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
    - name: Upload documentation
 | 
					        name: Documentation
 | 
				
			||||||
      run: .github/workflows/make-doc.sh 2> /dev/null
 | 
					        path: ./projects/web/build/site/
 | 
				
			||||||
      env:
 | 
					 | 
				
			||||||
        SSH_KEY:  ${{ secrets.SSH_KEY  }}
 | 
					 | 
				
			||||||
        SSH_USER: ${{ secrets.SSH_USER }}
 | 
					 | 
				
			||||||
        SSH_HOST: ${{ secrets.SSH_HOST }}
 | 
					 | 
				
			||||||
        SSH_PORT: ${{ secrets.SSH_PORT }}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -27,6 +27,7 @@
 | 
				
			|||||||
*.iml
 | 
					*.iml
 | 
				
			||||||
.idea
 | 
					.idea
 | 
				
			||||||
.gradle
 | 
					.gradle
 | 
				
			||||||
 | 
					.kotlin
 | 
				
			||||||
*.DS_Store
 | 
					*.DS_Store
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/.classpath
 | 
					/.classpath
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								.gitpod.yml
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								.gitpod.yml
									
									
									
									
									
								
							@@ -1,26 +0,0 @@
 | 
				
			|||||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
image:
 | 
					 | 
				
			||||||
  file: config/gitpod/Dockerfile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ports:
 | 
					 | 
				
			||||||
  - port: 25565
 | 
					 | 
				
			||||||
    onOpen: notify
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vscode:
 | 
					 | 
				
			||||||
  extensions:
 | 
					 | 
				
			||||||
    - eamodio.gitlens
 | 
					 | 
				
			||||||
    - github.vscode-pull-request-github
 | 
					 | 
				
			||||||
    - ms-azuretools.vscode-docker
 | 
					 | 
				
			||||||
    - redhat.java
 | 
					 | 
				
			||||||
    - richardwillis.vscode-gradle
 | 
					 | 
				
			||||||
    - vscjava.vscode-java-debug
 | 
					 | 
				
			||||||
    - vscode.github
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks:
 | 
					 | 
				
			||||||
  - name: Setup pre-commit hool
 | 
					 | 
				
			||||||
    init: pre-commit install --allow-missing-config
 | 
					 | 
				
			||||||
  - name: Install npm packages
 | 
					 | 
				
			||||||
    init: npm ci
 | 
					 | 
				
			||||||
@@ -6,7 +6,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: v4.4.0
 | 
					  rev: v5.0.0
 | 
				
			||||||
  hooks:
 | 
					  hooks:
 | 
				
			||||||
  - id: trailing-whitespace
 | 
					  - id: trailing-whitespace
 | 
				
			||||||
  - id: end-of-file-fixer
 | 
					  - id: end-of-file-fixer
 | 
				
			||||||
@@ -27,7 +27,7 @@ repos:
 | 
				
			|||||||
    exclude: "^(.*\\.(bat)|LICENSE)$"
 | 
					    exclude: "^(.*\\.(bat)|LICENSE)$"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- repo: https://github.com/fsfe/reuse-tool
 | 
					- repo: https://github.com/fsfe/reuse-tool
 | 
				
			||||||
  rev: v2.1.0
 | 
					  rev: v5.0.2
 | 
				
			||||||
  hooks:
 | 
					  hooks:
 | 
				
			||||||
  - id: reuse
 | 
					  - id: reuse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,6 +58,7 @@ repos:
 | 
				
			|||||||
exclude: |
 | 
					exclude: |
 | 
				
			||||||
  (?x)^(
 | 
					  (?x)^(
 | 
				
			||||||
    projects/[a-z]+/src/generated|
 | 
					    projects/[a-z]+/src/generated|
 | 
				
			||||||
 | 
					    projects/[a-z]+/src/examples/generatedResources|
 | 
				
			||||||
    projects/core/src/test/resources/test-rom/data/json-parsing/|
 | 
					    projects/core/src/test/resources/test-rom/data/json-parsing/|
 | 
				
			||||||
    .*\.dfpwm
 | 
					    .*\.dfpwm
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										100
									
								
								.reuse/dep5
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								.reuse/dep5
									
									
									
									
									
								
							@@ -1,100 +0,0 @@
 | 
				
			|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 | 
					 | 
				
			||||||
Source: https://github.com/cc-tweaked/cc-tweaked
 | 
					 | 
				
			||||||
Upstream-Name: CC: Tweaked
 | 
					 | 
				
			||||||
Upstream-Contact: Jonathan Coates <git@squiddev.cc>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/sounds.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg
 | 
					 | 
				
			||||||
  projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/*
 | 
					 | 
				
			||||||
  projects/common/src/testMod/resources/data/cctest/structures/*
 | 
					 | 
				
			||||||
  projects/fabric/src/generated/*
 | 
					 | 
				
			||||||
  projects/forge/src/generated/*
 | 
					 | 
				
			||||||
  projects/web/src/htmlTransform/export/index.json
 | 
					 | 
				
			||||||
  projects/web/src/htmlTransform/export/items/minecraft/*
 | 
					 | 
				
			||||||
Comment: Generated/data files are CC0.
 | 
					 | 
				
			||||||
Copyright: The CC: Tweaked Developers
 | 
					 | 
				
			||||||
License: CC0-1.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  doc/images/*
 | 
					 | 
				
			||||||
  package.json
 | 
					 | 
				
			||||||
  package-lock.json
 | 
					 | 
				
			||||||
  projects/common/src/client/resources/computercraft-client.mixins.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/computercraft.mixins.json
 | 
					 | 
				
			||||||
  projects/common/src/testMod/resources/computercraft-gametest.mixins.json
 | 
					 | 
				
			||||||
  projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json
 | 
					 | 
				
			||||||
  projects/common/src/testMod/resources/pack.mcmeta
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt
 | 
					 | 
				
			||||||
  projects/fabric-api/src/main/modJson/fabric.mod.json
 | 
					 | 
				
			||||||
  projects/fabric/src/client/resources/computercraft-client.fabric.mixins.json
 | 
					 | 
				
			||||||
  projects/fabric/src/main/resources/computercraft.fabric.mixins.json
 | 
					 | 
				
			||||||
  projects/fabric/src/main/resources/fabric.mod.json
 | 
					 | 
				
			||||||
  projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json
 | 
					 | 
				
			||||||
  projects/fabric/src/testMod/resources/fabric.mod.json
 | 
					 | 
				
			||||||
  projects/forge/src/client/resources/computercraft-client.forge.mixins.json
 | 
					 | 
				
			||||||
  projects/web/src/frontend/mount/.settings
 | 
					 | 
				
			||||||
  projects/web/src/frontend/mount/example.nfp
 | 
					 | 
				
			||||||
  projects/web/src/frontend/mount/example.nft
 | 
					 | 
				
			||||||
  projects/web/src/frontend/mount/expr_template.lua
 | 
					 | 
				
			||||||
  projects/web/tsconfig.json
 | 
					 | 
				
			||||||
Comment: Several assets where it's inconvenient to create a .license file.
 | 
					 | 
				
			||||||
Copyright: The CC: Tweaked Developers
 | 
					 | 
				
			||||||
License: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  doc/logo.png
 | 
					 | 
				
			||||||
  doc/logo-darkmode.png
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/models/*
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/textures/*
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/pack.mcmeta
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/pack.png
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/assets/computercraft/textures/gui/term_font.png
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/help/*
 | 
					 | 
				
			||||||
  projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/*
 | 
					 | 
				
			||||||
  projects/web/src/htmlTransform/export/items/computercraft/*
 | 
					 | 
				
			||||||
Comment: Bulk-license original assets as CCPL.
 | 
					 | 
				
			||||||
Copyright: 2011 Daniel Ratcliffe
 | 
					 | 
				
			||||||
License: LicenseRef-CCPL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/ko_kr.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/pl_pl.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/pt_br.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json
 | 
					 | 
				
			||||||
Comment: Community-contributed license files
 | 
					 | 
				
			||||||
Copyright: 2017 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
License: LicenseRef-CCPL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  projects/common/src/main/resources/assets/computercraft/lang/*
 | 
					 | 
				
			||||||
Comment: Community-contributed license files
 | 
					 | 
				
			||||||
Copyright: 2017 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
License: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  .github/*
 | 
					 | 
				
			||||||
Comment:
 | 
					 | 
				
			||||||
  GitHub build scripts are CC0. While we could add a header to each file,
 | 
					 | 
				
			||||||
  it's unclear if it will break actions or issue templates in some way.
 | 
					 | 
				
			||||||
Copyright: Jonathan Coates <git@squiddev.cc>
 | 
					 | 
				
			||||||
License: CC0-1.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files:
 | 
					 | 
				
			||||||
  gradle/wrapper/*
 | 
					 | 
				
			||||||
  gradlew
 | 
					 | 
				
			||||||
  gradlew.bat
 | 
					 | 
				
			||||||
Copyright: Gradle Inc
 | 
					 | 
				
			||||||
License: Apache-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Files: projects/core/src/test/resources/test-rom/data/json-parsing/*
 | 
					 | 
				
			||||||
Copyright: 2016 Nicolas Seriot
 | 
					 | 
				
			||||||
License: MIT
 | 
					 | 
				
			||||||
@@ -22,16 +22,15 @@ If you have a bug, suggestion, or other feedback, the best thing to do is [file
 | 
				
			|||||||
use the issue templates - they provide a useful hint on what information to provide.
 | 
					use the issue templates - they provide a useful hint on what information to provide.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Translations
 | 
					## Translations
 | 
				
			||||||
Translations are managed through [Weblate], an online interface for managing language strings. This is synced
 | 
					Translations are managed through [CrowdIn], an online interface for managing language strings.
 | 
				
			||||||
automatically with GitHub, so please don't submit PRs adding/changing translations!
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Setting up a development environment
 | 
					## Setting up a development environment
 | 
				
			||||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
 | 
					In order to develop CC: Tweaked, you'll need to download the source code and then run it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - Make sure you've got the following software installed:
 | 
					 - Make sure you've got the following software installed:
 | 
				
			||||||
   - Java Development Kit (JDK) installed. This can be downloaded from [Adoptium].
 | 
					   - Java Development Kit 21 (JDK). This can be downloaded from [Adoptium].
 | 
				
			||||||
   - [Git](https://git-scm.com/).
 | 
					   - [Git](https://git-scm.com/).
 | 
				
			||||||
   - If you want to work on documentation, [NodeJS][node].
 | 
					   - [NodeJS 20 or later][node].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - Download CC: Tweaked's source code:
 | 
					 - Download CC: Tweaked's source code:
 | 
				
			||||||
   ```
 | 
					   ```
 | 
				
			||||||
@@ -49,9 +48,12 @@ If you want to run CC:T in a normal Minecraft instance, run `./gradlew assemble`
 | 
				
			|||||||
`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
 | 
					`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Developing CC: Tweaked
 | 
					## Developing CC: Tweaked
 | 
				
			||||||
Before making any major changes to CC: Tweaked, I'd recommend you have a read of the [the architecture
 | 
					Before making any major changes to CC: Tweaked, I'd recommend starting opening an issue or starting a discussion on
 | 
				
			||||||
document][architecture] first. While it's not a comprehensive document, it gives a good hint of where you should start
 | 
					GitHub first. It's often helpful to discuss features before spending time developing them!
 | 
				
			||||||
looking to make your changes. As always, if you're not sure, [do ask the community][community]!
 | 
					
 | 
				
			||||||
 | 
					Once you're ready to start programming, have a read of the [the architecture document][architecture] first. While it's
 | 
				
			||||||
 | 
					not a comprehensive document, it gives a good hint of where you should start looking to make your changes. As always, if
 | 
				
			||||||
 | 
					you're not sure, [do ask the community][community]!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Testing
 | 
					### Testing
 | 
				
			||||||
When making larger changes, it may be useful to write a test to make sure your code works as expected.
 | 
					When making larger changes, it may be useful to write a test to make sure your code works as expected.
 | 
				
			||||||
@@ -86,8 +88,8 @@ You'll first need to [set up a development environment as above](#setting-up-a-d
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
 | 
					Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
 | 
				
			||||||
writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
 | 
					writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
 | 
				
			||||||
documentation, you can instead run `./gradlew docWebsite -t`, which will rebuild documentation every time you change a
 | 
					documentation, you can instead run `./gradlew :web:assemble -x :web:compileTeaVM -t`, which will rebuild documentation
 | 
				
			||||||
file.
 | 
					every time you change a file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
 | 
					Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
 | 
				
			||||||
as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
 | 
					as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
 | 
				
			||||||
@@ -99,12 +101,12 @@ about how you can build on that until you've covered everything!
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
 | 
					[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
 | 
				
			||||||
[community]: README.md#community "Get in touch with the community."
 | 
					[community]: README.md#community "Get in touch with the community."
 | 
				
			||||||
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
 | 
					[Adoptium]: https://adoptium.net/temurin/releases?version=21 "Download OpenJDK 21"
 | 
				
			||||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
 | 
					[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
 | 
				
			||||||
[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance"
 | 
					 | 
				
			||||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
 | 
					[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
 | 
				
			||||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
 | 
					[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
 | 
				
			||||||
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
 | 
					[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
 | 
				
			||||||
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
 | 
					[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
 | 
				
			||||||
[node]: https://nodejs.org/en/ "Node.js"
 | 
					[node]: https://nodejs.org/en/ "Node.js"
 | 
				
			||||||
[architecture]: projects/ARCHITECTURE.md
 | 
					[architecture]: projects/ARCHITECTURE.md
 | 
				
			||||||
 | 
					[Crowdin]: https://crowdin.com/project/cc-tweaked/
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
								
							@@ -11,14 +11,13 @@ SPDX-License-Identifier: MPL-2.0
 | 
				
			|||||||
</picture>
 | 
					</picture>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
 | 
					[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
 | 
				
			||||||
[][CurseForge]
 | 
					 | 
				
			||||||
[][Modrinth]
 | 
					[][Modrinth]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
 | 
					CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
 | 
				
			||||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
 | 
					much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
 | 
				
			||||||
new features.
 | 
					new features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
 | 
					CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Contributing
 | 
					## Contributing
 | 
				
			||||||
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
 | 
					Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
 | 
				
			||||||
@@ -26,8 +25,9 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Community
 | 
					## Community
 | 
				
			||||||
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
 | 
					If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
 | 
				
			||||||
ComputerCraft, do check out our [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
 | 
					ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
 | 
				
			||||||
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
 | 
					albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
 | 
				
			||||||
 | 
					desktop client, or online using [KiwiIRC].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
 | 
					We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,7 +39,7 @@ on is present.
 | 
				
			|||||||
```groovy
 | 
					```groovy
 | 
				
			||||||
repositories {
 | 
					repositories {
 | 
				
			||||||
  maven {
 | 
					  maven {
 | 
				
			||||||
    url "https://squiddev.cc/maven/"
 | 
					    url "https://maven.squiddev.cc"
 | 
				
			||||||
    content {
 | 
					    content {
 | 
				
			||||||
      includeGroup("cc.tweaked")
 | 
					      includeGroup("cc.tweaked")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -61,19 +61,6 @@ dependencies {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When using ForgeGradle, you may also need to add the following:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```groovy
 | 
					 | 
				
			||||||
minecraft {
 | 
					 | 
				
			||||||
    runs {
 | 
					 | 
				
			||||||
        configureEach {
 | 
					 | 
				
			||||||
            property 'mixin.env.remapRefMap', 'true'
 | 
					 | 
				
			||||||
            property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
 | 
					You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
 | 
				
			||||||
subject to change at any point. If you depend on functionality outside the API (or need to mixin to CC:T), please file
 | 
					subject to change at any point. If you depend on functionality outside the API (or need to mixin to CC:T), please file
 | 
				
			||||||
an issue to let me know!
 | 
					an issue to let me know!
 | 
				
			||||||
@@ -82,10 +69,9 @@ We bundle the API sources with the jar, so documentation should be easily viewab
 | 
				
			|||||||
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
 | 
					the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
					[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
				
			||||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
 | 
					 | 
				
			||||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
 | 
					[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
 | 
				
			||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
					[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
				
			||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
 | 
					[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
 | 
				
			||||||
[forum]: https://forums.computercraft.cc/
 | 
					 | 
				
			||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
					[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
				
			||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
 | 
					[EsperNet]: https://www.esper.net/
 | 
				
			||||||
 | 
					[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										100
									
								
								REUSE.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								REUSE.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
				
			|||||||
 | 
					# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					version = 1
 | 
				
			||||||
 | 
					SPDX-PackageName = "CC: Tweaked"
 | 
				
			||||||
 | 
					SPDX-PackageSupplier = "Jonathan Coates <git@squiddev.cc>"
 | 
				
			||||||
 | 
					SPDX-PackageDownloadLocation = "https://github.com/cc-tweaked/cc-tweaked"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "The CC: Tweaked Developers"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "CC0-1.0"
 | 
				
			||||||
 | 
					path = [
 | 
				
			||||||
 | 
					    # Generated/data files are CC0.
 | 
				
			||||||
 | 
					    "gradle/gradle-daemon-jvm.properties",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/sounds.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg",
 | 
				
			||||||
 | 
					    "projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/**",
 | 
				
			||||||
 | 
					    "projects/common/src/testMod/resources/data/cctest/structures/**",
 | 
				
			||||||
 | 
					    "projects/*/src/generated/**",
 | 
				
			||||||
 | 
					    "projects/web/src/htmlTransform/export/index.json",
 | 
				
			||||||
 | 
					    "projects/web/src/htmlTransform/export/items/minecraft/**",
 | 
				
			||||||
 | 
					    # GitHub build scripts are CC0. While we could add a header to each file,
 | 
				
			||||||
 | 
					    # it's unclear if it will break actions or issue templates in some way.
 | 
				
			||||||
 | 
					    ".github/**",
 | 
				
			||||||
 | 
					    # Example mod is CC0.
 | 
				
			||||||
 | 
					    "projects/*/src/examples/**"
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					# Several assets where it's inconvenient to create a .license file.
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "The CC: Tweaked Developers"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "MPL-2.0"
 | 
				
			||||||
 | 
					path = [
 | 
				
			||||||
 | 
					    "doc/images/**",
 | 
				
			||||||
 | 
					    "package.json",
 | 
				
			||||||
 | 
					    "package-lock.json",
 | 
				
			||||||
 | 
					    "projects/*/src/*/resources/*.mixins.json",
 | 
				
			||||||
 | 
					    "projects/fabric/src/*/resources/fabric.mod.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json",
 | 
				
			||||||
 | 
					    "projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json",
 | 
				
			||||||
 | 
					    "projects/common/src/testMod/resources/pack.mcmeta",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt",
 | 
				
			||||||
 | 
					    "projects/web/src/frontend/mount/.settings",
 | 
				
			||||||
 | 
					    "projects/web/src/frontend/mount/example.nfp",
 | 
				
			||||||
 | 
					    "projects/web/src/frontend/mount/example.nft",
 | 
				
			||||||
 | 
					    "projects/web/src/frontend/mount/expr_template.lua",
 | 
				
			||||||
 | 
					    "projects/web/tsconfig.json",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					# Bulk-license original assets as CCPL.
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "2011 Daniel Ratcliffe"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "LicenseRef-CCPL"
 | 
				
			||||||
 | 
					path = [
 | 
				
			||||||
 | 
					    "doc/logo.png",
 | 
				
			||||||
 | 
					    "doc/logo-darkmode.png",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/models/**",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/textures/**",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/pack.mcmeta",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/pack.png",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/assets/computercraft/textures/gui/term_font.png",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/help/**",
 | 
				
			||||||
 | 
					    "projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/**",
 | 
				
			||||||
 | 
					    "projects/web/src/htmlTransform/export/items/computercraft/**",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					# Community-contributed language files
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "LicenseRef-CCPL"
 | 
				
			||||||
 | 
					path = [
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/ko_kr.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/pl_pl.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/pt_br.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json",
 | 
				
			||||||
 | 
					    "projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					# Community-contributed language files
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "MPL-2.0"
 | 
				
			||||||
 | 
					path = "projects/common/src/main/resources/assets/computercraft/lang/**"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					path = ["gradle/wrapper/**"]
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "Gradle Inc"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "Apache-2.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[annotations]]
 | 
				
			||||||
 | 
					path = "projects/core/src/test/resources/test-rom/data/json-parsing/**"
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText = "2016 Nicolas Seriot"
 | 
				
			||||||
 | 
					SPDX-License-Identifier = "MIT"
 | 
				
			||||||
@@ -4,14 +4,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import cc.tweaked.gradle.JUnitExt
 | 
					import cc.tweaked.gradle.JUnitExt
 | 
				
			||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
 | 
					import net.fabricmc.loom.api.LoomGradleExtensionAPI
 | 
				
			||||||
import net.fabricmc.loom.util.gradle.SourceSetHelper
 | 
					import org.jetbrains.gradle.ext.*
 | 
				
			||||||
import org.jetbrains.gradle.ext.compiler
 | 
					import org.jetbrains.gradle.ext.Application
 | 
				
			||||||
import org.jetbrains.gradle.ext.runConfigurations
 | 
					 | 
				
			||||||
import org.jetbrains.gradle.ext.settings
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    publishing
 | 
					    publishing
 | 
				
			||||||
    alias(libs.plugins.taskTree)
 | 
					 | 
				
			||||||
    alias(libs.plugins.githubRelease)
 | 
					    alias(libs.plugins.githubRelease)
 | 
				
			||||||
    alias(libs.plugins.gradleVersions)
 | 
					    alias(libs.plugins.gradleVersions)
 | 
				
			||||||
    alias(libs.plugins.versionCatalogUpdate)
 | 
					    alias(libs.plugins.versionCatalogUpdate)
 | 
				
			||||||
@@ -25,21 +22,19 @@ val mcVersion: String by extra
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
githubRelease {
 | 
					githubRelease {
 | 
				
			||||||
    token(findProperty("githubApiKey") as String? ?: "")
 | 
					    token(findProperty("githubApiKey") as String? ?: "")
 | 
				
			||||||
    owner.set("cc-tweaked")
 | 
					    owner = "cc-tweaked"
 | 
				
			||||||
    repo.set("CC-Tweaked")
 | 
					    repo = "CC-Tweaked"
 | 
				
			||||||
    targetCommitish.set(cct.gitBranch)
 | 
					    targetCommitish = cct.gitBranch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tagName.set("v$mcVersion-$modVersion")
 | 
					    tagName = "v$mcVersion-$modVersion"
 | 
				
			||||||
    releaseName.set("[$mcVersion] $modVersion")
 | 
					    releaseName = "[$mcVersion] $modVersion"
 | 
				
			||||||
    body.set(
 | 
					    body = provider {
 | 
				
			||||||
        provider {
 | 
					        "## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
 | 
				
			||||||
            "## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
 | 
					            .readLines()
 | 
				
			||||||
                .readLines()
 | 
					            .takeWhile { it != "Type \"help changelog\" to see the full version history." }
 | 
				
			||||||
                .takeWhile { it != "Type \"help changelog\" to see the full version history." }
 | 
					            .joinToString("\n").trim()
 | 
				
			||||||
                .joinToString("\n").trim()
 | 
					    }
 | 
				
			||||||
        },
 | 
					    prerelease = isUnstable
 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    prerelease.set(isUnstable)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.publish { dependsOn(tasks.githubRelease) }
 | 
					tasks.publish { dependsOn(tasks.githubRelease) }
 | 
				
			||||||
@@ -73,7 +68,7 @@ idea.project.settings.runConfigurations {
 | 
				
			|||||||
        val fabricProject = evaluationDependsOn(":fabric")
 | 
					        val fabricProject = evaluationDependsOn(":fabric")
 | 
				
			||||||
        val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
 | 
					        val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
 | 
				
			||||||
            .joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
 | 
					            .joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
 | 
				
			||||||
                SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
 | 
					                modSettings.modFiles.joinToString(File.pathSeparator) { it.absolutePath }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
 | 
					        vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
 | 
				
			||||||
@@ -86,6 +81,19 @@ idea.project.settings.runConfigurations {
 | 
				
			|||||||
        moduleName = "${idea.project.name}.forge.test"
 | 
					        moduleName = "${idea.project.name}.forge.test"
 | 
				
			||||||
        packageName = ""
 | 
					        packageName = ""
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    register<Application>("Standalone") {
 | 
				
			||||||
 | 
					        moduleName = "${idea.project.name}.standalone.main"
 | 
				
			||||||
 | 
					        mainClass = "cc.tweaked.standalone.Main"
 | 
				
			||||||
 | 
					        programParameters = "--resources=projects/core/src/main/resources --term=80x30 --allow-local-domains"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Build with the IntelliJ, rather than through Gradle. This may require setting the "Compiler Output" option in
 | 
				
			||||||
 | 
					// "Project Structure".
 | 
				
			||||||
 | 
					idea.project.settings.delegateActions {
 | 
				
			||||||
 | 
					    delegateBuildRunToGradle = false
 | 
				
			||||||
 | 
					    testRunner = ActionDelegationConfig.TestRunner.PLATFORM
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
idea.project.settings.compiler.javac {
 | 
					idea.project.settings.compiler.javac {
 | 
				
			||||||
@@ -105,8 +113,12 @@ idea.project.settings.compiler.javac {
 | 
				
			|||||||
        .toMap()
 | 
					        .toMap()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
versionCatalogUpdate {
 | 
					repositories() {
 | 
				
			||||||
    sortByKey.set(false)
 | 
					    mavenCentral()
 | 
				
			||||||
    pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
 | 
					}
 | 
				
			||||||
    keep { keepUnusedLibraries.set(true) }
 | 
					
 | 
				
			||||||
 | 
					versionCatalogUpdate {
 | 
				
			||||||
 | 
					    sortByKey = false
 | 
				
			||||||
 | 
					    pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
 | 
				
			||||||
 | 
					    keep { keepUnusedVersions = true }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,18 +14,10 @@ repositories {
 | 
				
			|||||||
    mavenCentral()
 | 
					    mavenCentral()
 | 
				
			||||||
    gradlePluginPortal()
 | 
					    gradlePluginPortal()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    maven("https://maven.minecraftforge.net") {
 | 
					    maven("https://maven.neoforged.net") {
 | 
				
			||||||
        name = "Forge"
 | 
					        name = "NeoForge"
 | 
				
			||||||
        content {
 | 
					        content {
 | 
				
			||||||
            includeGroup("net.minecraftforge")
 | 
					            includeGroup("net.neoforged")
 | 
				
			||||||
            includeGroup("net.minecraftforge.gradle")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    maven("https://maven.parchmentmc.org") {
 | 
					 | 
				
			||||||
        name = "Librarian"
 | 
					 | 
				
			||||||
        content {
 | 
					 | 
				
			||||||
            includeGroupByRegex("^org\\.parchmentmc.*")
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -33,10 +25,11 @@ repositories {
 | 
				
			|||||||
        name = "Fabric"
 | 
					        name = "Fabric"
 | 
				
			||||||
        content {
 | 
					        content {
 | 
				
			||||||
            includeGroup("net.fabricmc")
 | 
					            includeGroup("net.fabricmc")
 | 
				
			||||||
 | 
					            includeGroup("net.fabricmc.unpick")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    maven("https://squiddev.cc/maven") {
 | 
					    maven("https://maven.squiddev.cc") {
 | 
				
			||||||
        name = "SquidDev"
 | 
					        name = "SquidDev"
 | 
				
			||||||
        content {
 | 
					        content {
 | 
				
			||||||
            includeGroup("cc.tweaked.vanilla-extract")
 | 
					            includeGroup("cc.tweaked.vanilla-extract")
 | 
				
			||||||
@@ -49,12 +42,10 @@ dependencies {
 | 
				
			|||||||
    implementation(libs.kotlin.plugin)
 | 
					    implementation(libs.kotlin.plugin)
 | 
				
			||||||
    implementation(libs.spotless)
 | 
					    implementation(libs.spotless)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation(libs.curseForgeGradle)
 | 
					 | 
				
			||||||
    implementation(libs.fabric.loom)
 | 
					    implementation(libs.fabric.loom)
 | 
				
			||||||
    implementation(libs.forgeGradle)
 | 
					 | 
				
			||||||
    implementation(libs.ideaExt)
 | 
					    implementation(libs.ideaExt)
 | 
				
			||||||
    implementation(libs.librarian)
 | 
					 | 
				
			||||||
    implementation(libs.minotaur)
 | 
					    implementation(libs.minotaur)
 | 
				
			||||||
 | 
					    implementation(libs.modDevGradle)
 | 
				
			||||||
    implementation(libs.vanillaExtract)
 | 
					    implementation(libs.vanillaExtract)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,7 +69,7 @@ gradlePlugin {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
versionCatalogUpdate {
 | 
					versionCatalogUpdate {
 | 
				
			||||||
    sortByKey.set(false)
 | 
					    sortByKey = false
 | 
				
			||||||
    keep { keepUnusedLibraries.set(true) }
 | 
					    keep { keepUnusedVersions = true }
 | 
				
			||||||
    catalogFile.set(file("../gradle/libs.versions.toml"))
 | 
					    catalogFile = file("../gradle/libs.versions.toml")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** Default configuration for Fabric projects. */
 | 
					/** Default configuration for Fabric projects. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cc.tweaked.gradle.CCTweakedExtension
 | 
					import cc.tweaked.gradle.*
 | 
				
			||||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.IdeaRunConfigurations
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.MinecraftConfigurations
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    `java-library`
 | 
					    `java-library`
 | 
				
			||||||
@@ -30,7 +27,7 @@ repositories {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
loom {
 | 
					loom {
 | 
				
			||||||
    splitEnvironmentSourceSets()
 | 
					    splitEnvironmentSourceSets()
 | 
				
			||||||
    splitModDependencies.set(true)
 | 
					    splitModDependencies = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MinecraftConfigurations.setup(project)
 | 
					MinecraftConfigurations.setup(project)
 | 
				
			||||||
@@ -67,3 +64,19 @@ dependencies {
 | 
				
			|||||||
tasks.ideaSyncTask {
 | 
					tasks.ideaSyncTask {
 | 
				
			||||||
    doLast { IdeaRunConfigurations(project).patch() }
 | 
					    doLast { IdeaRunConfigurations(project).patch() }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
 | 
				
			||||||
 | 
					    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
				
			||||||
 | 
					    // Minecraft depends on lwjgl, but Fabric forces it to a more recent version
 | 
				
			||||||
 | 
					    for (lwjgl in listOf(
 | 
				
			||||||
 | 
					        "lwjgl",
 | 
				
			||||||
 | 
					        "lwjgl-glfw",
 | 
				
			||||||
 | 
					        "lwjgl-jemalloc",
 | 
				
			||||||
 | 
					        "lwjgl-openal",
 | 
				
			||||||
 | 
					        "lwjgl-opengl",
 | 
				
			||||||
 | 
					        "lwjgl-stb",
 | 
				
			||||||
 | 
					        "lwjgl-tinyfd",
 | 
				
			||||||
 | 
					    )) {
 | 
				
			||||||
 | 
					        override("org.lwjgl", lwjgl, "3.3.2")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,25 +6,25 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import cc.tweaked.gradle.CCTweakedExtension
 | 
					import cc.tweaked.gradle.CCTweakedExtension
 | 
				
			||||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
					import cc.tweaked.gradle.CCTweakedPlugin
 | 
				
			||||||
import cc.tweaked.gradle.IdeaRunConfigurations
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.MinecraftConfigurations
 | 
					import cc.tweaked.gradle.MinecraftConfigurations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    id("net.minecraftforge.gradle")
 | 
					 | 
				
			||||||
    // We must apply java-convention after Forge, as we need the fg extension to be present.
 | 
					 | 
				
			||||||
    id("cc-tweaked.java-convention")
 | 
					    id("cc-tweaked.java-convention")
 | 
				
			||||||
    id("org.parchmentmc.librarian.forgegradle")
 | 
					    id("net.neoforged.moddev.legacyforge")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins.apply(CCTweakedPlugin::class.java)
 | 
					plugins.apply(CCTweakedPlugin::class.java)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val mcVersion: String by extra
 | 
					val mcVersion: String by extra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
minecraft {
 | 
					legacyForge {
 | 
				
			||||||
    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
					    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
				
			||||||
    mappings("parchment", "${libs.findVersion("parchmentMc").get()}-${libs.findVersion("parchment").get()}-$mcVersion")
 | 
					    version = "$mcVersion-${libs.findVersion("forge").get()}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    accessTransformer(project(":forge").file("src/main/resources/META-INF/accesstransformer.cfg"))
 | 
					    parchment {
 | 
				
			||||||
 | 
					        minecraftVersion = libs.findVersion("parchmentMc").get().toString()
 | 
				
			||||||
 | 
					        mappingsVersion = libs.findVersion("parchment").get().toString()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MinecraftConfigurations.setup(project)
 | 
					MinecraftConfigurations.setup(project)
 | 
				
			||||||
@@ -32,13 +32,3 @@ MinecraftConfigurations.setup(project)
 | 
				
			|||||||
extensions.configure(CCTweakedExtension::class.java) {
 | 
					extensions.configure(CCTweakedExtension::class.java) {
 | 
				
			||||||
    linters(minecraft = true, loader = "forge")
 | 
					    linters(minecraft = true, loader = "forge")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
dependencies {
 | 
					 | 
				
			||||||
    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
					 | 
				
			||||||
    "minecraft"("net.minecraftforge:forge:$mcVersion-${libs.findVersion("forge").get()}")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks.configureEach {
 | 
					 | 
				
			||||||
    // genIntellijRuns isn't registered until much later, so we need this silly hijinks.
 | 
					 | 
				
			||||||
    if (name == "genIntellijRuns") doLast { IdeaRunConfigurations(project).patch() }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,8 @@ plugins {
 | 
				
			|||||||
    checkstyle
 | 
					    checkstyle
 | 
				
			||||||
    id("com.diffplug.spotless")
 | 
					    id("com.diffplug.spotless")
 | 
				
			||||||
    id("net.ltgt.errorprone")
 | 
					    id("net.ltgt.errorprone")
 | 
				
			||||||
 | 
					    // Required for cross-project dependencies in Fabric
 | 
				
			||||||
 | 
					    id("net.fabricmc.fabric-loom-companion")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val modVersion: String by extra
 | 
					val modVersion: String by extra
 | 
				
			||||||
@@ -28,9 +30,9 @@ version = modVersion
 | 
				
			|||||||
base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
 | 
					base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    toolchain {
 | 
					    toolchain { languageVersion = CCTweakedPlugin.JDK_VERSION }
 | 
				
			||||||
        languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
 | 
					    sourceCompatibility = CCTweakedPlugin.JAVA_VERSION
 | 
				
			||||||
    }
 | 
					    targetCompatibility = CCTweakedPlugin.JAVA_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    withSourcesJar()
 | 
					    withSourcesJar()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -38,22 +40,16 @@ java {
 | 
				
			|||||||
repositories {
 | 
					repositories {
 | 
				
			||||||
    mavenCentral()
 | 
					    mavenCentral()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val mainMaven = maven("https://squiddev.cc/maven") {
 | 
					    val mainMaven = maven("https://maven.squiddev.cc/mirror") {
 | 
				
			||||||
        name = "SquidDev"
 | 
					        name = "SquidDev"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exclusiveContent {
 | 
					    exclusiveContent {
 | 
				
			||||||
        forRepositories(mainMaven)
 | 
					        forRepositories(mainMaven)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Include the ForgeGradle repository if present. This requires that ForgeGradle is already present, which we
 | 
					 | 
				
			||||||
        // enforce in our Forge overlay.
 | 
					 | 
				
			||||||
        val fg =
 | 
					 | 
				
			||||||
            project.extensions.findByType(net.minecraftforge.gradle.userdev.DependencyManagementExtension::class.java)
 | 
					 | 
				
			||||||
        if (fg != null) forRepositories(fg.repository)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        filter {
 | 
					        filter {
 | 
				
			||||||
            includeGroup("cc.tweaked")
 | 
					            includeGroup("cc.tweaked")
 | 
				
			||||||
            // Things we mirror
 | 
					            // Things we mirror
 | 
				
			||||||
 | 
					            includeGroup("com.simibubi.create")
 | 
				
			||||||
            includeGroup("commoble.morered")
 | 
					            includeGroup("commoble.morered")
 | 
				
			||||||
            includeGroup("dev.architectury")
 | 
					            includeGroup("dev.architectury")
 | 
				
			||||||
            includeGroup("dev.emi")
 | 
					            includeGroup("dev.emi")
 | 
				
			||||||
@@ -85,20 +81,31 @@ dependencies {
 | 
				
			|||||||
// Configure default JavaCompile tasks with our arguments.
 | 
					// Configure default JavaCompile tasks with our arguments.
 | 
				
			||||||
sourceSets.all {
 | 
					sourceSets.all {
 | 
				
			||||||
    tasks.named(compileJavaTaskName, JavaCompile::class.java) {
 | 
					    tasks.named(compileJavaTaskName, JavaCompile::class.java) {
 | 
				
			||||||
        // Processing just gives us "No processor claimed any of these annotations", so skip that!
 | 
					        // Explicitly set release, as that limits the APIs we can use to the right version of Java.
 | 
				
			||||||
        options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
 | 
					        options.release = CCTweakedPlugin.JAVA_TARGET.asInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        options.compilerArgs.addAll(
 | 
				
			||||||
 | 
					            listOf(
 | 
				
			||||||
 | 
					                "-Xlint",
 | 
				
			||||||
 | 
					                // Processing just gives us "No processor claimed any of these annotations", so skip that!
 | 
				
			||||||
 | 
					                "-Xlint:-processing",
 | 
				
			||||||
 | 
					                // We violate this pattern too often for it to be a helpful warning. Something to improve one day!
 | 
				
			||||||
 | 
					                "-Xlint:-this-escape",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        options.errorprone {
 | 
					        options.errorprone {
 | 
				
			||||||
            check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
 | 
					            check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
 | 
				
			||||||
            check("InvalidParam", CheckSeverity.OFF) // Broken by records.
 | 
					 | 
				
			||||||
            check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
 | 
					            check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
 | 
				
			||||||
            // Too many false positives right now. Maybe we need an indirection for it later on.
 | 
					            // Too many false positives right now. Maybe we need an indirection for it later on.
 | 
				
			||||||
 | 
					            check("AssignmentExpression", CheckSeverity.OFF) // I'm a bad person.
 | 
				
			||||||
            check("ReferenceEquality", CheckSeverity.OFF)
 | 
					            check("ReferenceEquality", CheckSeverity.OFF)
 | 
				
			||||||
            check("UnusedVariable", CheckSeverity.OFF) // Too many false positives with records.
 | 
					            check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap.
 | 
				
			||||||
            check("OperatorPrecedence", CheckSeverity.OFF) // For now.
 | 
					            check("OperatorPrecedence", CheckSeverity.OFF) // For now.
 | 
				
			||||||
            check("AlreadyChecked", CheckSeverity.OFF) // Seems to be broken?
 | 
					 | 
				
			||||||
            check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
 | 
					            check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
 | 
				
			||||||
            check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
 | 
					            check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
 | 
				
			||||||
 | 
					            check("InvalidInlineTag", CheckSeverity.OFF) // Triggered by @snippet. Can be removed on Java 21.
 | 
				
			||||||
 | 
					            option("UnusedMethod:ExemptingMethodAnnotations", "dan200.computercraft.api.lua.LuaFunction")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            check("NullAway", CheckSeverity.ERROR)
 | 
					            check("NullAway", CheckSeverity.ERROR)
 | 
				
			||||||
            option(
 | 
					            option(
 | 
				
			||||||
@@ -121,7 +128,6 @@ tasks.compileTestJava {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks.withType(JavaCompile::class.java).configureEach {
 | 
					tasks.withType(JavaCompile::class.java).configureEach {
 | 
				
			||||||
    options.encoding = "UTF-8"
 | 
					    options.encoding = "UTF-8"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -134,8 +140,8 @@ tasks.processResources {
 | 
				
			|||||||
tasks.withType(AbstractArchiveTask::class.java).configureEach {
 | 
					tasks.withType(AbstractArchiveTask::class.java).configureEach {
 | 
				
			||||||
    isPreserveFileTimestamps = false
 | 
					    isPreserveFileTimestamps = false
 | 
				
			||||||
    isReproducibleFileOrder = true
 | 
					    isReproducibleFileOrder = true
 | 
				
			||||||
    dirMode = Integer.valueOf("755", 8)
 | 
					    filePermissions {}
 | 
				
			||||||
    fileMode = Integer.valueOf("664", 8)
 | 
					    dirPermissions {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.jar {
 | 
					tasks.jar {
 | 
				
			||||||
@@ -155,7 +161,7 @@ tasks.javadoc {
 | 
				
			|||||||
    options {
 | 
					    options {
 | 
				
			||||||
        val stdOptions = this as StandardJavadocDocletOptions
 | 
					        val stdOptions = this as StandardJavadocDocletOptions
 | 
				
			||||||
        stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
 | 
					        stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
 | 
				
			||||||
        stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
 | 
					        stdOptions.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,8 +175,8 @@ tasks.test {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.withType(JacocoReport::class.java).configureEach {
 | 
					tasks.withType(JacocoReport::class.java).configureEach {
 | 
				
			||||||
    reports.xml.required.set(true)
 | 
					    reports.xml.required = true
 | 
				
			||||||
    reports.html.required.set(true)
 | 
					    reports.html.required = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
project.plugins.withType(CCTweakedPlugin::class.java) {
 | 
					project.plugins.withType(CCTweakedPlugin::class.java) {
 | 
				
			||||||
@@ -194,30 +200,23 @@ spotless {
 | 
				
			|||||||
    fun FormatExtension.defaults() {
 | 
					    fun FormatExtension.defaults() {
 | 
				
			||||||
        endWithNewline()
 | 
					        endWithNewline()
 | 
				
			||||||
        trimTrailingWhitespace()
 | 
					        trimTrailingWhitespace()
 | 
				
			||||||
        indentWithSpaces(4)
 | 
					        leadingTabsToSpaces(4)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    java {
 | 
					    java {
 | 
				
			||||||
        defaults()
 | 
					        defaults()
 | 
				
			||||||
 | 
					        importOrder("", "javax|java", "\\#")
 | 
				
			||||||
        removeUnusedImports()
 | 
					        removeUnusedImports()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val ktlintConfig = mapOf(
 | 
					 | 
				
			||||||
        "ktlint_standard_no-wildcard-imports" to "disabled",
 | 
					 | 
				
			||||||
        "ktlint_standard_class-naming" to "disabled",
 | 
					 | 
				
			||||||
        "ktlint_standard_function-naming" to "disabled",
 | 
					 | 
				
			||||||
        "ij_kotlin_allow_trailing_comma" to "true",
 | 
					 | 
				
			||||||
        "ij_kotlin_allow_trailing_comma_on_call_site" to "true",
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    kotlinGradle {
 | 
					    kotlinGradle {
 | 
				
			||||||
        defaults()
 | 
					        defaults()
 | 
				
			||||||
        ktlint().editorConfigOverride(ktlintConfig)
 | 
					        ktlint()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    kotlin {
 | 
					    kotlin {
 | 
				
			||||||
        defaults()
 | 
					        defaults()
 | 
				
			||||||
        ktlint().editorConfigOverride(ktlintConfig)
 | 
					        ktlint()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -226,6 +225,5 @@ idea.module {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
 | 
					    // Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
 | 
				
			||||||
    // This is required for Loom, and we patch Forge's run configurations to work there.
 | 
					    // This is required for Loom, and we patch Forge's run configurations to work there.
 | 
				
			||||||
    // TODO: Submit a patch to Forge to support ProjectRootManager.
 | 
					 | 
				
			||||||
    inheritOutputDirs = true
 | 
					    inheritOutputDirs = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
					 | 
				
			||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
plugins {
 | 
					 | 
				
			||||||
    kotlin("jvm")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
kotlin {
 | 
					 | 
				
			||||||
    jvmToolchain {
 | 
					 | 
				
			||||||
        languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks.withType(KotlinCompile::class.java).configureEach {
 | 
					 | 
				
			||||||
    // So technically we shouldn't need to do this as the toolchain sets it above. However, the option only appears
 | 
					 | 
				
			||||||
    // to be set when the task executes, so doesn't get picked up by IDEs.
 | 
					 | 
				
			||||||
    kotlinOptions.jvmTarget = when {
 | 
					 | 
				
			||||||
        CCTweakedPlugin.JAVA_VERSION.asInt() > 8 -> CCTweakedPlugin.JAVA_VERSION.toString()
 | 
					 | 
				
			||||||
        else -> "1.${CCTweakedPlugin.JAVA_VERSION.asInt()}"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -2,11 +2,9 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.darkhax.curseforgegradle.TaskPublishCurseForge
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.setProvider
 | 
					import cc.tweaked.gradle.setProvider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    id("net.darkhax.curseforgegradle")
 | 
					 | 
				
			||||||
    id("com.modrinth.minotaur")
 | 
					    id("com.modrinth.minotaur")
 | 
				
			||||||
    id("cc-tweaked.publishing")
 | 
					    id("cc-tweaked.publishing")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -25,34 +23,17 @@ val isUnstable = project.properties["isUnstable"] == "true"
 | 
				
			|||||||
val modVersion: String by extra
 | 
					val modVersion: String by extra
 | 
				
			||||||
val mcVersion: String by extra
 | 
					val mcVersion: String by extra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
 | 
					 | 
				
			||||||
    group = PublishingPlugin.PUBLISH_TASK_GROUP
 | 
					 | 
				
			||||||
    description = "Upload artifacts to CurseForge"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    apiToken = findProperty("curseForgeApiKey") ?: ""
 | 
					 | 
				
			||||||
    enabled = apiToken != ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val mainFile = upload("282001", modPublishing.output)
 | 
					 | 
				
			||||||
    mainFile.changelog =
 | 
					 | 
				
			||||||
        "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
 | 
					 | 
				
			||||||
    mainFile.changelogType = "markdown"
 | 
					 | 
				
			||||||
    mainFile.releaseType = if (isUnstable) "alpha" else "release"
 | 
					 | 
				
			||||||
    mainFile.gameVersions.add(mcVersion)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
tasks.publish { dependsOn(publishCurseForge) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
modrinth {
 | 
					modrinth {
 | 
				
			||||||
    token.set(findProperty("modrinthApiKey") as String? ?: "")
 | 
					    token = findProperty("modrinthApiKey") as String? ?: ""
 | 
				
			||||||
    projectId.set("gu7yAYhd")
 | 
					    projectId = "gu7yAYhd"
 | 
				
			||||||
    versionNumber.set(modVersion)
 | 
					    versionNumber = modVersion
 | 
				
			||||||
    versionName.set(modVersion)
 | 
					    versionName = modVersion
 | 
				
			||||||
    versionType.set(if (isUnstable) "alpha" else "release")
 | 
					    versionType = if (isUnstable) "alpha" else "release"
 | 
				
			||||||
    uploadFile.setProvider(modPublishing.output)
 | 
					    uploadFile.setProvider(modPublishing.output)
 | 
				
			||||||
    gameVersions.add(mcVersion)
 | 
					    gameVersions.add(mcVersion)
 | 
				
			||||||
    changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
 | 
					    changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    syncBodyFrom.set(provider { rootProject.file("doc/mod-page.md").readText() })
 | 
					    syncBodyFrom = provider { rootProject.file("doc/mod-page.md").readText() }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.publish { dependsOn(tasks.modrinth) }
 | 
					tasks.publish { dependsOn(tasks.modrinth) }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,44 +2,35 @@
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cc.tweaked.gradle.clientClasses
 | 
					 | 
				
			||||||
import cc.tweaked.gradle.commonClasses
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Sets up the configurations for writing game tests.
 | 
					 * Sets up the configurations for writing game tests.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
 | 
					 * See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cc.tweaked.gradle.CCTweakedPlugin
 | 
				
			||||||
 | 
					import cc.tweaked.gradle.MinecraftConfigurations
 | 
				
			||||||
 | 
					import cc.tweaked.gradle.clientClasses
 | 
				
			||||||
 | 
					import cc.tweaked.gradle.commonClasses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    id("cc-tweaked.kotlin-convention")
 | 
					    kotlin("jvm")
 | 
				
			||||||
    id("cc-tweaked.java-convention")
 | 
					    id("cc-tweaked.java-convention")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val main = sourceSets["main"]
 | 
					val main = sourceSets["main"]
 | 
				
			||||||
val client = sourceSets["client"]
 | 
					val client = sourceSets["client"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
 | 
					MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.DATAGEN)
 | 
				
			||||||
val testMod by sourceSets.creating {
 | 
					MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.EXAMPLES)
 | 
				
			||||||
    compileClasspath += main.compileClasspath + client.compileClasspath
 | 
					MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.TEST_MOD)
 | 
				
			||||||
    runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
configurations {
 | 
					// Set up generated resources
 | 
				
			||||||
    named(testMod.compileClasspathConfigurationName) {
 | 
					sourceSets.main { resources.srcDir("src/generated/resources") }
 | 
				
			||||||
        shouldResolveConsistentlyWith(compileClasspath.get())
 | 
					sourceSets.named("examples") { resources.srcDir("src/examples/generatedResources") }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    named(testMod.runtimeClasspathConfigurationName) {
 | 
					// Make sure our examples compile.
 | 
				
			||||||
        shouldResolveConsistentlyWith(runtimeClasspath.get())
 | 
					tasks.check { dependsOn(tasks.named("compileExamplesJava")) }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Like the main test configurations, we're safe to depend on source set outputs.
 | 
					 | 
				
			||||||
dependencies {
 | 
					 | 
				
			||||||
    add(testMod.implementationConfigurationName, main.output)
 | 
					 | 
				
			||||||
    add(testMod.implementationConfigurationName, client.output)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
 | 
					// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,3 +53,5 @@ dependencies {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    testImplementation(testFixtures(project))
 | 
					    testImplementation(testFixtures(project))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET
 | 
				
			||||||
@@ -12,25 +12,26 @@ publishing {
 | 
				
			|||||||
        register<MavenPublication>("maven") {
 | 
					        register<MavenPublication>("maven") {
 | 
				
			||||||
            artifactId = base.archivesName.get()
 | 
					            artifactId = base.archivesName.get()
 | 
				
			||||||
            from(components["java"])
 | 
					            from(components["java"])
 | 
				
			||||||
 | 
					            suppressAllPomMetadataWarnings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pom {
 | 
					            pom {
 | 
				
			||||||
                name.set("CC: Tweaked")
 | 
					                name = "CC: Tweaked"
 | 
				
			||||||
                description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
 | 
					                description = "CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft."
 | 
				
			||||||
                url.set("https://github.com/cc-tweaked/CC-Tweaked")
 | 
					                url = "https://github.com/cc-tweaked/CC-Tweaked"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                scm {
 | 
					                scm {
 | 
				
			||||||
                    url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
 | 
					                    url = "https://github.com/cc-tweaked/CC-Tweaked.git"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                issueManagement {
 | 
					                issueManagement {
 | 
				
			||||||
                    system.set("github")
 | 
					                    system = "github"
 | 
				
			||||||
                    url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
 | 
					                    url = "https://github.com/cc-tweaked/CC-Tweaked/issues"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                licenses {
 | 
					                licenses {
 | 
				
			||||||
                    license {
 | 
					                    license {
 | 
				
			||||||
                        name.set("ComputerCraft Public License, Version 1.0")
 | 
					                        name = "ComputerCraft Public License, Version 1.0"
 | 
				
			||||||
                        url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
 | 
					                        url = "https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE"
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -38,7 +39,7 @@ publishing {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    repositories {
 | 
					    repositories {
 | 
				
			||||||
        maven("https://squiddev.cc/maven") {
 | 
					        maven("https://maven.squiddev.cc") {
 | 
				
			||||||
            name = "SquidDev"
 | 
					            name = "SquidDev"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            credentials(PasswordCredentials::class)
 | 
					            credentials(PasswordCredentials::class)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,23 +10,16 @@ import org.gradle.api.GradleException
 | 
				
			|||||||
import org.gradle.api.NamedDomainObjectProvider
 | 
					import org.gradle.api.NamedDomainObjectProvider
 | 
				
			||||||
import org.gradle.api.Project
 | 
					import org.gradle.api.Project
 | 
				
			||||||
import org.gradle.api.Task
 | 
					import org.gradle.api.Task
 | 
				
			||||||
import org.gradle.api.artifacts.Dependency
 | 
					 | 
				
			||||||
import org.gradle.api.attributes.TestSuiteType
 | 
					 | 
				
			||||||
import org.gradle.api.file.FileSystemOperations
 | 
					 | 
				
			||||||
import org.gradle.api.plugins.JavaPluginExtension
 | 
					import org.gradle.api.plugins.JavaPluginExtension
 | 
				
			||||||
import org.gradle.api.provider.ListProperty
 | 
					 | 
				
			||||||
import org.gradle.api.provider.Provider
 | 
					import org.gradle.api.provider.Provider
 | 
				
			||||||
import org.gradle.api.provider.SetProperty
 | 
					import org.gradle.api.provider.SetProperty
 | 
				
			||||||
import org.gradle.api.reporting.ReportingExtension
 | 
					 | 
				
			||||||
import org.gradle.api.tasks.SourceSet
 | 
					import org.gradle.api.tasks.SourceSet
 | 
				
			||||||
import org.gradle.api.tasks.bundling.Jar
 | 
					import org.gradle.api.tasks.bundling.Jar
 | 
				
			||||||
import org.gradle.api.tasks.compile.JavaCompile
 | 
					import org.gradle.api.tasks.compile.JavaCompile
 | 
				
			||||||
import org.gradle.api.tasks.javadoc.Javadoc
 | 
					import org.gradle.api.tasks.javadoc.Javadoc
 | 
				
			||||||
import org.gradle.configurationcache.extensions.capitalized
 | 
					 | 
				
			||||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
 | 
					import org.gradle.language.base.plugins.LifecycleBasePlugin
 | 
				
			||||||
import org.gradle.language.jvm.tasks.ProcessResources
 | 
					import org.gradle.language.jvm.tasks.ProcessResources
 | 
				
			||||||
import org.gradle.process.JavaForkOptions
 | 
					import org.gradle.process.JavaForkOptions
 | 
				
			||||||
import org.gradle.testing.jacoco.plugins.JacocoCoverageReport
 | 
					 | 
				
			||||||
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
 | 
					import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
 | 
				
			||||||
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
 | 
					import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
 | 
				
			||||||
import org.gradle.testing.jacoco.tasks.JacocoReport
 | 
					import org.gradle.testing.jacoco.tasks.JacocoReport
 | 
				
			||||||
@@ -35,57 +28,42 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 | 
				
			|||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
import java.io.IOException
 | 
					import java.io.IOException
 | 
				
			||||||
import java.net.URI
 | 
					import java.net.URI
 | 
				
			||||||
import java.net.URL
 | 
					 | 
				
			||||||
import java.util.regex.Pattern
 | 
					import java.util.regex.Pattern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class CCTweakedExtension(
 | 
					abstract class CCTweakedExtension(private val project: Project) {
 | 
				
			||||||
    private val project: Project,
 | 
					 | 
				
			||||||
    private val fs: FileSystemOperations,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    /** Get the hash of the latest git commit. */
 | 
					    /** Get the hash of the latest git commit. */
 | 
				
			||||||
    val gitHash: Provider<String> = gitProvider(project, "<no git hash>") {
 | 
					    val gitHash: Provider<String> =
 | 
				
			||||||
        ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "HEAD").trim()
 | 
					        gitProvider("<no git commit>", listOf("rev-parse", "HEAD")) { it.trim() }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Get the current git branch. */
 | 
					    /** Get the current git branch. */
 | 
				
			||||||
    val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
 | 
					    val gitBranch: Provider<String> =
 | 
				
			||||||
        ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
 | 
					        gitProvider("<no git branch>", listOf("rev-parse", "--abbrev-ref", "HEAD")) { it.trim() }
 | 
				
			||||||
            .trim()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Get a list of all contributors to the project. */
 | 
					    /** Get a list of all contributors to the project. */
 | 
				
			||||||
    val gitContributors: Provider<List<String>> = gitProvider(project, listOf()) {
 | 
					    val gitContributors: Provider<List<String>> =
 | 
				
			||||||
        ProcessHelpers.captureLines(
 | 
					        gitProvider(listOf(), listOf("shortlog", "-ns", "--group=author", "--group=trailer:co-authored-by", "HEAD")) { input ->
 | 
				
			||||||
            "git", "-C", project.rootProject.projectDir.absolutePath, "shortlog", "-ns",
 | 
					            input.lineSequence()
 | 
				
			||||||
            "--group=author", "--group=trailer:co-authored-by", "HEAD",
 | 
					                .filter { it.isNotEmpty() }
 | 
				
			||||||
        )
 | 
					                .map {
 | 
				
			||||||
            .asSequence()
 | 
					                    val matcher = COMMIT_COUNTS.matcher(it)
 | 
				
			||||||
            .map {
 | 
					                    matcher.find()
 | 
				
			||||||
                val matcher = COMMIT_COUNTS.matcher(it)
 | 
					                    matcher.group(1)
 | 
				
			||||||
                matcher.find()
 | 
					                }
 | 
				
			||||||
                matcher.group(1)
 | 
					                .filter { !IGNORED_USERS.contains(it) }
 | 
				
			||||||
            }
 | 
					                .toList()
 | 
				
			||||||
            .filter { !IGNORED_USERS.contains(it) }
 | 
					                .sortedWith(String.CASE_INSENSITIVE_ORDER)
 | 
				
			||||||
            .toList()
 | 
					        }
 | 
				
			||||||
            .sortedWith(String.CASE_INSENSITIVE_ORDER)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * References to other sources
 | 
					     * References to other sources
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    val sourceDirectories: SetProperty<SourceSetReference> = project.objects.setProperty(SourceSetReference::class.java)
 | 
					    val sourceDirectories: SetProperty<SourceSetReference> = project.objects.setProperty(SourceSetReference::class.java)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Dependencies excluded from published artifacts.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    private val excludedDeps: ListProperty<Dependency> = project.objects.listProperty(Dependency::class.java)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** All source sets referenced by this project. */
 | 
					    /** All source sets referenced by this project. */
 | 
				
			||||||
    val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
 | 
					    val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        sourceDirectories.finalizeValueOnRead()
 | 
					        sourceDirectories.finalizeValueOnRead()
 | 
				
			||||||
        excludedDeps.finalizeValueOnRead()
 | 
					 | 
				
			||||||
        project.afterEvaluate { sourceDirectories.disallowChanges() }
 | 
					        project.afterEvaluate { sourceDirectories.disallowChanges() }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,14 +89,13 @@ abstract class CCTweakedExtension(
 | 
				
			|||||||
        val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
 | 
					        val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
 | 
				
			||||||
        val main = otherJava.sourceSets.getByName("main")
 | 
					        val main = otherJava.sourceSets.getByName("main")
 | 
				
			||||||
        val client = otherJava.sourceSets.getByName("client")
 | 
					        val client = otherJava.sourceSets.getByName("client")
 | 
				
			||||||
        val testMod = otherJava.sourceSets.findByName("testMod")
 | 
					 | 
				
			||||||
        val testFixtures = otherJava.sourceSets.findByName("testFixtures")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Pull in sources from the other project.
 | 
					        // Pull in sources from the other project.
 | 
				
			||||||
        extendSourceSet(otherProject, main)
 | 
					        extendSourceSet(otherProject, main)
 | 
				
			||||||
        extendSourceSet(otherProject, client)
 | 
					        extendSourceSet(otherProject, client)
 | 
				
			||||||
        if (testMod != null) extendSourceSet(otherProject, testMod)
 | 
					        for (sourceSet in listOf(MinecraftConfigurations.DATAGEN, MinecraftConfigurations.EXAMPLES, MinecraftConfigurations.TEST_MOD, "testFixtures")) {
 | 
				
			||||||
        if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
 | 
					            otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // The extra source-processing tasks should include these files too.
 | 
					        // The extra source-processing tasks should include these files too.
 | 
				
			||||||
        project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
 | 
					        project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
 | 
				
			||||||
@@ -181,23 +158,19 @@ abstract class CCTweakedExtension(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
 | 
					    fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
 | 
				
			||||||
        val classDump = project.layout.buildDirectory.dir("jacocoClassDump/${task.name}")
 | 
					        val reportTaskName = "jacoco${task.name.capitalise()}Report"
 | 
				
			||||||
        val reportTaskName = "jacoco${task.name.capitalized()}Report"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
 | 
					        val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
 | 
				
			||||||
        task.configure {
 | 
					        task.configure {
 | 
				
			||||||
            finalizedBy(reportTaskName)
 | 
					            finalizedBy(reportTaskName)
 | 
				
			||||||
 | 
					 | 
				
			||||||
            doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            jacoco.applyTo(this)
 | 
					            jacoco.applyTo(this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            extensions.configure(JacocoTaskExtension::class.java) {
 | 
					            extensions.configure(JacocoTaskExtension::class.java) {
 | 
				
			||||||
                includes = listOf("dan200.computercraft.*")
 | 
					                includes = listOf("dan200.computercraft.*")
 | 
				
			||||||
                classDumpDir = classDump.get().asFile
 | 
					                excludes = listOf(
 | 
				
			||||||
 | 
					                    "dan200.computercraft.mixin.*", // Exclude mixins, as they're not executed at runtime.
 | 
				
			||||||
                // Older versions of modlauncher don't include a protection domain (and thus no code
 | 
					                    "dan200.computercraft.shared.Capabilities$*", // Exclude capability tokens, as Forge rewrites them.
 | 
				
			||||||
                // source). Jacoco skips such classes by default, so we need to explicitly include them.
 | 
					                )
 | 
				
			||||||
                isIncludeNoLocationClasses = true
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,15 +179,11 @@ abstract class CCTweakedExtension(
 | 
				
			|||||||
            description = "Generates code coverage report for the ${task.name} task."
 | 
					            description = "Generates code coverage report for the ${task.name} task."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            executionData(task.get())
 | 
					            executionData(task.get())
 | 
				
			||||||
            classDirectories.from(classDump)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Don't want to use sourceSets(...) here as we have a custom class directory.
 | 
					            // Don't want to use sourceSets(...) here as we don't use all class directories.
 | 
				
			||||||
            for (ref in sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
 | 
					            for (ref in this@CCTweakedExtension.sourceDirectories.get()) {
 | 
				
			||||||
        }
 | 
					                sourceDirectories.from(ref.sourceSet.allSource.sourceDirectories)
 | 
				
			||||||
 | 
					                if (ref.classes) classDirectories.from(ref.sourceSet.output)
 | 
				
			||||||
        project.extensions.configure(ReportingExtension::class.java) {
 | 
					 | 
				
			||||||
            reports.register("${task.name}CodeCoverageReport", JacocoCoverageReport::class.java) {
 | 
					 | 
				
			||||||
                testType.set(TestSuiteType.INTEGRATION_TEST)
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -226,12 +195,12 @@ abstract class CCTweakedExtension(
 | 
				
			|||||||
     * where possible.
 | 
					     * where possible.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fun downloadFile(label: String, url: String): File {
 | 
					    fun downloadFile(label: String, url: String): File {
 | 
				
			||||||
        val url = URL(url)
 | 
					        val uri = URI(url)
 | 
				
			||||||
        val path = File(url.path)
 | 
					        val path = File(uri.path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        project.repositories.ivy {
 | 
					        project.repositories.ivy {
 | 
				
			||||||
            name = label
 | 
					            name = label
 | 
				
			||||||
            setUrl(URI(url.protocol, url.userInfo, url.host, url.port, path.parent, null, null))
 | 
					            setUrl(URI(uri.scheme, uri.userInfo, uri.host, uri.port, path.parent, null, null))
 | 
				
			||||||
            patternLayout {
 | 
					            patternLayout {
 | 
				
			||||||
                artifact("[artifact].[ext]")
 | 
					                artifact("[artifact].[ext]")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -254,40 +223,31 @@ abstract class CCTweakedExtension(
 | 
				
			|||||||
        ).resolve().single()
 | 
					        ).resolve().single()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    private fun <T: Any> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
 | 
				
			||||||
     * Exclude a dependency from being published in Maven.
 | 
					        val baseResult = project.providers.exec {
 | 
				
			||||||
     */
 | 
					            commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
 | 
				
			||||||
    fun exclude(dep: Dependency) {
 | 
					        }
 | 
				
			||||||
        excludedDeps.add(dep)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					        return project.provider {
 | 
				
			||||||
     * Configure a [MavenDependencySpec].
 | 
					            val res = try {
 | 
				
			||||||
     */
 | 
					                baseResult.standardOutput.asText.get()
 | 
				
			||||||
    fun configureExcludes(spec: MavenDependencySpec) {
 | 
					            } catch (e: IOException) {
 | 
				
			||||||
        for (dep in excludedDeps.get()) spec.exclude(dep)
 | 
					                project.logger.error("Cannot read Git repository: ${e.message}", e)
 | 
				
			||||||
 | 
					                return@provider default
 | 
				
			||||||
 | 
					            } catch (e: GradleException) {
 | 
				
			||||||
 | 
					                project.logger.error("Cannot read Git repository: ${e.message}", e)
 | 
				
			||||||
 | 
					                return@provider default
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            process(res)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
 | 
					        private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
 | 
				
			||||||
        private val IGNORED_USERS = setOf(
 | 
					        private val IGNORED_USERS = setOf(
 | 
				
			||||||
            "GitHub", "Daniel Ratcliffe", "Weblate",
 | 
					            "GitHub", "Daniel Ratcliffe", "NotSquidDev", "Weblate",
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private fun <T> gitProvider(project: Project, default: T, supplier: () -> T): Provider<T> {
 | 
					 | 
				
			||||||
            return project.provider {
 | 
					 | 
				
			||||||
                try {
 | 
					 | 
				
			||||||
                    supplier()
 | 
					 | 
				
			||||||
                } catch (e: IOException) {
 | 
					 | 
				
			||||||
                    project.logger.error("Cannot read Git repository: ${e.message}")
 | 
					 | 
				
			||||||
                    default
 | 
					 | 
				
			||||||
                } catch (e: GradleException) {
 | 
					 | 
				
			||||||
                    project.logger.error("Cannot read Git repository: ${e.message}")
 | 
					 | 
				
			||||||
                    default
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private val isIdeSync: Boolean
 | 
					        private val isIdeSync: Boolean
 | 
				
			||||||
            get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
 | 
					            get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package cc.tweaked.gradle
 | 
					package cc.tweaked.gradle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.gradle.api.JavaVersion
 | 
				
			||||||
import org.gradle.api.Plugin
 | 
					import org.gradle.api.Plugin
 | 
				
			||||||
import org.gradle.api.Project
 | 
					import org.gradle.api.Project
 | 
				
			||||||
import org.gradle.api.plugins.JavaPlugin
 | 
					import org.gradle.api.plugins.JavaPlugin
 | 
				
			||||||
@@ -13,6 +14,7 @@ import org.gradle.plugins.ide.idea.model.IdeaModel
 | 
				
			|||||||
import org.jetbrains.gradle.ext.IdeaExtPlugin
 | 
					import org.jetbrains.gradle.ext.IdeaExtPlugin
 | 
				
			||||||
import org.jetbrains.gradle.ext.runConfigurations
 | 
					import org.jetbrains.gradle.ext.runConfigurations
 | 
				
			||||||
import org.jetbrains.gradle.ext.settings
 | 
					import org.jetbrains.gradle.ext.settings
 | 
				
			||||||
 | 
					import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Configures projects to match a shared configuration.
 | 
					 * Configures projects to match a shared configuration.
 | 
				
			||||||
@@ -42,6 +44,17 @@ class CCTweakedPlugin : Plugin<Project> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        val JAVA_VERSION = JavaLanguageVersion.of(17)
 | 
					        /**
 | 
				
			||||||
 | 
					         * The version we run with. We use Java 21 here, as our Gradle build requires that.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        val JDK_VERSION = JavaLanguageVersion.of(21)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The Java version we target. Should be the same as what Minecraft uses.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        val JAVA_TARGET = JavaLanguageVersion.of(17)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val JAVA_VERSION = JavaVersion.toVersion(JAVA_TARGET.asInt())
 | 
				
			||||||
 | 
					        val KOTLIN_TARGET = JvmTarget.fromTarget(JAVA_TARGET.toString())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,19 +22,19 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class DependencyCheck : DefaultTask() {
 | 
					abstract class DependencyCheck : DefaultTask() {
 | 
				
			||||||
    @get:Input
 | 
					    @get:Input
 | 
				
			||||||
    abstract val configuration: ListProperty<Configuration>
 | 
					    protected abstract val dependencies: ListProperty<DependencyResult>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
 | 
					     * A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @get:Input
 | 
					    @get:Input
 | 
				
			||||||
    abstract val overrides: MapProperty<String, String>
 | 
					    protected abstract val overrides: MapProperty<String, String>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        description = "Check :core's dependencies are consistent with Minecraft's."
 | 
					        description = "Check :core's dependencies are consistent with Minecraft's."
 | 
				
			||||||
        group = LifecycleBasePlugin.VERIFICATION_GROUP
 | 
					        group = LifecycleBasePlugin.VERIFICATION_GROUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        configuration.finalizeValueOnRead()
 | 
					        dependencies.finalizeValueOnRead()
 | 
				
			||||||
        overrides.finalizeValueOnRead()
 | 
					        overrides.finalizeValueOnRead()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,13 +45,23 @@ abstract class DependencyCheck : DefaultTask() {
 | 
				
			|||||||
        overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
 | 
					        overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun override(group: String, module: String, version: String) {
 | 
				
			||||||
 | 
					        overrides.put("$group:$module", version)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add a configuration to check.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun configuration(configuration: Provider<Configuration>) {
 | 
				
			||||||
 | 
					        // We can't store the Configuration in the cache, so store the resolved dependencies instead.
 | 
				
			||||||
 | 
					        dependencies.addAll(configuration.map { it.incoming.resolutionResult.allDependencies })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @TaskAction
 | 
					    @TaskAction
 | 
				
			||||||
    fun run() {
 | 
					    fun run() {
 | 
				
			||||||
        var ok = true
 | 
					        var ok = true
 | 
				
			||||||
        for (configuration in configuration.get()) {
 | 
					        for (configuration in dependencies.get()) {
 | 
				
			||||||
            configuration.incoming.resolutionResult.allDependencies {
 | 
					            if (!check(configuration)) ok = false
 | 
				
			||||||
                if (!check(this@allDependencies)) ok = false
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!ok) {
 | 
					        if (!ok) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,8 @@
 | 
				
			|||||||
package cc.tweaked.gradle
 | 
					package cc.tweaked.gradle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.gradle.api.file.DirectoryProperty
 | 
					import org.gradle.api.file.DirectoryProperty
 | 
				
			||||||
import org.gradle.api.provider.Property
 | 
					 | 
				
			||||||
import org.gradle.api.tasks.AbstractExecTask
 | 
					import org.gradle.api.tasks.AbstractExecTask
 | 
				
			||||||
import org.gradle.api.tasks.OutputDirectory
 | 
					import org.gradle.api.tasks.OutputDirectory
 | 
				
			||||||
import java.io.File
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
 | 
					abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
 | 
				
			||||||
    @get:OutputDirectory
 | 
					    @get:OutputDirectory
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -124,7 +124,7 @@ class CloseScope : AutoCloseable {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Proxy method to avoid overload ambiguity. */
 | 
					/** Proxy method to avoid overload ambiguity. */
 | 
				
			||||||
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
 | 
					fun <T: Any> Property<T >.setProvider(provider: Provider<out T>) = set(provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
 | 
					/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
 | 
				
			||||||
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
 | 
					fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
 | 
				
			||||||
@@ -143,7 +143,7 @@ fun getNextVersion(version: String): String {
 | 
				
			|||||||
    val lastIndex = mainVersion.lastIndexOf('.')
 | 
					    val lastIndex = mainVersion.lastIndexOf('.')
 | 
				
			||||||
    if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
 | 
					    if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
 | 
				
			||||||
    val lastVersion = try {
 | 
					    val lastVersion = try {
 | 
				
			||||||
        version.substring(lastIndex + 1).toInt()
 | 
					        mainVersion.substring(lastIndex + 1).toInt()
 | 
				
			||||||
    } catch (e: NumberFormatException) {
 | 
					    } catch (e: NumberFormatException) {
 | 
				
			||||||
        throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
 | 
					        throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -155,3 +155,15 @@ fun getNextVersion(version: String): String {
 | 
				
			|||||||
    if (dashIndex >= 0) out.append(version, dashIndex, version.length)
 | 
					    if (dashIndex >= 0) out.append(version, dashIndex, version.length)
 | 
				
			||||||
    return out.toString()
 | 
					    return out.toString()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Capitalise the first letter of the string.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is a replacement for the now deprecated [String.capitalize].
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun String.capitalise(): String {
 | 
				
			||||||
 | 
					    if (isEmpty()) return this
 | 
				
			||||||
 | 
					    val first = this[0]
 | 
				
			||||||
 | 
					    val firstTitle = first.titlecaseChar()
 | 
				
			||||||
 | 
					    return if (first == firstTitle) this else firstTitle + substring(1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package cc.tweaked.gradle
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraftforge.gradle.common.util.RunConfig
 | 
					 | 
				
			||||||
import net.minecraftforge.gradle.common.util.runs.setRunConfigInternal
 | 
					 | 
				
			||||||
import org.gradle.api.plugins.JavaPluginExtension
 | 
					 | 
				
			||||||
import org.gradle.api.tasks.JavaExec
 | 
					 | 
				
			||||||
import org.gradle.jvm.toolchain.JavaToolchainService
 | 
					 | 
				
			||||||
import java.nio.file.Files
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Set [JavaExec] task to run a given [RunConfig].
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
fun JavaExec.setRunConfig(config: RunConfig) {
 | 
					 | 
				
			||||||
    dependsOn("prepareRuns")
 | 
					 | 
				
			||||||
    setRunConfigInternal(project, this, config)
 | 
					 | 
				
			||||||
    doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    javaLauncher.set(
 | 
					 | 
				
			||||||
        project.extensions.getByType(JavaToolchainService::class.java)
 | 
					 | 
				
			||||||
            .launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -25,7 +25,6 @@ import javax.xml.xpath.XPathFactory
 | 
				
			|||||||
 * Would be good to PR some (or all) of these changes upstream at some point.
 | 
					 * Would be good to PR some (or all) of these changes upstream at some point.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
 | 
					 * @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
 | 
				
			||||||
 * @see net.minecraftforge.gradle.common.util.runs.IntellijRunGenerator
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
internal class IdeaRunConfigurations(project: Project) {
 | 
					internal class IdeaRunConfigurations(project: Project) {
 | 
				
			||||||
    private val rootProject = project.rootProject
 | 
					    private val rootProject = project.rootProject
 | 
				
			||||||
@@ -35,22 +34,6 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
				
			|||||||
    private val writer = TransformerFactory.newInstance().newTransformer()
 | 
					    private val writer = TransformerFactory.newInstance().newTransformer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val ideaDir = rootProject.file(".idea/")
 | 
					    private val ideaDir = rootProject.file(".idea/")
 | 
				
			||||||
    private val buildDir: Lazy<String?> = lazy {
 | 
					 | 
				
			||||||
        val ideaMisc = ideaDir.resolve("misc.xml")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try {
 | 
					 | 
				
			||||||
            val doc = Files.newBufferedReader(ideaMisc.toPath()).use {
 | 
					 | 
				
			||||||
                documentBuilder.parse(InputSource(it))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            val node =
 | 
					 | 
				
			||||||
                xpath.evaluate("//component[@name=\"ProjectRootManager\"]/output", doc, XPathConstants.NODE) as Node
 | 
					 | 
				
			||||||
            val attr = node.attributes.getNamedItem("url") as Attr
 | 
					 | 
				
			||||||
            attr.value.removePrefix("file://")
 | 
					 | 
				
			||||||
        } catch (e: Exception) {
 | 
					 | 
				
			||||||
            LOGGER.error("Failed to find root directory", e)
 | 
					 | 
				
			||||||
            null
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun patch() = synchronized(LOCK) {
 | 
					    fun patch() = synchronized(LOCK) {
 | 
				
			||||||
        val runConfigDir = ideaDir.resolve("runConfigurations")
 | 
					        val runConfigDir = ideaDir.resolve("runConfigurations")
 | 
				
			||||||
@@ -58,10 +41,9 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        Files.list(runConfigDir.toPath()).use {
 | 
					        Files.list(runConfigDir.toPath()).use {
 | 
				
			||||||
            for (configuration in it) {
 | 
					            for (configuration in it) {
 | 
				
			||||||
                val filename = configuration.fileName.toString();
 | 
					                val filename = configuration.fileName.toString()
 | 
				
			||||||
                when {
 | 
					                when {
 | 
				
			||||||
                    filename.endsWith("_fabric.xml") -> patchFabric(configuration)
 | 
					                    filename.endsWith("_fabric.xml") -> patchFabric(configuration)
 | 
				
			||||||
                    filename.startsWith("forge_") && filename.endsWith(".xml") -> patchForge(configuration)
 | 
					 | 
				
			||||||
                    else -> {}
 | 
					                    else -> {}
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -72,65 +54,6 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
				
			|||||||
        setXml("//configuration", "folderName") { "Fabric" }
 | 
					        setXml("//configuration", "folderName") { "Fabric" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun patchForge(path: Path) = withXml(path) {
 | 
					 | 
				
			||||||
        val configId = path.fileName.toString().removePrefix("forge_").removeSuffix(".xml")
 | 
					 | 
				
			||||||
        val sourceSet = forgeConfigs[configId]
 | 
					 | 
				
			||||||
        if (sourceSet == null) {
 | 
					 | 
				
			||||||
            LOGGER.error("[{}] Cannot map run configuration to a known source set", path)
 | 
					 | 
				
			||||||
            return@withXml
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        setXml("//configuration", "folderName") { "Forge" }
 | 
					 | 
				
			||||||
        setXml("//configuration/module", "name") { "${rootProject.name}.forge.$sourceSet" }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (buildDir.value == null) return@withXml
 | 
					 | 
				
			||||||
        setXml("//configuration/envs/env[@name=\"MOD_CLASSES\"]", "value") { classpath ->
 | 
					 | 
				
			||||||
            val classes = classpath!!.split(':')
 | 
					 | 
				
			||||||
            val newClasses = mutableListOf<String>()
 | 
					 | 
				
			||||||
            fun appendUnique(x: String) {
 | 
					 | 
				
			||||||
                if (!newClasses.contains(x)) newClasses.add(x)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            for (entry in classes) {
 | 
					 | 
				
			||||||
                if (!entry.contains("/out/")) {
 | 
					 | 
				
			||||||
                    appendUnique(entry)
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                val match = CLASSPATH_ENTRY.matchEntire(entry)
 | 
					 | 
				
			||||||
                if (match != null) {
 | 
					 | 
				
			||||||
                    val modId = match.groups["modId"]!!.value
 | 
					 | 
				
			||||||
                    val proj = match.groups["proj"]!!.value
 | 
					 | 
				
			||||||
                    var component = match.groups["component"]!!.value
 | 
					 | 
				
			||||||
                    if (component == "production") component = "main"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    appendUnique(forgeModEntry(modId, proj, component))
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    LOGGER.warn("[{}] Unknown classpath entry {}", path, entry)
 | 
					 | 
				
			||||||
                    appendUnique(entry)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Ensure common code is on the classpath
 | 
					 | 
				
			||||||
            for (proj in listOf("common", "common-api")) {
 | 
					 | 
				
			||||||
                for (component in listOf("main", "client")) {
 | 
					 | 
				
			||||||
                    appendUnique(forgeModEntry("computercraft", proj, component))
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (newClasses.any { it.startsWith("cctest%%") }) {
 | 
					 | 
				
			||||||
                appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
 | 
					 | 
				
			||||||
                appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
 | 
					 | 
				
			||||||
                appendUnique(forgeModEntry("cctest", "common", "testMod"))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            newClasses.joinToString(":")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun forgeModEntry(mod: String, project: String, component: String) =
 | 
					 | 
				
			||||||
        "$mod%%${buildDir.value}/production/${rootProject.name}.$project.$component"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
 | 
					    private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
 | 
				
			||||||
        val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
 | 
					        val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
 | 
				
			||||||
        if (node == null) {
 | 
					        if (node == null) {
 | 
				
			||||||
@@ -159,16 +82,5 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
				
			|||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
 | 
					        private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
 | 
				
			||||||
        private val LOCK = Any()
 | 
					        private val LOCK = Any()
 | 
				
			||||||
 | 
					 | 
				
			||||||
        private val CLASSPATH_ENTRY =
 | 
					 | 
				
			||||||
            Regex("(?<modId>[a-z]+)%%\\\$PROJECT_DIR\\\$/projects/(?<proj>[a-z-]+)/out/(?<component>\\w+)/(?<type>[a-z]+)\$")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        private val forgeConfigs = mapOf(
 | 
					 | 
				
			||||||
            "runClient" to "client",
 | 
					 | 
				
			||||||
            "runData" to "main",
 | 
					 | 
				
			||||||
            "runGameTestServer" to "testMod",
 | 
					 | 
				
			||||||
            "runServer" to "main",
 | 
					 | 
				
			||||||
            "runTestClient" to "testMod",
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,73 +0,0 @@
 | 
				
			|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package cc.tweaked.gradle
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.gradle.api.artifacts.Dependency
 | 
					 | 
				
			||||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
 | 
					 | 
				
			||||||
import org.gradle.api.artifacts.ProjectDependency
 | 
					 | 
				
			||||||
import org.gradle.api.plugins.BasePluginExtension
 | 
					 | 
				
			||||||
import org.gradle.api.publish.maven.MavenPublication
 | 
					 | 
				
			||||||
import org.gradle.api.specs.Spec
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * A dependency in a POM file.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
data class MavenDependency(val groupId: String?, val artifactId: String?, val version: String?, val scope: String?)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * A spec specifying which dependencies to include/exclude.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class MavenDependencySpec {
 | 
					 | 
				
			||||||
    private val excludeSpecs = mutableListOf<Spec<MavenDependency>>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun exclude(spec: Spec<MavenDependency>) {
 | 
					 | 
				
			||||||
        excludeSpecs.add(spec)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun exclude(dep: Dependency) {
 | 
					 | 
				
			||||||
        exclude {
 | 
					 | 
				
			||||||
            // We have to cheat a little for project dependencies, as the project name doesn't match the artifact group.
 | 
					 | 
				
			||||||
            val name = when (dep) {
 | 
					 | 
				
			||||||
                is ProjectDependency -> dep.dependencyProject.extensions.getByType(BasePluginExtension::class.java).archivesName.get()
 | 
					 | 
				
			||||||
                else -> dep.name
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            (dep.group.isNullOrEmpty() || dep.group == it.groupId) &&
 | 
					 | 
				
			||||||
                (name.isNullOrEmpty() || name == it.artifactId) &&
 | 
					 | 
				
			||||||
                (dep.version.isNullOrEmpty() || dep.version == it.version)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun exclude(dep: MinimalExternalModuleDependency) {
 | 
					 | 
				
			||||||
        exclude {
 | 
					 | 
				
			||||||
            dep.module.group == it.groupId && dep.module.name == it.artifactId
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun isIncluded(dep: MavenDependency) = !excludeSpecs.any { it.isSatisfiedBy(dep) }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Configure dependencies present in this publication's POM file.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * While this approach is very ugly, it's the easiest way to handle it!
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
fun MavenPublication.mavenDependencies(action: MavenDependencySpec.() -> Unit) {
 | 
					 | 
				
			||||||
    val spec = MavenDependencySpec()
 | 
					 | 
				
			||||||
    action(spec)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pom.withXml {
 | 
					 | 
				
			||||||
        val dependencies = XmlUtil.findChild(asNode(), "dependencies") ?: return@withXml
 | 
					 | 
				
			||||||
        dependencies.children().map { it as groovy.util.Node }.forEach {
 | 
					 | 
				
			||||||
            val dep = MavenDependency(
 | 
					 | 
				
			||||||
                groupId = XmlUtil.findChild(it, "groupId")?.text(),
 | 
					 | 
				
			||||||
                artifactId = XmlUtil.findChild(it, "artifactId")?.text(),
 | 
					 | 
				
			||||||
                version = XmlUtil.findChild(it, "version")?.text(),
 | 
					 | 
				
			||||||
                scope = XmlUtil.findChild(it, "scope")?.text(),
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (!spec.isIncluded(dep)) it.parent().remove(it)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										120
									
								
								buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package cc.tweaked.gradle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cc.tweaked.vanillaextract.core.util.MoreFiles
 | 
				
			||||||
 | 
					import org.gradle.api.Action
 | 
				
			||||||
 | 
					import org.gradle.api.DefaultTask
 | 
				
			||||||
 | 
					import org.gradle.api.GradleException
 | 
				
			||||||
 | 
					import org.gradle.api.file.*
 | 
				
			||||||
 | 
					import org.gradle.api.model.ObjectFactory
 | 
				
			||||||
 | 
					import org.gradle.api.provider.ListProperty
 | 
				
			||||||
 | 
					import org.gradle.api.tasks.*
 | 
				
			||||||
 | 
					import javax.inject.Inject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Merge common files across multiple directories into one destination directory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This is intended for merging the generated resources from the Forge and Fabric projects. Files common between the two
 | 
				
			||||||
 | 
					 * are written to the global [output] directory, while distinct files are written to the per-source
 | 
				
			||||||
 | 
					 * [MergeTrees.Source.output] directory.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					abstract class MergeTrees : DefaultTask() {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * A source directory to read from.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    interface Source {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The folder contianing all input files.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        @get:InputFiles
 | 
				
			||||||
 | 
					        @get:PathSensitive(PathSensitivity.RELATIVE)
 | 
				
			||||||
 | 
					        val input: ConfigurableFileTree
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun input(configure: Action<ConfigurableFileTree>) {
 | 
				
			||||||
 | 
					            configure.execute(input)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * The folder to write files unique to this folder to.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        @get:OutputDirectory
 | 
				
			||||||
 | 
					        val output: DirectoryProperty
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The list of sources.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @get:Nested
 | 
				
			||||||
 | 
					    abstract val sources: ListProperty<Source>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add and configure a new source.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun source(configure: Action<Source>) {
 | 
				
			||||||
 | 
					        val instance = objectFactory.newInstance(Source::class.java)
 | 
				
			||||||
 | 
					        configure.execute(instance)
 | 
				
			||||||
 | 
					        instance.output.disallowChanges()
 | 
				
			||||||
 | 
					        sources.add(instance)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The directory to write common files to.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @get:OutputDirectory
 | 
				
			||||||
 | 
					    abstract val output: DirectoryProperty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @get:Inject
 | 
				
			||||||
 | 
					    protected abstract val objectFactory: ObjectFactory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @get:Inject
 | 
				
			||||||
 | 
					    protected abstract val fsOperations: FileSystemOperations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @TaskAction
 | 
				
			||||||
 | 
					    fun run() {
 | 
				
			||||||
 | 
					        val sources = this.sources.get()
 | 
				
			||||||
 | 
					        if (sources.isEmpty()) throw GradleException("Cannot have an empty list of sources")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val files = mutableMapOf<String, SharedFile>()
 | 
				
			||||||
 | 
					        for (source in sources) {
 | 
				
			||||||
 | 
					            source.input.visit(
 | 
				
			||||||
 | 
					                object : FileVisitor {
 | 
				
			||||||
 | 
					                    override fun visitDir(dirDetails: FileVisitDetails) = Unit
 | 
				
			||||||
 | 
					                    override fun visitFile(fileDetails: FileVisitDetails) {
 | 
				
			||||||
 | 
					                        val path = fileDetails.file.toRelativeString(source.input.dir)
 | 
				
			||||||
 | 
					                        val hash = MoreFiles.computeSha1(fileDetails.file.toPath())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        val existing = files[path]
 | 
				
			||||||
 | 
					                        if (existing == null) {
 | 
				
			||||||
 | 
					                            files[path] = SharedFile(hash, 1)
 | 
				
			||||||
 | 
					                        } else if (existing.hash == hash) {
 | 
				
			||||||
 | 
					                            existing.found++
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Copy shared files to the common directory
 | 
				
			||||||
 | 
					        fsOperations.sync {
 | 
				
			||||||
 | 
					            from(sources[0].input)
 | 
				
			||||||
 | 
					            into(output)
 | 
				
			||||||
 | 
					            include(sharedFiles)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // And all other files to their per-source directory
 | 
				
			||||||
 | 
					        for (source in sources) {
 | 
				
			||||||
 | 
					            fsOperations.sync {
 | 
				
			||||||
 | 
					                from(source.input)
 | 
				
			||||||
 | 
					                into(source.output)
 | 
				
			||||||
 | 
					                exclude(sharedFiles)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class SharedFile(val hash: String, var found: Int)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -24,7 +24,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
				
			|||||||
    private val java = project.extensions.getByType(JavaPluginExtension::class.java)
 | 
					    private val java = project.extensions.getByType(JavaPluginExtension::class.java)
 | 
				
			||||||
    private val sourceSets = java.sourceSets
 | 
					    private val sourceSets = java.sourceSets
 | 
				
			||||||
    private val configurations = project.configurations
 | 
					    private val configurations = project.configurations
 | 
				
			||||||
    private val objects = project.objects
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
 | 
					    private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
 | 
				
			||||||
    private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
 | 
					    private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
 | 
				
			||||||
@@ -37,17 +36,10 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
				
			|||||||
        val client = sourceSets.maybeCreate("client")
 | 
					        val client = sourceSets.maybeCreate("client")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Ensure the client classpaths behave the same as the main ones.
 | 
					        // Ensure the client classpaths behave the same as the main ones.
 | 
				
			||||||
        configurations.named(client.compileClasspathConfigurationName) {
 | 
					        consistentWithMain(client)
 | 
				
			||||||
            shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        configurations.named(client.runtimeClasspathConfigurationName) {
 | 
					 | 
				
			||||||
            shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Set up an API configuration for clients (to ensure it's consistent with the main source set).
 | 
					        // Set up an API configuration for clients (to ensure it's consistent with the main source set).
 | 
				
			||||||
        val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
 | 
					        val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
 | 
				
			||||||
            isVisible = false
 | 
					 | 
				
			||||||
            isCanBeConsumed = false
 | 
					            isCanBeConsumed = false
 | 
				
			||||||
            isCanBeResolved = false
 | 
					            isCanBeResolved = false
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -85,6 +77,16 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
				
			|||||||
        setupBasic()
 | 
					        setupBasic()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun consistentWithMain(sourceSet: SourceSet) {
 | 
				
			||||||
 | 
					        configurations.named(sourceSet.compileClasspathConfigurationName) {
 | 
				
			||||||
 | 
					            shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        configurations.named(sourceSet.runtimeClasspathConfigurationName) {
 | 
				
			||||||
 | 
					            shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun setupBasic() {
 | 
					    private fun setupBasic() {
 | 
				
			||||||
        val client = sourceSets["client"]
 | 
					        val client = sourceSets["client"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -96,13 +98,30 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
				
			|||||||
        val checkDependencyConsistency =
 | 
					        val checkDependencyConsistency =
 | 
				
			||||||
            project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
 | 
					            project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
 | 
				
			||||||
                // We need to check both the main and client classpath *configurations*, as the actual configuration
 | 
					                // We need to check both the main and client classpath *configurations*, as the actual configuration
 | 
				
			||||||
                configuration.add(configurations.named(main.runtimeClasspathConfigurationName))
 | 
					                configuration(configurations.named(main.runtimeClasspathConfigurationName))
 | 
				
			||||||
                configuration.add(configurations.named(client.runtimeClasspathConfigurationName))
 | 
					                configuration(configurations.named(client.runtimeClasspathConfigurationName))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
 | 
					        project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new configuration that pulls in the main and client classes from the mod.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private fun createDerivedConfiguration(name: String) {
 | 
				
			||||||
 | 
					        val client = sourceSets["client"]
 | 
				
			||||||
 | 
					        val sourceSet = sourceSets.create(name)
 | 
				
			||||||
 | 
					        sourceSet.compileClasspath += main.compileClasspath + client.compileClasspath
 | 
				
			||||||
 | 
					        sourceSet.runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
 | 
				
			||||||
 | 
					        consistentWithMain(sourceSet)
 | 
				
			||||||
 | 
					        project.dependencies.add(sourceSet.implementationConfigurationName, main.output)
 | 
				
			||||||
 | 
					        project.dependencies.add(sourceSet.implementationConfigurationName, client.output)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
 | 
					        const val DATAGEN = "datagen"
 | 
				
			||||||
 | 
					        const val EXAMPLES = "examples"
 | 
				
			||||||
 | 
					        const val TEST_MOD = "testMod"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fun setupBasic(project: Project) {
 | 
					        fun setupBasic(project: Project) {
 | 
				
			||||||
            MinecraftConfigurations(project).setupBasic()
 | 
					            MinecraftConfigurations(project).setupBasic()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -110,6 +129,10 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
				
			|||||||
        fun setup(project: Project) {
 | 
					        fun setup(project: Project) {
 | 
				
			||||||
            MinecraftConfigurations(project).setup()
 | 
					            MinecraftConfigurations(project).setup()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun createDerivedConfiguration(project: Project, name: String) {
 | 
				
			||||||
 | 
					            MinecraftConfigurations(project).createDerivedConfiguration(name)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package cc.tweaked.gradle
 | 
					package cc.tweaked.gradle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.minecraftforge.gradle.common.util.RunConfig
 | 
					import net.neoforged.moddevgradle.internal.RunGameTask
 | 
				
			||||||
import org.gradle.api.GradleException
 | 
					import org.gradle.api.GradleException
 | 
				
			||||||
import org.gradle.api.file.FileSystemOperations
 | 
					import org.gradle.api.file.FileSystemOperations
 | 
				
			||||||
import org.gradle.api.invocation.Gradle
 | 
					import org.gradle.api.invocation.Gradle
 | 
				
			||||||
@@ -65,11 +65,19 @@ abstract class ClientJavaExec : JavaExec() {
 | 
				
			|||||||
        setTestProperties()
 | 
					        setTestProperties()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun copyFromForge(path: String) = copyFromForge(project.tasks.getByName(path, RunGameTask::class))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Set this task to run a given [RunConfig].
 | 
					     * Set this task to run a given [RunGameTask].
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    fun setRunConfig(config: RunConfig) {
 | 
					    fun copyFromForge(task: RunGameTask) {
 | 
				
			||||||
        (this as JavaExec).setRunConfig(config)
 | 
					        copyFrom(task)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Eagerly evaluate the behaviour of RunGameTask.exec
 | 
				
			||||||
 | 
					        environment.putAll(task.environmentProperty.get())
 | 
				
			||||||
 | 
					        classpath(task.classpathProvider)
 | 
				
			||||||
 | 
					        workingDir = task.gameDirectory.get().asFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
 | 
					        setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,9 @@ import org.gradle.api.file.Directory
 | 
				
			|||||||
import org.gradle.api.file.DirectoryProperty
 | 
					import org.gradle.api.file.DirectoryProperty
 | 
				
			||||||
import org.gradle.api.provider.Provider
 | 
					import org.gradle.api.provider.Provider
 | 
				
			||||||
import org.gradle.api.tasks.*
 | 
					import org.gradle.api.tasks.*
 | 
				
			||||||
 | 
					import org.gradle.process.ExecOperations
 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
 | 
					import javax.inject.Inject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NodePlugin : Plugin<Project> {
 | 
					class NodePlugin : Plugin<Project> {
 | 
				
			||||||
    override fun apply(project: Project) {
 | 
					    override fun apply(project: Project) {
 | 
				
			||||||
@@ -43,10 +45,13 @@ abstract class NpmInstall : DefaultTask() {
 | 
				
			|||||||
    @get:OutputDirectory
 | 
					    @get:OutputDirectory
 | 
				
			||||||
    val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
 | 
					    val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @get:Inject
 | 
				
			||||||
 | 
					    protected abstract val execOperations: ExecOperations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @TaskAction
 | 
					    @TaskAction
 | 
				
			||||||
    fun install() {
 | 
					    fun install() {
 | 
				
			||||||
        project.exec {
 | 
					        execOperations.exec {
 | 
				
			||||||
            commandLine("npm", "ci")
 | 
					            commandLine(ProcessHelpers.getExecutable("npm"), "ci")
 | 
				
			||||||
            workingDir = projectRoot.get().asFile
 | 
					            workingDir = projectRoot.get().asFile
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -59,6 +64,6 @@ abstract class NpmInstall : DefaultTask() {
 | 
				
			|||||||
abstract class NpxExecToDir : ExecToDir() {
 | 
					abstract class NpxExecToDir : ExecToDir() {
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        dependsOn(NpmInstall.TASK_NAME)
 | 
					        dependsOn(NpmInstall.TASK_NAME)
 | 
				
			||||||
        executable = "npx"
 | 
					        executable = ProcessHelpers.getExecutable("npx")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,48 +4,36 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package cc.tweaked.gradle
 | 
					package cc.tweaked.gradle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.codehaus.groovy.runtime.ProcessGroovyMethods
 | 
					 | 
				
			||||||
import org.gradle.api.GradleException
 | 
					import org.gradle.api.GradleException
 | 
				
			||||||
import java.io.BufferedReader
 | 
					 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
import java.io.InputStreamReader
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal object ProcessHelpers {
 | 
					internal object ProcessHelpers {
 | 
				
			||||||
    fun startProcess(vararg command: String): Process {
 | 
					 | 
				
			||||||
        // Something randomly passes in "GIT_DIR=" as an environment variable which clobbers everything else. Don't
 | 
					 | 
				
			||||||
        // inherit the environment array!
 | 
					 | 
				
			||||||
        return ProcessBuilder()
 | 
					 | 
				
			||||||
            .command(*command)
 | 
					 | 
				
			||||||
            .redirectError(ProcessBuilder.Redirect.INHERIT)
 | 
					 | 
				
			||||||
            .also { it.environment().clear() }
 | 
					 | 
				
			||||||
            .start()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun captureOut(vararg command: String): String {
 | 
					 | 
				
			||||||
        val process = startProcess(*command)
 | 
					 | 
				
			||||||
        process.outputStream.close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        val result = ProcessGroovyMethods.getText(process)
 | 
					 | 
				
			||||||
        process.waitForOrThrow("Failed to run command")
 | 
					 | 
				
			||||||
        return result
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun captureLines(vararg command: String): List<String> {
 | 
					 | 
				
			||||||
        val process = startProcess(*command)
 | 
					 | 
				
			||||||
        process.outputStream.close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        val out = BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
 | 
					 | 
				
			||||||
            reader.lines().filter { it.isNotEmpty() }.toList()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        ProcessGroovyMethods.closeStreams(process)
 | 
					 | 
				
			||||||
        process.waitForOrThrow("Failed to run command")
 | 
					 | 
				
			||||||
        return out
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun onPath(name: String): Boolean {
 | 
					    fun onPath(name: String): Boolean {
 | 
				
			||||||
        val path = System.getenv("PATH") ?: return false
 | 
					        val path = System.getenv("PATH") ?: return false
 | 
				
			||||||
        return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
 | 
					        return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Search for an executable on the `PATH` if required.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * [Process]/[ProcessBuilder] does not handle all executable file extensions on Windows (such as `.com). When on
 | 
				
			||||||
 | 
					     * Windows, this function searches `PATH` and `PATHEXT` for an executable matching [name].
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fun getExecutable(name: String): String {
 | 
				
			||||||
 | 
					        if (!System.getProperty("os.name").lowercase().contains("windows")) return name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val path = (System.getenv("PATH") ?: return name).split(File.pathSeparator)
 | 
				
			||||||
 | 
					        val pathExt = (System.getenv("PATHEXT") ?: return name).split(File.pathSeparator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (pathEntry in path) {
 | 
				
			||||||
 | 
					            for (ext in pathExt) {
 | 
				
			||||||
 | 
					                val resolved = File(pathEntry, name + ext)
 | 
				
			||||||
 | 
					                if (resolved.exists()) return resolved.getAbsolutePath()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return name
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal fun Process.waitForOrThrow(message: String) {
 | 
					internal fun Process.waitForOrThrow(message: String) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package cc.tweaked.gradle
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import groovy.util.Node
 | 
					 | 
				
			||||||
import groovy.util.NodeList
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
object XmlUtil {
 | 
					 | 
				
			||||||
    fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
 | 
					 | 
				
			||||||
        is Node -> child
 | 
					 | 
				
			||||||
        is NodeList -> child.singleOrNull() as Node?
 | 
					 | 
				
			||||||
        else -> null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,51 +0,0 @@
 | 
				
			|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
package net.minecraftforge.gradle.common.util.runs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import net.minecraftforge.gradle.common.util.RunConfig
 | 
					 | 
				
			||||||
import org.gradle.api.Project
 | 
					 | 
				
			||||||
import org.gradle.process.CommandLineArgumentProvider
 | 
					 | 
				
			||||||
import org.gradle.process.JavaExecSpec
 | 
					 | 
				
			||||||
import java.io.File
 | 
					 | 
				
			||||||
import java.util.function.Supplier
 | 
					 | 
				
			||||||
import java.util.stream.Collectors
 | 
					 | 
				
			||||||
import java.util.stream.Stream
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Set up a [JavaExecSpec] to execute a [RunConfig].
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * [MinecraftRunTask] sets up all its properties when the task is executed, rather than when configured. As such, it's
 | 
					 | 
				
			||||||
 * not possible to use [cc.tweaked.gradle.copyToFull] like we do for Fabric. Instead, we set up the task manually.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Unfortunately most of the functionality we need is package-private, and so we have to put our code into the package.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
internal fun setRunConfigInternal(project: Project, spec: JavaExecSpec, config: RunConfig) {
 | 
					 | 
				
			||||||
    spec.workingDir = File(config.workingDirectory)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    spec.mainClass.set(config.main)
 | 
					 | 
				
			||||||
    for (source in config.allSources) spec.classpath(source.runtimeClasspath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts.
 | 
					 | 
				
			||||||
    val lazyTokens = RunConfigGenerator.configureTokensLazy(
 | 
					 | 
				
			||||||
        project, config, RunConfigGenerator.mapModClassesToGradle(project, config),
 | 
					 | 
				
			||||||
        originalTask.get().minecraftArtifacts,
 | 
					 | 
				
			||||||
        originalTask.get().runtimeClasspathArtifacts,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    spec.argumentProviders.add(
 | 
					 | 
				
			||||||
        CommandLineArgumentProvider {
 | 
					 | 
				
			||||||
            RunConfigGenerator.getArgsStream(config, lazyTokens, false).toList()
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    spec.jvmArgumentProviders.add(
 | 
					 | 
				
			||||||
        CommandLineArgumentProvider {
 | 
					 | 
				
			||||||
            (if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } +
 | 
					 | 
				
			||||||
                config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -92,7 +92,10 @@ SPDX-License-Identifier: MPL-2.0
 | 
				
			|||||||
        <module name="InvalidJavadocPosition" />
 | 
					        <module name="InvalidJavadocPosition" />
 | 
				
			||||||
        <module name="JavadocBlockTagLocation" />
 | 
					        <module name="JavadocBlockTagLocation" />
 | 
				
			||||||
        <module name="JavadocMethod"/>
 | 
					        <module name="JavadocMethod"/>
 | 
				
			||||||
        <module name="JavadocType"/>
 | 
					        <module name="JavadocType">
 | 
				
			||||||
 | 
					            <!-- Seems to complain about @hidden!? -->
 | 
				
			||||||
 | 
					            <property name="allowUnknownTags" value="true" />
 | 
				
			||||||
 | 
					        </module>
 | 
				
			||||||
        <module name="JavadocStyle">
 | 
					        <module name="JavadocStyle">
 | 
				
			||||||
            <property name="checkHtml" value="false" />
 | 
					            <property name="checkHtml" value="false" />
 | 
				
			||||||
        </module>
 | 
					        </module>
 | 
				
			||||||
@@ -124,7 +127,7 @@ SPDX-License-Identifier: MPL-2.0
 | 
				
			|||||||
        </module>
 | 
					        </module>
 | 
				
			||||||
        <module name="MethodTypeParameterName" />
 | 
					        <module name="MethodTypeParameterName" />
 | 
				
			||||||
        <module name="PackageName">
 | 
					        <module name="PackageName">
 | 
				
			||||||
            <property name="format" value="^(dan200\.computercraft|cc\.tweaked)(\.[a-z][a-z0-9]*)*" />
 | 
					            <property name="format" value="^(dan200\.computercraft|cc\.tweaked|com\.example\.examplemod)(\.[a-z][a-z0-9]*)*" />
 | 
				
			||||||
        </module>
 | 
					        </module>
 | 
				
			||||||
        <module name="ParameterName" />
 | 
					        <module name="ParameterName" />
 | 
				
			||||||
        <module name="StaticVariableName">
 | 
					        <module name="StaticVariableName">
 | 
				
			||||||
@@ -143,7 +146,10 @@ SPDX-License-Identifier: MPL-2.0
 | 
				
			|||||||
        <module name="NoWhitespaceAfter">
 | 
					        <module name="NoWhitespaceAfter">
 | 
				
			||||||
            <property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
 | 
					            <property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
 | 
				
			||||||
        </module>
 | 
					        </module>
 | 
				
			||||||
        <module name="NoWhitespaceBefore" />
 | 
					        <module name="NoWhitespaceBefore">
 | 
				
			||||||
 | 
					            <!-- Allow whitespace before "..." for @Nullable annotations -->
 | 
				
			||||||
 | 
					            <property name="tokens" value="COMMA,SEMI,POST_INC,POST_DEC,LABELED_STAT" />
 | 
				
			||||||
 | 
					        </module>
 | 
				
			||||||
        <!-- TODO: Decide on an OperatorWrap style. -->
 | 
					        <!-- TODO: Decide on an OperatorWrap style. -->
 | 
				
			||||||
        <module name="ParenPad" />
 | 
					        <module name="ParenPad" />
 | 
				
			||||||
        <module name="SeparatorWrap">
 | 
					        <module name="SeparatorWrap">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# SPDX-License-Identifier: MPL-2.0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FROM gitpod/workspace-base
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
USER gitpod
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RUN sudo apt-get -q update \
 | 
					 | 
				
			||||||
 && sudo apt-get install -yq openjdk-16-jdk python3-pip npm \
 | 
					 | 
				
			||||||
 && sudo pip3 install pre-commit \
 | 
					 | 
				
			||||||
 && sudo update-java-alternatives --set java-1.16.0-openjdk-amd64
 | 
					 | 
				
			||||||
							
								
								
									
										29
									
								
								crowdin.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								crowdin.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					files:
 | 
				
			||||||
 | 
					  - source: projects/common/src/generated/resources/assets/computercraft/lang/en_us.json
 | 
				
			||||||
 | 
					    translation: /projects/common/src/main/resources/assets/computercraft/lang/%locale_with_underscore%.json
 | 
				
			||||||
 | 
					    languages_mapping:
 | 
				
			||||||
 | 
					      locale_with_underscore:
 | 
				
			||||||
 | 
					        cs: cs_cz    # Czech
 | 
				
			||||||
 | 
					        da: da_dk    # Danish
 | 
				
			||||||
 | 
					        de: de_de    # German
 | 
				
			||||||
 | 
					        es-ES: es_es # Spanish
 | 
				
			||||||
 | 
					        fr: fr_fr    # French
 | 
				
			||||||
 | 
					        hu: hu_hu    # Hungarian
 | 
				
			||||||
 | 
					        it: it_it    # Italian
 | 
				
			||||||
 | 
					        ja: ja_jp    # Japanese
 | 
				
			||||||
 | 
					        ko: ko_kr    # Korean
 | 
				
			||||||
 | 
					        nb: nb_no    # Norwegian Bokmal
 | 
				
			||||||
 | 
					        nl: nl_nl    # Dutch
 | 
				
			||||||
 | 
					        pl: pl_pl    # Polish
 | 
				
			||||||
 | 
					        pt-BR: pt_br # Portuguese, Brazilian
 | 
				
			||||||
 | 
					        ru: ru_ru    # Russian
 | 
				
			||||||
 | 
					        sv-SE: sv_se # Sweedish
 | 
				
			||||||
 | 
					        tok: tok     # Toki Pona
 | 
				
			||||||
 | 
					        tr: tr_tr    # Turkish
 | 
				
			||||||
 | 
					        uk: uk_ua    # Ukraine
 | 
				
			||||||
 | 
					        vi: vi_vn    # Vietnamese
 | 
				
			||||||
 | 
					        zh-CN: zh_cn # Chinese Simplified
 | 
				
			||||||
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
 | 
				
			|||||||
SPDX-License-Identifier: MPL-2.0
 | 
					SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The [`monitor_resize`] event is fired when an adjacent or networked monitor's size is changed.
 | 
					The [`monitor_resize`] event is fired when an adjacent or networked [monitor's][`monitor`] size is changed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Return Values
 | 
					## Return Values
 | 
				
			||||||
1. [`string`]: The event name.
 | 
					1. [`string`]: The event name.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
 | 
				
			|||||||
SPDX-License-Identifier: MPL-2.0
 | 
					SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The [`monitor_touch`] event is fired when an adjacent or networked Advanced Monitor is right-clicked.
 | 
					The [`monitor_touch`] event is fired when an adjacent or networked [Advanced Monitor][`monitor`] is right-clicked.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Return Values
 | 
					## Return Values
 | 
				
			||||||
1. [`string`]: The event name.
 | 
					1. [`string`]: The event name.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
 | 
				
			|||||||
SPDX-License-Identifier: MPL-2.0
 | 
					SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The [`event!redstone`] event is fired whenever any redstone inputs on the computer change.
 | 
					The [`event!redstone`] event is fired whenever any redstone inputs on the computer or [relay][`redstone_relay`] change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Return values
 | 
					## Return values
 | 
				
			||||||
1. [`string`]: The event name.
 | 
					1. [`string`]: The event name.
 | 
				
			||||||
@@ -21,3 +21,7 @@ while true do
 | 
				
			|||||||
  print("A redstone input has changed!")
 | 
					  print("A redstone input has changed!")
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## See also
 | 
				
			||||||
 | 
					 - [The `redstone` API on computers][`module!redstone`]
 | 
				
			||||||
 | 
					 - [The `redstone_relay` peripheral][`redstone_relay`]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -131,7 +131,7 @@ different.
 | 
				
			|||||||
First, we require the dfpwm module and call [`cc.audio.dfpwm.make_decoder`] to construct a new decoder. This decoder
 | 
					First, we require the dfpwm module and call [`cc.audio.dfpwm.make_decoder`] to construct a new decoder. This decoder
 | 
				
			||||||
accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
 | 
					accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPMW uses a single bit for each
 | 
					As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPWM uses a single bit for each
 | 
				
			||||||
sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
 | 
					sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
 | 
				
			||||||
[`io.lines`], which provides a nice way to loop over chunks of a file. You can of course just use [`fs.open`] and
 | 
					[`io.lines`], which provides a nice way to loop over chunks of a file. You can of course just use [`fs.open`] and
 | 
				
			||||||
[`fs.ReadHandle.read`] if you prefer.
 | 
					[`fs.ReadHandle.read`] if you prefer.
 | 
				
			||||||
@@ -191,7 +191,7 @@ end
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
> [Confused?][!NOTE]
 | 
					> [Confused?][!NOTE]
 | 
				
			||||||
> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
 | 
					> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
 | 
				
			||||||
> cover. That said, don't be afraid to ask on [GitHub Discussions] or [IRC] either!
 | 
					> cover. That said, don't be afraid to ask [the community for help][community].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
 | 
					It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
 | 
				
			||||||
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
 | 
					the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
 | 
				
			||||||
@@ -205,5 +205,4 @@ This is, I'm afraid, left as an exercise to the reader.
 | 
				
			|||||||
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
 | 
					[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
 | 
				
			||||||
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
 | 
					[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
 | 
				
			||||||
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
 | 
					[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
 | 
				
			||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
					[Community]: /#community
 | 
				
			||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								doc/index.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								doc/index.md
									
									
									
									
									
								
							@@ -4,12 +4,19 @@ SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
 | 
				
			|||||||
SPDX-License-Identifier: MPL-2.0
 | 
					SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 
 | 
					<h1>
 | 
				
			||||||
 | 
					    <picture>
 | 
				
			||||||
 | 
					        <source media="(prefers-color-scheme: dark)" srcset="logo-darkmode.png">
 | 
				
			||||||
 | 
					        <source media="(prefers-color-scheme: light)" srcset="logo.png">
 | 
				
			||||||
 | 
					        <img alt="CC: Tweaked" src="logo.png">
 | 
				
			||||||
 | 
					    </picture>
 | 
				
			||||||
 | 
					</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
 | 
					CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
 | 
				
			||||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
 | 
					much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
 | 
				
			||||||
new features.
 | 
					new features.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
 | 
					CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Features
 | 
					## Features
 | 
				
			||||||
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
 | 
					Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
 | 
				
			||||||
@@ -38,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 - [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
 | 
					 - [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
 | 
				
			||||||
 - [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
 | 
					 - [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
 | 
				
			||||||
 - [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
 | 
					 - [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
 | 
					Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
 | 
				
			||||||
various APIs and peripherals provided by the mod.
 | 
					various APIs and peripherals provided by the mod.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
 | 
					<h2 id="community">Community</h2>
 | 
				
			||||||
 | 
					If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
 | 
				
			||||||
 | 
					ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
 | 
				
			||||||
 | 
					albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
 | 
				
			||||||
 | 
					desktop client, or online using [KiwiIRC].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Get Involved
 | 
					## Get Involved
 | 
				
			||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
 | 
					CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
 | 
				
			||||||
@@ -51,11 +62,11 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
 | 
				
			|||||||
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
 | 
					[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
 | 
				
			||||||
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
 | 
					[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
 | 
				
			||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
					[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
				
			||||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
 | 
					 | 
				
			||||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
 | 
					[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
 | 
				
			||||||
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
					[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
				
			||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
					[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
 | 
				
			||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
 | 
					[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
 | 
				
			||||||
[lua]: https://www.lua.org/ "Lua's main website"
 | 
					[lua]: https://www.lua.org/ "Lua's main website"
 | 
				
			||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
					[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
				
			||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
 | 
					[EsperNet]: https://www.esper.net/
 | 
				
			||||||
 | 
					[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 - [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
 | 
					 - [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
 | 
				
			||||||
 - [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
 | 
					 - [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
 | 
				
			||||||
 - [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
 | 
					 - [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
 | 
					Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
 | 
				
			||||||
various APIs and peripherals provided by the mod.
 | 
					various APIs and peripherals provided by the mod.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
 | 
					## Community
 | 
				
			||||||
 | 
					If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
 | 
				
			||||||
 | 
					ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
 | 
				
			||||||
 | 
					albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
 | 
				
			||||||
 | 
					desktop client, or online using [KiwiIRC].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Get Involved
 | 
					## Get Involved
 | 
				
			||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
 | 
					CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
 | 
				
			||||||
@@ -60,4 +64,5 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
 | 
				
			|||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
					[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
 | 
				
			||||||
[lua]: https://www.lua.org/ "Lua's main website"
 | 
					[lua]: https://www.lua.org/ "Lua's main website"
 | 
				
			||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
					[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
 | 
				
			||||||
[IRC]: http://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
 | 
					[EsperNet]: https://www.esper.net/
 | 
				
			||||||
 | 
					[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,13 +25,13 @@ as documentation for breaking changes and "gotchas" one should look out for betw
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 - Update to Lua 5.2:
 | 
					 - Update to Lua 5.2:
 | 
				
			||||||
   - Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
 | 
					   - Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
 | 
				
			||||||
   - Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. `getfenv`/`setfenv`
 | 
					   - Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. [`getfenv`]/[`setfenv`]
 | 
				
			||||||
     now only work on Lua functions with an `_ENV` upvalue. `getfenv` will return the global environment when called
 | 
					     now only work on Lua functions with an `_ENV` upvalue. [`getfenv`] will return the global environment when called
 | 
				
			||||||
     with other functions, and `setfenv` will have no effect.
 | 
					     with other functions, and [`setfenv`] will have no effect.
 | 
				
			||||||
   - `load`/`loadstring` defaults to using the global environment (`_G`) rather than the current coroutine's
 | 
					   - [`load`]/[`loadstring`] defaults to using the global environment (`_G`) rather than the current coroutine's
 | 
				
			||||||
     environment.
 | 
					     environment.
 | 
				
			||||||
   - Support for dumping functions (`string.dump`) and loading binary chunks has been removed.
 | 
					   - Support for dumping functions ([`string.dump`]) and loading binary chunks has been removed.
 | 
				
			||||||
   - `math.random` now uses Lua 5.4's random number generator.
 | 
					   - [`math.random`] now uses Lua 5.4's random number generator.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
 | 
					 - File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,7 +44,7 @@ as documentation for breaking changes and "gotchas" one should look out for betw
 | 
				
			|||||||
   `keys.enter` constant was queued when the key was pressed)
 | 
					   `keys.enter` constant was queued when the key was pressed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
 | 
					 - Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
 | 
				
			||||||
   result `turtle.inspect` no longer provides block metadata, and `turtle.getItemDetail` no longer provides damage.
 | 
					   result [`turtle.inspect`] no longer provides block metadata, and [`turtle.getItemDetail`] no longer provides damage.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   - Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
 | 
					   - Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
 | 
				
			||||||
     more understandable format.
 | 
					     more understandable format.
 | 
				
			||||||
@@ -70,12 +70,12 @@ as documentation for breaking changes and "gotchas" one should look out for betw
 | 
				
			|||||||
 - Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
 | 
					 - Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## ComputerCraft 1.80pr1 {#cc-1.80}
 | 
					## ComputerCraft 1.80pr1 {#cc-1.80}
 | 
				
			||||||
 - Programs run via `shell.run` are now started in their own isolated environment. This means globals set by programs
 | 
					 - Programs run via [`shell.run`] are now started in their own isolated environment. This means globals set by programs
 | 
				
			||||||
   will not be accessible outside of this program.
 | 
					   will not be accessible outside of this program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
 | 
					 - Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
 | 
				
			||||||
   you can no longer type `turtle/excavate` to run `/rom/programs/turtle/excavate.lua`.
 | 
					   you can no longer type `turtle/excavate` to run `/rom/programs/turtle/excavate.lua`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[flattening]: https://minecraft.wiki/w/Java_Edition_1.13/Flattening
 | 
					[flattening]: https://minecraft.wiki/w/Java_Edition_1.13/Flattening
 | 
				
			||||||
[legal_data_pack]: https://minecraft.gamepedia.com/Tutorials/Creating_a_data_pack#Legal_characters
 | 
					[legal_data_pack]: https://minecraft.wiki/w/Tutorials/Creating_a_data_pack#Legal_characters
 | 
				
			||||||
[datapack-example]: https://github.com/cc-tweaked/datapack-example "An example datapack for CC: Tweaked"
 | 
					[datapack-example]: https://github.com/cc-tweaked/datapack-example "An example datapack for CC: Tweaked"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,7 +81,7 @@ compatibility for these newer versions.
 | 
				
			|||||||
| `string.dump` strip argument                                                          | ✔          |                           |
 | 
					| `string.dump` strip argument                                                          | ✔          |                           |
 | 
				
			||||||
| `string.pack`/`string.unpack`/`string.packsize`                                       | ✔          |                           |
 | 
					| `string.pack`/`string.unpack`/`string.packsize`                                       | ✔          |                           |
 | 
				
			||||||
| `table.move`                                                                          | ✔          |                           |
 | 
					| `table.move`                                                                          | ✔          |                           |
 | 
				
			||||||
| `math.atan2` -> `math.atan`                                                           | ❌         |                           |
 | 
					| `math.atan2` -> `math.atan`                                                           | 🔶         | `math.atan` supports its two argument form. |
 | 
				
			||||||
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌         |                           |
 | 
					| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌         |                           |
 | 
				
			||||||
| `math.maxinteger`/`math.mininteger`                                                   | ❌         |                           |
 | 
					| `math.maxinteger`/`math.mininteger`                                                   | ❌         |                           |
 | 
				
			||||||
| `math.tointeger`                                                                      | ❌         |                           |
 | 
					| `math.tointeger`                                                                      | ❌         |                           |
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
#
 | 
					#
 | 
				
			||||||
# SPDX-License-Identifier: MPL-2.0
 | 
					# SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
org.gradle.jvmargs=-Xmx3G
 | 
					org.gradle.jvmargs=-Xmx3G -Dfile.encoding=UTF-8
 | 
				
			||||||
org.gradle.parallel=true
 | 
					org.gradle.parallel=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kotlin.stdlib.default.dependency=false
 | 
					kotlin.stdlib.default.dependency=false
 | 
				
			||||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Mod properties
 | 
					# Mod properties
 | 
				
			||||||
isUnstable=false
 | 
					isUnstable=false
 | 
				
			||||||
modVersion=1.110.2
 | 
					modVersion=1.116.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
 | 
					# Minecraft properties: We want to configure this here so we can read it in settings.gradle
 | 
				
			||||||
mcVersion=1.20.1
 | 
					mcVersion=1.20.1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gradle/gradle-daemon-jvm.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								gradle/gradle-daemon-jvm.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#This file is generated by updateDaemonJvm
 | 
				
			||||||
 | 
					toolchainVersion=21
 | 
				
			||||||
@@ -23,17 +23,17 @@ netty = "4.1.82.Final"
 | 
				
			|||||||
slf4j = "2.0.1"
 | 
					slf4j = "2.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Core dependencies (independent of Minecraft)
 | 
					# Core dependencies (independent of Minecraft)
 | 
				
			||||||
asm = "9.6"
 | 
					asm = "9.9"
 | 
				
			||||||
autoService = "1.1.1"
 | 
					autoService = "1.1.1"
 | 
				
			||||||
checkerFramework = "3.42.0"
 | 
					checkerFramework = "3.51.1"
 | 
				
			||||||
cobalt = "0.9.2"
 | 
					cobalt = { strictly = "0.9.7" }
 | 
				
			||||||
commonsCli = "1.6.0"
 | 
					commonsCli = "1.10.0"
 | 
				
			||||||
jetbrainsAnnotations = "24.1.0"
 | 
					jetbrainsAnnotations = "26.0.2-1"
 | 
				
			||||||
jsr305 = "3.0.2"
 | 
					jspecify = "1.0.0"
 | 
				
			||||||
jzlib = "1.1.3"
 | 
					jzlib = "1.1.3"
 | 
				
			||||||
kotlin = "1.9.21"
 | 
					kotlin = "2.2.21"
 | 
				
			||||||
kotlin-coroutines = "1.7.3"
 | 
					kotlin-coroutines = "1.10.2"
 | 
				
			||||||
nightConfig = "3.6.7"
 | 
					nightConfig = "3.8.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Minecraft mods
 | 
					# Minecraft mods
 | 
				
			||||||
emi = "1.0.8+1.20.1"
 | 
					emi = "1.0.8+1.20.1"
 | 
				
			||||||
@@ -46,34 +46,35 @@ oculus = "1.2.5"
 | 
				
			|||||||
rei = "12.0.626"
 | 
					rei = "12.0.626"
 | 
				
			||||||
rubidium = "0.6.1"
 | 
					rubidium = "0.6.1"
 | 
				
			||||||
sodium = "mc1.20-0.4.10"
 | 
					sodium = "mc1.20-0.4.10"
 | 
				
			||||||
 | 
					create-forge = "6.0.0-9"
 | 
				
			||||||
 | 
					create-fabric = "6.0.7.0+mc1.20.1-build.1716"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Testing
 | 
					# Testing
 | 
				
			||||||
hamcrest = "2.2"
 | 
					hamcrest = "3.0"
 | 
				
			||||||
jqwik = "1.8.2"
 | 
					jqwik = "1.9.3"
 | 
				
			||||||
junit = "5.10.1"
 | 
					junit = "6.0.1"
 | 
				
			||||||
 | 
					junitPlatform = "6.0.1"
 | 
				
			||||||
jmh = "1.37"
 | 
					jmh = "1.37"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build tools
 | 
					# Build tools
 | 
				
			||||||
cctJavadoc = "1.8.2"
 | 
					cctJavadoc = "1.8.4"
 | 
				
			||||||
checkstyle = "10.14.1"
 | 
					checkstyle = "12.1.1"
 | 
				
			||||||
curseForgeGradle = "1.0.14"
 | 
					errorProne-core = "2.43.0"
 | 
				
			||||||
errorProne-core = "2.23.0"
 | 
					errorProne-plugin = "4.3.0"
 | 
				
			||||||
errorProne-plugin = "3.1.0"
 | 
					fabric-loom = "1.12.3"
 | 
				
			||||||
fabric-loom = "1.5.7"
 | 
					 | 
				
			||||||
forgeGradle = "6.0.20"
 | 
					 | 
				
			||||||
githubRelease = "2.5.2"
 | 
					githubRelease = "2.5.2"
 | 
				
			||||||
gradleVersions = "0.50.0"
 | 
					gradleVersions = "0.53.0"
 | 
				
			||||||
ideaExt = "1.1.7"
 | 
					ideaExt = "1.3"
 | 
				
			||||||
illuaminate = "0.1.0-71-g378d86e"
 | 
					illuaminate = "0.1.0-83-g1131f68"
 | 
				
			||||||
librarian = "1.+"
 | 
					lwjgl = "3.3.6"
 | 
				
			||||||
lwjgl = "3.3.3"
 | 
					minotaur = "2.8.7"
 | 
				
			||||||
minotaur = "2.+"
 | 
					modDevGradle = "2.0.116"
 | 
				
			||||||
nullAway = "0.10.25"
 | 
					nullAway = "0.12.11"
 | 
				
			||||||
spotless = "6.23.3"
 | 
					shadow = "9.2.2"
 | 
				
			||||||
taskTree = "2.1.1"
 | 
					spotless = "8.0.0"
 | 
				
			||||||
teavm = "0.10.0-SQUID.3"
 | 
					teavm = "0.13.0-SQUID.2"
 | 
				
			||||||
vanillaExtract = "0.1.2"
 | 
					vanillaExtract = "0.2.1"
 | 
				
			||||||
versionCatalogUpdate = "0.8.1"
 | 
					versionCatalogUpdate = "1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[libraries]
 | 
					[libraries]
 | 
				
			||||||
# Normal dependencies
 | 
					# Normal dependencies
 | 
				
			||||||
@@ -87,24 +88,27 @@ fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
 | 
				
			|||||||
forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
 | 
					forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
 | 
				
			||||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
 | 
					guava = { module = "com.google.guava:guava", version.ref = "guava" }
 | 
				
			||||||
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
 | 
					jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
 | 
				
			||||||
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
 | 
					jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
 | 
				
			||||||
jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
 | 
					jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
 | 
				
			||||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
 | 
					kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
 | 
				
			||||||
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
 | 
					kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
 | 
				
			||||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
 | 
					kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
 | 
				
			||||||
 | 
					netty-codec = { module = "io.netty:netty-codec", version.ref = "netty" }
 | 
				
			||||||
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
 | 
					netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
 | 
				
			||||||
netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
 | 
					 | 
				
			||||||
netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
 | 
					netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
 | 
				
			||||||
 | 
					netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
 | 
				
			||||||
nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
 | 
					nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
 | 
				
			||||||
nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
 | 
					nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
 | 
				
			||||||
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
 | 
					slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Minecraft mods
 | 
					# Minecraft mods
 | 
				
			||||||
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
 | 
					create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" }
 | 
				
			||||||
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
 | 
					create-forge = { module = "com.simibubi.create:create-1.20.1", version.ref = "create-forge" }
 | 
				
			||||||
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
 | 
					 | 
				
			||||||
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
 | 
					 | 
				
			||||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
 | 
					emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
 | 
				
			||||||
 | 
					fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
 | 
				
			||||||
 | 
					fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
 | 
				
			||||||
 | 
					fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
 | 
				
			||||||
 | 
					fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
 | 
				
			||||||
iris = { module = "maven.modrinth:iris", version.ref = "iris" }
 | 
					iris = { module = "maven.modrinth:iris", version.ref = "iris" }
 | 
				
			||||||
jei-api = { module = "mezz.jei:jei-1.20.1-common-api", version.ref = "jei" }
 | 
					jei-api = { module = "mezz.jei:jei-1.20.1-common-api", version.ref = "jei" }
 | 
				
			||||||
jei-fabric = { module = "mezz.jei:jei-1.20.1-fabric", version.ref = "jei" }
 | 
					jei-fabric = { module = "mezz.jei:jei-1.20.1-fabric", version.ref = "jei" }
 | 
				
			||||||
@@ -126,6 +130,7 @@ jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
 | 
				
			|||||||
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
 | 
					junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
 | 
				
			||||||
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
 | 
					junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
 | 
				
			||||||
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
 | 
					junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
 | 
				
			||||||
 | 
					junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitPlatform" }
 | 
				
			||||||
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
 | 
					slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
 | 
				
			||||||
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
 | 
					jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
 | 
				
			||||||
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
 | 
					jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
 | 
				
			||||||
@@ -139,21 +144,20 @@ lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw" }
 | 
				
			|||||||
# Build tools
 | 
					# Build tools
 | 
				
			||||||
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
 | 
					cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
 | 
				
			||||||
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
 | 
					checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
 | 
				
			||||||
curseForgeGradle = { module = "net.darkhax.curseforgegradle:CurseForgeGradle", version.ref = "curseForgeGradle" }
 | 
					 | 
				
			||||||
errorProne-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne-core" }
 | 
					errorProne-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne-core" }
 | 
				
			||||||
errorProne-api = { module = "com.google.errorprone:error_prone_check_api", version.ref = "errorProne-core" }
 | 
					errorProne-api = { module = "com.google.errorprone:error_prone_check_api", version.ref = "errorProne-core" }
 | 
				
			||||||
errorProne-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
 | 
					errorProne-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
 | 
				
			||||||
errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorProne-plugin" }
 | 
					errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorProne-plugin" }
 | 
				
			||||||
errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
 | 
					errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
 | 
				
			||||||
fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
 | 
					fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
 | 
				
			||||||
forgeGradle = { module = "net.minecraftforge.gradle:ForgeGradle", version.ref = "forgeGradle" }
 | 
					 | 
				
			||||||
ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
 | 
					ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
 | 
				
			||||||
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
 | 
					kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
 | 
				
			||||||
librarian = { module = "org.parchmentmc:librarian", version.ref = "librarian" }
 | 
					 | 
				
			||||||
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
 | 
					minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
 | 
				
			||||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
 | 
					nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
 | 
				
			||||||
 | 
					modDevGradle = { module = "net.neoforged:moddev-gradle", version.ref = "modDevGradle" }
 | 
				
			||||||
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
 | 
					spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
 | 
				
			||||||
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
 | 
					teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
 | 
				
			||||||
 | 
					teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
 | 
				
			||||||
teavm-jso = { module = "org.teavm:teavm-jso", version.ref = "teavm" }
 | 
					teavm-jso = { module = "org.teavm:teavm-jso", version.ref = "teavm" }
 | 
				
			||||||
teavm-jso-apis = { module = "org.teavm:teavm-jso-apis", version.ref = "teavm" }
 | 
					teavm-jso-apis = { module = "org.teavm:teavm-jso-apis", version.ref = "teavm" }
 | 
				
			||||||
teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
 | 
					teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
 | 
				
			||||||
@@ -165,16 +169,14 @@ vanillaExtract = { module = "cc.tweaked.vanilla-extract:plugin", version.ref = "
 | 
				
			|||||||
yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
 | 
					yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[plugins]
 | 
					[plugins]
 | 
				
			||||||
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
 | 
					 | 
				
			||||||
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
 | 
					githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
 | 
				
			||||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
 | 
					gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
 | 
				
			||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
 | 
					kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
 | 
				
			||||||
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
 | 
					shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
 | 
				
			||||||
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
 | 
					 | 
				
			||||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
 | 
					versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[bundles]
 | 
					[bundles]
 | 
				
			||||||
annotations = ["jsr305", "checkerFramework", "jetbrainsAnnotations"]
 | 
					annotations = ["checkerFramework", "jetbrainsAnnotations", "jspecify"]
 | 
				
			||||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
 | 
					kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Minecraft
 | 
					# Minecraft
 | 
				
			||||||
@@ -186,7 +188,7 @@ externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Testing
 | 
					# Testing
 | 
				
			||||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
 | 
					test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
 | 
				
			||||||
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]
 | 
					testRuntime = ["junit-jupiter-engine", "junit-platform-launcher", "jqwik-engine"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build tools
 | 
					# Build tools
 | 
				
			||||||
teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
 | 
					teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
				
			|||||||
distributionBase=GRADLE_USER_HOME
 | 
					distributionBase=GRADLE_USER_HOME
 | 
				
			||||||
distributionPath=wrapper/dists
 | 
					distributionPath=wrapper/dists
 | 
				
			||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
 | 
					distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
 | 
				
			||||||
networkTimeout=10000
 | 
					networkTimeout=10000
 | 
				
			||||||
validateDistributionUrl=true
 | 
					validateDistributionUrl=true
 | 
				
			||||||
zipStoreBase=GRADLE_USER_HOME
 | 
					zipStoreBase=GRADLE_USER_HOME
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								gradlew
									
									
									
									
										vendored
									
									
								
							@@ -15,6 +15,8 @@
 | 
				
			|||||||
# See the License for the specific language governing permissions and
 | 
					# See the License for the specific language governing permissions and
 | 
				
			||||||
# limitations under the License.
 | 
					# limitations under the License.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##############################################################################
 | 
					##############################################################################
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
@@ -55,7 +57,7 @@
 | 
				
			|||||||
#       Darwin, MinGW, and NonStop.
 | 
					#       Darwin, MinGW, and NonStop.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#   (3) This script is generated from the Groovy template
 | 
					#   (3) This script is generated from the Groovy template
 | 
				
			||||||
#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
					#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
 | 
				
			||||||
#       within the Gradle project.
 | 
					#       within the Gradle project.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#       You can find Gradle at https://github.com/gradle/gradle/.
 | 
					#       You can find Gradle at https://github.com/gradle/gradle/.
 | 
				
			||||||
@@ -84,7 +86,7 @@ done
 | 
				
			|||||||
# shellcheck disable=SC2034
 | 
					# shellcheck disable=SC2034
 | 
				
			||||||
APP_BASE_NAME=${0##*/}
 | 
					APP_BASE_NAME=${0##*/}
 | 
				
			||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
 | 
					# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
 | 
				
			||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
 | 
					APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
					# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
				
			||||||
MAX_FD=maximum
 | 
					MAX_FD=maximum
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradlew.bat
									
									
									
									
										vendored
									
									
								
							@@ -13,6 +13,8 @@
 | 
				
			|||||||
@rem See the License for the specific language governing permissions and
 | 
					@rem See the License for the specific language governing permissions and
 | 
				
			||||||
@rem limitations under the License.
 | 
					@rem limitations under the License.
 | 
				
			||||||
@rem
 | 
					@rem
 | 
				
			||||||
 | 
					@rem SPDX-License-Identifier: Apache-2.0
 | 
				
			||||||
 | 
					@rem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if "%DEBUG%"=="" @echo off
 | 
					@if "%DEBUG%"=="" @echo off
 | 
				
			||||||
@rem ##########################################################################
 | 
					@rem ##########################################################################
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1709
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1709
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -12,11 +12,11 @@
 | 
				
			|||||||
    "tslib": "^2.0.3"
 | 
					    "tslib": "^2.0.3"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@rollup/plugin-node-resolve": "^15.2.1",
 | 
					    "@rollup/plugin-node-resolve": "^16.0.0",
 | 
				
			||||||
    "@rollup/plugin-typescript": "^11.0.0",
 | 
					    "@rollup/plugin-typescript": "^12.0.0",
 | 
				
			||||||
    "@rollup/plugin-url": "^8.0.1",
 | 
					    "@rollup/plugin-url": "^8.0.1",
 | 
				
			||||||
    "@swc/core": "^1.3.92",
 | 
					    "@swc/core": "^1.3.92",
 | 
				
			||||||
    "@types/node": "^20.8.3",
 | 
					    "@types/node": "^24.0.0",
 | 
				
			||||||
    "lightningcss": "^1.22.0",
 | 
					    "lightningcss": "^1.22.0",
 | 
				
			||||||
    "preact-render-to-string": "^6.2.1",
 | 
					    "preact-render-to-string": "^6.2.1",
 | 
				
			||||||
    "rehype": "^13.0.0",
 | 
					    "rehype": "^13.0.0",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ plugins {
 | 
				
			|||||||
    id("cc-tweaked.vanilla")
 | 
					    id("cc-tweaked.vanilla")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val mcVersion: String by extra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
java {
 | 
					java {
 | 
				
			||||||
    withJavadocJar()
 | 
					    withJavadocJar()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -16,9 +18,70 @@ dependencies {
 | 
				
			|||||||
    api(project(":core-api"))
 | 
					    api(project(":core-api"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val javadocOverview by tasks.registering(Copy::class) {
 | 
				
			||||||
 | 
					    from("src/overview.html")
 | 
				
			||||||
 | 
					    into(layout.buildDirectory.dir(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expand(
 | 
				
			||||||
 | 
					        mapOf(
 | 
				
			||||||
 | 
					            "mcVersion" to mcVersion,
 | 
				
			||||||
 | 
					            "modVersion" to version,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.javadoc {
 | 
					tasks.javadoc {
 | 
				
			||||||
 | 
					    title = "CC: Tweaked $version for Minecraft $mcVersion"
 | 
				
			||||||
    include("dan200/computercraft/api/**/*.java")
 | 
					    include("dan200/computercraft/api/**/*.java")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options {
 | 
				
			||||||
 | 
					        (this as StandardJavadocDocletOptions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inputs.files(javadocOverview)
 | 
				
			||||||
 | 
					        overview(javadocOverview.get().destinationDir.resolve("overview.html").absolutePath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        groups = mapOf(
 | 
				
			||||||
 | 
					            "Common" to listOf(
 | 
				
			||||||
 | 
					                "dan200.computercraft.api",
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.lua",
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.peripheral",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            "Upgrades" to listOf(
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.client.turtle",
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.pocket",
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.turtle",
 | 
				
			||||||
 | 
					                "dan200.computercraft.api.upgrades",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        addBooleanOption("-allow-script-in-comments", true)
 | 
				
			||||||
 | 
					        bottom(
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
 | 
				
			||||||
 | 
					            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
 | 
				
			||||||
 | 
					            <link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
 | 
				
			||||||
 | 
					            """.trimIndent(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val snippetSources = listOf(":common", ":fabric", ":forge").flatMap {
 | 
				
			||||||
 | 
					            project(it).sourceSets["examples"].allSource.sourceDirectories
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        inputs.files(snippetSources)
 | 
				
			||||||
 | 
					        addPathOption("-snippet-path").value = snippetSources
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
 | 
					    // Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
 | 
				
			||||||
    source(project(":core-api").sourceSets.main.map { it.allJava })
 | 
					    source(project(":core-api").sourceSets.main.map { it.allJava })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options {
 | 
				
			||||||
 | 
					        this as StandardJavadocDocletOptions
 | 
				
			||||||
 | 
					        addBooleanOption("-allow-script-in-comments", true)
 | 
				
			||||||
 | 
					        bottom(
 | 
				
			||||||
 | 
					            """
 | 
				
			||||||
 | 
					            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
 | 
				
			||||||
 | 
					            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
 | 
				
			||||||
 | 
					            <link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
 | 
				
			||||||
 | 
					            """.trimIndent(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,8 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
 | 
				
			|||||||
import net.minecraft.client.resources.model.UnbakedModel;
 | 
					import net.minecraft.client.resources.model.UnbakedModel;
 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.Collection;
 | 
					import java.util.Collection;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -22,7 +22,14 @@ import java.util.List;
 | 
				
			|||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
 | 
					 * Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
 | 
				
			||||||
 * modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
 | 
					 * modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
 | 
				
			||||||
 * on Forge
 | 
					 * on Forge.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h2>Example</h2>
 | 
				
			||||||
 | 
					 * <h3>Fabric</h3>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h3>Forge</h3>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> The type of turtle upgrade this modeller applies to.
 | 
					 * @param <T> The type of turtle upgrade this modeller applies to.
 | 
				
			||||||
 * @see RegisterTurtleUpgradeModeller For multi-loader registration support.
 | 
					 * @see RegisterTurtleUpgradeModeller For multi-loader registration support.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,7 @@ import net.minecraft.client.Minecraft;
 | 
				
			|||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import org.joml.Matrix4f;
 | 
					import org.joml.Matrix4f;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
final class TurtleUpgradeModellers {
 | 
					final class TurtleUpgradeModellers {
 | 
				
			||||||
    private static final Transformation leftTransform = getMatrixFor(-0.4065f);
 | 
					    private static final Transformation leftTransform = getMatrixFor(-0.4065f);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,7 @@ import net.minecraft.client.resources.model.ModelManager;
 | 
				
			|||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
 | 
					import net.minecraft.client.resources.model.ModelResourceLocation;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ApiStatus.Internal
 | 
					@ApiStatus.Internal
 | 
				
			||||||
public interface ClientPlatformHelper {
 | 
					public interface ClientPlatformHelper {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
 | 
				
			|||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
 | 
					import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
 | 
				
			||||||
import dan200.computercraft.impl.Services;
 | 
					import dan200.computercraft.impl.Services;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Backing interface for {@link ComputerCraftAPIClient}
 | 
					 * Backing interface for {@link ComputerCraftAPIClient}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,9 +4,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package dan200.computercraft.api;
 | 
					package dan200.computercraft.api;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dan200.computercraft.api.component.ComputerComponent;
 | 
				
			||||||
import dan200.computercraft.api.filesystem.Mount;
 | 
					import dan200.computercraft.api.filesystem.Mount;
 | 
				
			||||||
import dan200.computercraft.api.filesystem.WritableMount;
 | 
					import dan200.computercraft.api.filesystem.WritableMount;
 | 
				
			||||||
import dan200.computercraft.api.lua.GenericSource;
 | 
					import dan200.computercraft.api.lua.GenericSource;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.lua.IComputerSystem;
 | 
				
			||||||
import dan200.computercraft.api.lua.ILuaAPI;
 | 
					import dan200.computercraft.api.lua.ILuaAPI;
 | 
				
			||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
					import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
				
			||||||
import dan200.computercraft.api.media.IMedia;
 | 
					import dan200.computercraft.api.media.IMedia;
 | 
				
			||||||
@@ -24,8 +26,7 @@ import net.minecraft.core.Direction;
 | 
				
			|||||||
import net.minecraft.server.MinecraftServer;
 | 
					import net.minecraft.server.MinecraftServer;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					import net.minecraft.world.level.Level;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The static entry point to the ComputerCraft API.
 | 
					 * The static entry point to the ComputerCraft API.
 | 
				
			||||||
@@ -165,7 +166,13 @@ public final class ComputerCraftAPI {
 | 
				
			|||||||
     * Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
 | 
					     * Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
 | 
				
			||||||
     * <p>
 | 
					     * <p>
 | 
				
			||||||
     * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
 | 
					     * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
 | 
				
			||||||
     * to use peripherals to provide functionality to users.
 | 
					     * to use peripherals to provide functionality to users. If an API is <em>required</em>, you may want to consider
 | 
				
			||||||
 | 
					     * using {@link ILuaAPI#getModuleName()} to expose this library as a module instead of as a global.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This may be used with {@link IComputerSystem#getComponent(ComputerComponent)} to only attach APIs to specific
 | 
				
			||||||
 | 
					     * computers. For example, one can add a new API just to turtles with the following code:
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * {@snippet class=com.example.examplemod.ExampleAPI region=register}
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param factory The factory for your API subclass.
 | 
					     * @param factory The factory for your API subclass.
 | 
				
			||||||
     * @see ILuaAPIFactory
 | 
					     * @see ILuaAPIFactory
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,20 @@ public class ComputerCraftTags {
 | 
				
			|||||||
        public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
 | 
					        public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
 | 
				
			||||||
        public static final TagKey<Item> MONITOR = make("monitor");
 | 
					        public static final TagKey<Item> MONITOR = make("monitor");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Floppy disks. Both the read/write version, and treasure disks.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * @since 1.116.0
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public static final TagKey<Item> DISKS = make("disks");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * All pocket computers.
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * @since 1.116.0
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        public static final TagKey<Item> POCKET_COMPUTERS = make("pocket_computers");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
 | 
					         * Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
 | 
				
			||||||
         * {@code turtle.place()}.
 | 
					         * {@code turtle.place()}.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dan200.computercraft.api.component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.minecraft.commands.CommandSourceStack;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A computer which has permission to perform administrative/op commands, such as the command computer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@ApiStatus.NonExtendable
 | 
				
			||||||
 | 
					public interface AdminComputer {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The permission level that this computer can operate at.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The permission level for this computer.
 | 
				
			||||||
 | 
					     * @see CommandSourceStack#hasPermission(int)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    default int permissionLevel() {
 | 
				
			||||||
 | 
					        return 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dan200.computercraft.api.component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dan200.computercraft.api.lua.IComputerSystem;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A component attached to a computer.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Components provide a mechanism to attach additional data to a computer, that can then be queried with
 | 
				
			||||||
 | 
					 * {@link IComputerSystem#getComponent(ComputerComponent)}.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * This is largely designed for {@linkplain ILuaAPIFactory custom APIs}, allowing APIs to read additional properties
 | 
				
			||||||
 | 
					 * of the computer, such as its position.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param <T> The type of this component.
 | 
				
			||||||
 | 
					 * @see ComputerComponents The built-in components.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@SuppressWarnings("UnusedTypeParameter")
 | 
				
			||||||
 | 
					public final class ComputerComponent<T> {
 | 
				
			||||||
 | 
					    private final String id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ComputerComponent(String id) {
 | 
				
			||||||
 | 
					        this.id = id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new computer component.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * Mods typically will not need to create their own components.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param namespace The namespace of this component. This should be the mod id.
 | 
				
			||||||
 | 
					     * @param id        The unique id of this component.
 | 
				
			||||||
 | 
					     * @param <T>       The component
 | 
				
			||||||
 | 
					     * @return The newly created component.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static <T> ComputerComponent<T> create(String namespace, String id) {
 | 
				
			||||||
 | 
					        return new ComputerComponent<>(namespace + ":" + id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String toString() {
 | 
				
			||||||
 | 
					        return "ComputerComponent(" + id + ")";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dan200.computercraft.api.component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dan200.computercraft.api.ComputerCraftAPI;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.pocket.IPocketAccess;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.turtle.ITurtleAccess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The {@link ComputerComponent}s provided by ComputerCraft.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ComputerComponents {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The {@link ITurtleAccess} associated with a turtle.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ComputerComponent<ITurtleAccess> TURTLE = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "turtle");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The {@link IPocketAccess} associated with a pocket computer.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ComputerComponent<IPocketAccess> POCKET = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "pocket");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This component is only present on "command computers", and other computers with admin capabilities.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final ComputerComponent<AdminComputer> ADMIN_COMPUTER = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "admin_computer");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,14 +6,14 @@ package dan200.computercraft.api.detail;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An item detail provider for {@link ItemStack}'s whose {@link Item} has a specific type.
 | 
					 * An item detail provider for {@link ItemStack}s whose {@link Item} has a specific type.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> The type the stack's item must have.
 | 
					 * @param <T> The type the stack's item must have.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -22,7 +22,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
 | 
				
			|||||||
    private final @Nullable String namespace;
 | 
					    private final @Nullable String namespace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a new item detail provider. Meta will be inserted into a new sub-map named as per {@code namespace}.
 | 
					     * Create a new item detail provider. Details will be inserted into a new sub-map named as per {@code namespace}.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param itemType  The type the stack's item must have.
 | 
					     * @param itemType  The type the stack's item must have.
 | 
				
			||||||
     * @param namespace The namespace to use for this provider.
 | 
					     * @param namespace The namespace to use for this provider.
 | 
				
			||||||
@@ -34,7 +34,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a new item detail provider. Meta will be inserted directly into the results.
 | 
					     * Create a new item detail provider. Details will be inserted directly into the results.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param itemType The type the stack's item must have.
 | 
					     * @param itemType The type the stack's item must have.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -53,21 +53,18 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
 | 
				
			|||||||
     * @param stack The item stack to provide details for.
 | 
					     * @param stack The item stack to provide details for.
 | 
				
			||||||
     * @param item  The item to provide details for.
 | 
					     * @param item  The item to provide details for.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public abstract void provideDetails(
 | 
					    public abstract void provideDetails(Map<? super String, Object> data, ItemStack stack, T item);
 | 
				
			||||||
        Map<? super String, Object> data, ItemStack stack, T item
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void provideDetails(Map<? super String, Object> data, ItemStack stack) {
 | 
					    public final void provideDetails(Map<? super String, Object> data, ItemStack stack) {
 | 
				
			||||||
        var item = stack.getItem();
 | 
					        var item = stack.getItem();
 | 
				
			||||||
        if (!itemType.isInstance(item)) return;
 | 
					        if (!itemType.isInstance(item)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // If `namespace` is specified, insert into a new data map instead of the existing one.
 | 
					        if (namespace == null) {
 | 
				
			||||||
        Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
 | 
					            provideDetails(data, stack, itemType.cast(item));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
        provideDetails(child, stack, itemType.cast(item));
 | 
					            Map<? super String, Object> child = new HashMap<>();
 | 
				
			||||||
 | 
					            provideDetails(child, stack, itemType.cast(item));
 | 
				
			||||||
        if (namespace != null) {
 | 
					 | 
				
			||||||
            data.put(namespace, child);
 | 
					            data.put(namespace, child);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,7 @@ import net.minecraft.core.BlockPos;
 | 
				
			|||||||
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 org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A reference to a block in the world, used by block detail providers.
 | 
					 * A reference to a block in the world, used by block detail providers.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,7 @@ import java.util.Map;
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> The type of object that this provider can provide details for.
 | 
					 * @param <T> The type of object that this provider can provide details for.
 | 
				
			||||||
 * @see DetailRegistry
 | 
					 * @see DetailRegistry
 | 
				
			||||||
 | 
					 * @see dan200.computercraft.api.detail An overview of the detail system.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@FunctionalInterface
 | 
					@FunctionalInterface
 | 
				
			||||||
public interface DetailProvider<T> {
 | 
					public interface DetailProvider<T> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@ import java.util.Map;
 | 
				
			|||||||
 * also in this package.
 | 
					 * also in this package.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> The type of object that this registry provides details for.
 | 
					 * @param <T> The type of object that this registry provides details for.
 | 
				
			||||||
 | 
					 * @see dan200.computercraft.api.detail An overview of the detail system.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ApiStatus.NonExtendable
 | 
					@ApiStatus.NonExtendable
 | 
				
			||||||
public interface DetailRegistry<T> {
 | 
					public interface DetailRegistry<T> {
 | 
				
			||||||
@@ -26,7 +27,7 @@ public interface DetailRegistry<T> {
 | 
				
			|||||||
     * @param provider The detail provider to register.
 | 
					     * @param provider The detail provider to register.
 | 
				
			||||||
     * @see DetailProvider
 | 
					     * @see DetailProvider
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void addProvider(DetailProvider<T> provider);
 | 
					    void addProvider(DetailProvider<? super T> provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
 | 
					     * Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,9 @@ public class VanillaDetailRegistries {
 | 
				
			|||||||
     * <p>
 | 
					     * <p>
 | 
				
			||||||
     * This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
 | 
					     * This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
 | 
				
			||||||
     * and may be called from the computer thread.
 | 
					     * and may be called from the computer thread.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This does not have special handling for {@linkplain ItemStack#isEmpty() empty item stacks}, and so the returned
 | 
				
			||||||
 | 
					     * details will be an empty stack of air. Callers should generally check for empty stacks before calling this.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
 | 
					    public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The detail system provides a standard way for mods to return descriptions of common game objects, such as blocks or
 | 
				
			||||||
 | 
					 * items, as well as registering additional detail to be included in those descriptions.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * For instance, the built-in {@code turtle.getItemDetail()} method uses
 | 
				
			||||||
 | 
					 * {@linkplain dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK in order to provide information about}
 | 
				
			||||||
 | 
					 * the selected item:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <pre class="language language-lua">{@code
 | 
				
			||||||
 | 
					 * local item = turtle.getItemDetail(nil, true)
 | 
				
			||||||
 | 
					 * --[[
 | 
				
			||||||
 | 
					 * item = {
 | 
				
			||||||
 | 
					 *   name = "minecraft:wheat",
 | 
				
			||||||
 | 
					 *   displayName = "Wheat",
 | 
				
			||||||
 | 
					 *   count = 1,
 | 
				
			||||||
 | 
					 *   maxCount = 64,
 | 
				
			||||||
 | 
					 *   tags = {},
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * ]]
 | 
				
			||||||
 | 
					 * }</pre>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h2>Built-in detail providers</h2>
 | 
				
			||||||
 | 
					 * While you can define your own detail providers (perhaps for types from your own mod), CC comes with several built-in
 | 
				
			||||||
 | 
					 * detail registries for vanilla and mod-loader objects:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <ul>
 | 
				
			||||||
 | 
					 *     <li>{@link dan200.computercraft.api.detail.VanillaDetailRegistries}, for vanilla objects</li>
 | 
				
			||||||
 | 
					 *     <li>{@code dan200.computercraft.api.detail.ForgeDetailRegistries} for Forge-specific objects</li>
 | 
				
			||||||
 | 
					 *     <li>{@code dan200.computercraft.api.detail.FabricDetailRegistries} for Fabric-specific objects</li>
 | 
				
			||||||
 | 
					 * </ul>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h2>Example: Returning details from methods</h2>
 | 
				
			||||||
 | 
					 * Here we define a {@code getHeldItem()} method for pocket computers which finds the currently held item of the player
 | 
				
			||||||
 | 
					 * and returns it to the user using {@link dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK} and
 | 
				
			||||||
 | 
					 * {@link dan200.computercraft.api.detail.DetailRegistry#getDetails(java.lang.Object)}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.ExamplePocketPeripheral region=details}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h2>Example: Registering custom detail registries</h2>
 | 
				
			||||||
 | 
					 * Here we define a new detail provider for items that includes the nutrition and saturation values in the returned object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.ExampleMod region=details}
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package dan200.computercraft.api.detail;
 | 
				
			||||||
@@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dan200.computercraft.api.lua;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dan200.computercraft.api.component.ComputerComponent;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.peripheral.IComputerAccess;
 | 
				
			||||||
 | 
					import net.minecraft.core.BlockPos;
 | 
				
			||||||
 | 
					import net.minecraft.server.level.ServerLevel;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * An interface passed to {@link ILuaAPIFactory} in order to provide additional information
 | 
				
			||||||
 | 
					 * about a computer.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@ApiStatus.NonExtendable
 | 
				
			||||||
 | 
					public interface IComputerSystem extends IComputerAccess {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the level this computer is currently in.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This method is not guaranteed to remain the same (even for stationary computers).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The computer's current level.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ServerLevel getLevel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the position this computer is currently at.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This method is not guaranteed to remain the same (even for stationary computers).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The computer's current position.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    BlockPos getPosition();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the label for this computer.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return This computer's label, or {@code null} if it is not set.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    String getLabel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a component attached to this computer.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * No component is guaranteed to be on a computer, and so this method should always be guarded with a null check.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * This method will always return the same value for a given component, and so may be cached.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param component The component to query.
 | 
				
			||||||
 | 
					     * @param <T>       The type of the component.
 | 
				
			||||||
 | 
					     * @return The component, if present.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    <T> @Nullable T getComponent(ComputerComponent<T> component);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,13 +4,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package dan200.computercraft.api.lua;
 | 
					package dan200.computercraft.api.lua;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					import dan200.computercraft.api.ComputerCraftAPI;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Construct an {@link ILuaAPI} for a specific computer.
 | 
					 * Construct an {@link ILuaAPI} for a computer.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @see ILuaAPI
 | 
					 * @see ILuaAPI
 | 
				
			||||||
 * @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
 | 
					 * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@FunctionalInterface
 | 
					@FunctionalInterface
 | 
				
			||||||
public interface ILuaAPIFactory {
 | 
					public interface ILuaAPIFactory {
 | 
				
			||||||
@@ -12,8 +12,7 @@ import net.minecraft.server.level.ServerLevel;
 | 
				
			|||||||
import net.minecraft.sounds.SoundEvent;
 | 
					import net.minecraft.sounds.SoundEvent;
 | 
				
			||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents an item that can be placed in a disk drive and used by a Computer.
 | 
					 * Represents an item that can be placed in a disk drive and used by a Computer.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,7 @@
 | 
				
			|||||||
package dan200.computercraft.api.media;
 | 
					package dan200.computercraft.api.media;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
 | 
					 * This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package dan200.computercraft.api.media;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dan200.computercraft.impl.ComputerCraftAPIService;
 | 
				
			||||||
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.stream.Stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * The contents of a page (or book) created by a ComputerCraft printer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @since 1.115
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Nullable
 | 
				
			||||||
 | 
					public interface PrintoutContents {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the (possibly empty) title for this printout.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The title of this printout.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    String getTitle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the text contents of this printout, as a sequence of lines.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * The lines in the printout may include blank lines at the end of the document, as well as trailing spaces on each
 | 
				
			||||||
 | 
					     * line.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The text contents of this printout.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Stream<String> getTextLines();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the printout contents for a particular stack.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param stack The stack to get the contents for.
 | 
				
			||||||
 | 
					     * @return The printout contents, or {@code null} if this is not a printout item.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    static @Nullable PrintoutContents get(ItemStack stack) {
 | 
				
			||||||
 | 
					        return ComputerCraftAPIService.get().getPrintoutContents(stack);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,13 +14,13 @@ import dan200.computercraft.api.ComputerCraftAPI;
 | 
				
			|||||||
 * as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
 | 
					 * as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
 | 
				
			||||||
 * for its lifespan.
 | 
					 * for its lifespan.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the
 | 
					 * Elements are generally tied to a block or block entity in world. In such as case, one should provide the
 | 
				
			||||||
 * {@link WiredElement} capability for the appropriate sides.
 | 
					 * {@link WiredElement} capability for the appropriate sides.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface WiredElement extends WiredSender {
 | 
					public interface WiredElement extends WiredSender {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Called when objects on the network change. This may occur when network nodes are added or removed, or when
 | 
					     * Called when peripherals on the network change. This may occur when network nodes are added or removed, or when
 | 
				
			||||||
     * peripherals change.
 | 
					     * peripherals are attached or detached from a modem.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param change The change which occurred.
 | 
					     * @param change The change which occurred.
 | 
				
			||||||
     * @see WiredNetworkChange
 | 
					     * @see WiredNetworkChange
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,18 +6,37 @@ package dan200.computercraft.api.pocket;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
					import dan200.computercraft.api.peripheral.IPeripheral;
 | 
				
			||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
					import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.upgrades.UpgradeData;
 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
 | 
					import net.minecraft.server.level.ServerLevel;
 | 
				
			||||||
import net.minecraft.world.entity.Entity;
 | 
					import net.minecraft.world.entity.Entity;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import net.minecraft.world.phys.Vec3;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Wrapper class for pocket computers.
 | 
					 * Wrapper class for pocket computers.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@ApiStatus.NonExtendable
 | 
				
			||||||
public interface IPocketAccess {
 | 
					public interface IPocketAccess {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the level in which the pocket computer exists.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The pocket computer's level.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ServerLevel getLevel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the position of the pocket computer.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The pocket computer's position.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    Vec3 getPosition();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the entity holding this item.
 | 
					     * Gets the entity holding this item.
 | 
				
			||||||
     * <p>
 | 
					     * <p>
 | 
				
			||||||
@@ -64,6 +83,26 @@ public interface IPocketAccess {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    void setLight(int colour);
 | 
					    void setLight(int colour);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the currently equipped upgrade.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return The currently equipped upgrade.
 | 
				
			||||||
 | 
					     * @see #getUpgradeNBTData()
 | 
				
			||||||
 | 
					     * @see #setUpgrade(UpgradeData)
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    UpgradeData<IPocketUpgrade> getUpgrade();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the upgrade for this pocket computer, also updating the item stack.
 | 
				
			||||||
 | 
					     * <p>
 | 
				
			||||||
 | 
					     * Note this method is not thread safe - it must be called from the server thread.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param upgrade The new upgrade to set it to, may be {@code null}.
 | 
				
			||||||
 | 
					     * @see #getUpgrade()
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void setUpgrade(@Nullable UpgradeData<IPocketUpgrade> upgrade);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the upgrade-specific NBT.
 | 
					     * Get the upgrade-specific NBT.
 | 
				
			||||||
     * <p>
 | 
					     * <p>
 | 
				
			||||||
@@ -73,6 +112,7 @@ public interface IPocketAccess {
 | 
				
			|||||||
     * @see #updateUpgradeNBTData()
 | 
					     * @see #updateUpgradeNBTData()
 | 
				
			||||||
     * @see UpgradeBase#getUpgradeItem(CompoundTag)
 | 
					     * @see UpgradeBase#getUpgradeItem(CompoundTag)
 | 
				
			||||||
     * @see UpgradeBase#getUpgradeData(ItemStack)
 | 
					     * @see UpgradeBase#getUpgradeData(ItemStack)
 | 
				
			||||||
 | 
					     * @see #getUpgrade()
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    CompoundTag getUpgradeNBTData();
 | 
					    CompoundTag getUpgradeNBTData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,20 +7,16 @@ package dan200.computercraft.api.pocket;
 | 
				
			|||||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
					import dan200.computercraft.api.peripheral.IPeripheral;
 | 
				
			||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
					import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					import net.minecraft.world.level.Level;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A peripheral which can be equipped to the back side of a pocket computer.
 | 
					 * A peripheral which can be equipped to the back side of a pocket computer.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * Pocket upgrades are defined in two stages. First, on creates a {@link IPocketUpgrade} subclass and corresponding
 | 
					 * Pocket upgrades are defined in two stages. First, on creates a {@link IPocketUpgrade} subclass and corresponding
 | 
				
			||||||
 * {@link PocketUpgradeSerialiser} instance, which are then registered in a Forge registry.
 | 
					 * {@link PocketUpgradeSerialiser} instance, which are then registered in a Minecraft registry.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
 | 
					 * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
 | 
				
			||||||
 * the upgrade registered internally. See the documentation in {@link PocketUpgradeSerialiser} for details on this process
 | 
					 * the upgrade registered internally.
 | 
				
			||||||
 * and where files should be located.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @see PocketUpgradeSerialiser For how to register a pocket computer upgrade.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface IPocketUpgrade extends UpgradeBase {
 | 
					public interface IPocketUpgrade extends UpgradeBase {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,7 @@ import net.minecraft.world.Container;
 | 
				
			|||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					import net.minecraft.world.level.Level;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The interface passed to turtle by turtles, providing methods that they can call.
 | 
					 * The interface passed to turtle by turtles, providing methods that they can call.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,21 +8,69 @@ import dan200.computercraft.api.peripheral.IPeripheral;
 | 
				
			|||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
					import dan200.computercraft.api.upgrades.UpgradeBase;
 | 
				
			||||||
import net.minecraft.core.Direction;
 | 
					import net.minecraft.core.Direction;
 | 
				
			||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
 | 
					import net.minecraft.world.item.Items;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					import java.util.function.BiFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
 | 
					 * The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
 | 
				
			||||||
 * peripheral.
 | 
					 * peripheral.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
 | 
					 * Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
 | 
				
			||||||
 * {@link TurtleUpgradeSerialiser} instance, which are then registered in a Forge registry.
 | 
					 * {@link TurtleUpgradeSerialiser} instance, which are then registered in a Minecraft registry.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
 | 
					 * You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
 | 
				
			||||||
 * the upgrade registered internally. See the documentation in {@link TurtleUpgradeSerialiser} for details on this process
 | 
					 * the upgrade automatically registered.
 | 
				
			||||||
 * and where files should be located.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @see TurtleUpgradeSerialiser For how to register a turtle upgrade.
 | 
					 * <h2>Example</h2>
 | 
				
			||||||
 | 
					 * <h3>Registering the upgrade serialiser</h3>
 | 
				
			||||||
 | 
					 * First, let's create a new class that implements {@link ITurtleUpgrade}. It is recommended to subclass
 | 
				
			||||||
 | 
					 * {@link AbstractTurtleUpgrade}, as that provides a default implementation of most methods.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.ExampleTurtleUpgrade region=body}
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Now we must construct a new upgrade serialiser. In most cases, you can use one of the helper methods
 | 
				
			||||||
 | 
					 * (e.g. {@link TurtleUpgradeSerialiser#simpleWithCustomItem(BiFunction)}), rather than defining your own implementation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.ExampleMod region=turtle_upgrades}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We now must register this upgrade serialiser. This is done the same way as you'd register blocks, items, or other
 | 
				
			||||||
 | 
					 * Minecraft objects. The approach to do this will depend on mod-loader.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h4>Fabric</h4>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.FabricExampleMod region=turtle_upgrades}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h4>Forge</h4>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.ForgeExampleMod region=turtle_upgrades}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h3>Rendering the upgrade</h3>
 | 
				
			||||||
 | 
					 * Next, we need to register a model for our upgrade. This is done by registering a
 | 
				
			||||||
 | 
					 * {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for your upgrade serialiser.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h4>Fabric</h4>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h4>Forge</h4>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * <h3>Registering the upgrade itself</h3>
 | 
				
			||||||
 | 
					 * Upgrades themselves are loaded from datapacks when a level is loaded. In order to register our new upgrade, we must
 | 
				
			||||||
 | 
					 * create a new JSON file at {@code data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet file = data/examplemod/computercraft/turtle_upgrades/example_turtle_upgrade.json}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The {@code "type"} field points to the ID of the upgrade serialiser we've just registered, while the other fields
 | 
				
			||||||
 | 
					 * are read by the serialiser itself. As our upgrade was defined with {@link TurtleUpgradeSerialiser#simpleWithCustomItem(BiFunction)}, the
 | 
				
			||||||
 | 
					 * {@code "item"} field will construct our upgrade with {@link Items#COMPASS}.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Rather than manually creating the file, it is recommended to data-generators to generate this file. This can be done
 | 
				
			||||||
 | 
					 * with {@link TurtleUpgradeDataProvider}.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see TurtleUpgradeSerialiser Registering a turtle upgrade.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public interface ITurtleUpgrade extends UpgradeBase {
 | 
					public interface ITurtleUpgrade extends UpgradeBase {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,7 @@
 | 
				
			|||||||
package dan200.computercraft.api.turtle;
 | 
					package dan200.computercraft.api.turtle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import net.minecraft.core.Direction;
 | 
					import net.minecraft.core.Direction;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Used to indicate the result of executing a turtle command.
 | 
					 * Used to indicate the result of executing a turtle command.
 | 
				
			||||||
@@ -60,9 +59,9 @@ public final class TurtleCommandResult {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private final boolean success;
 | 
					    private final boolean success;
 | 
				
			||||||
    private final @Nullable String errorMessage;
 | 
					    private final @Nullable String errorMessage;
 | 
				
			||||||
    private final @Nullable Object[] results;
 | 
					    private final @Nullable Object @Nullable [] results;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object[] results) {
 | 
					    private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object @Nullable [] results) {
 | 
				
			||||||
        this.success = success;
 | 
					        this.success = success;
 | 
				
			||||||
        this.errorMessage = errorMessage;
 | 
					        this.errorMessage = errorMessage;
 | 
				
			||||||
        this.results = results;
 | 
					        this.results = results;
 | 
				
			||||||
@@ -92,8 +91,7 @@ public final class TurtleCommandResult {
 | 
				
			|||||||
     *
 | 
					     *
 | 
				
			||||||
     * @return The command's result, or {@code null} if it was a failure.
 | 
					     * @return The command's result, or {@code null} if it was a failure.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @Nullable
 | 
					    public @Nullable Object @Nullable [] getResults() {
 | 
				
			||||||
    public Object[] getResults() {
 | 
					 | 
				
			||||||
        return results;
 | 
					        return results;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
package dan200.computercraft.api.turtle;
 | 
					package dan200.computercraft.api.turtle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An enum representing the two sides of the turtle that a turtle turtle might reside.
 | 
					 * An enum representing the two sides of the turtle that a turtle upgrade might reside.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public enum TurtleSide {
 | 
					public enum TurtleSide {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,8 @@ import net.minecraft.world.entity.ai.attributes.Attributes;
 | 
				
			|||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import net.minecraft.world.level.block.Block;
 | 
					import net.minecraft.world.level.block.Block;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -29,6 +29,9 @@ import java.util.function.Consumer;
 | 
				
			|||||||
 * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
 | 
					 * {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
 | 
				
			||||||
 * generate them.
 | 
					 * generate them.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * <h2>Example</h2>
 | 
				
			||||||
 | 
					 * {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @see TurtleUpgradeSerialiser
 | 
					 * @see TurtleUpgradeSerialiser
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> {
 | 
					public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,32 +27,6 @@ import java.util.function.Function;
 | 
				
			|||||||
 * If your turtle upgrade doesn't have any associated configurable parameters (like most upgrades), you can use
 | 
					 * If your turtle upgrade doesn't have any associated configurable parameters (like most upgrades), you can use
 | 
				
			||||||
 * {@link #simple(Function)} or {@link #simpleWithCustomItem(BiFunction)} to create a basic upgrade serialiser.
 | 
					 * {@link #simple(Function)} or {@link #simpleWithCustomItem(BiFunction)} to create a basic upgrade serialiser.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * <h2>Example (Forge)</h2>
 | 
					 | 
				
			||||||
 * <pre>{@code
 | 
					 | 
				
			||||||
 * static final DeferredRegister<TurtleUpgradeSerialiser<?>> SERIALISERS = DeferredRegister.create( TurtleUpgradeSerialiser.TYPE, "my_mod" );
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * // Register a new upgrade serialiser called "my_upgrade".
 | 
					 | 
				
			||||||
 * public static final RegistryObject<TurtleUpgradeSerialiser<MyUpgrade>> MY_UPGRADE =
 | 
					 | 
				
			||||||
 *     SERIALISERS.register( "my_upgrade", () -> TurtleUpgradeSerialiser.simple( MyUpgrade::new ) );
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * // Then in your constructor
 | 
					 | 
				
			||||||
 * SERIALISERS.register( bus );
 | 
					 | 
				
			||||||
 * }</pre>
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * We can then define a new upgrade using JSON by placing the following in
 | 
					 | 
				
			||||||
 * {@literal data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}}.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * <pre>{@code
 | 
					 | 
				
			||||||
 * {
 | 
					 | 
				
			||||||
 *     "type": my_mod:my_upgrade",
 | 
					 | 
				
			||||||
 * }
 | 
					 | 
				
			||||||
 * }</pre>
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Finally, we need to register a model for our upgrade. The way to do this varies on mod loader, see
 | 
					 | 
				
			||||||
 * {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param <T> The type of turtle upgrade this is responsible for serialising.
 | 
					 * @param <T> The type of turtle upgrade this is responsible for serialising.
 | 
				
			||||||
 * @see ITurtleUpgrade
 | 
					 * @see ITurtleUpgrade
 | 
				
			||||||
 * @see TurtleUpgradeDataProvider
 | 
					 * @see TurtleUpgradeDataProvider
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,8 +9,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
 | 
				
			|||||||
import net.minecraft.nbt.CompoundTag;
 | 
					import net.minecraft.nbt.CompoundTag;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import org.jetbrains.annotations.Contract;
 | 
					import org.jetbrains.annotations.Contract;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
 | 
					 * An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,8 @@ import net.minecraft.data.PackOutput;
 | 
				
			|||||||
import net.minecraft.resources.ResourceKey;
 | 
					import net.minecraft.resources.ResourceKey;
 | 
				
			||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.concurrent.CompletableFuture;
 | 
					import java.util.concurrent.CompletableFuture;
 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
@@ -32,6 +32,8 @@ import java.util.function.Function;
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> The base class of upgrades.
 | 
					 * @param <T> The base class of upgrades.
 | 
				
			||||||
 * @param <R> The upgrade serialiser to register for.
 | 
					 * @param <R> The upgrade serialiser to register for.
 | 
				
			||||||
 | 
					 * @see dan200.computercraft.api.turtle.TurtleUpgradeDataProvider
 | 
				
			||||||
 | 
					 * @see dan200.computercraft.api.pocket.PocketUpgradeDataProvider
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider {
 | 
					public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider {
 | 
				
			||||||
    private final PackOutput output;
 | 
					    private final PackOutput output;
 | 
				
			||||||
@@ -84,13 +86,9 @@ public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends Upgra
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Add all turtle or pocket computer upgrades.
 | 
					     * Add all turtle or pocket computer upgrades.
 | 
				
			||||||
     * <p>
 | 
					     *
 | 
				
			||||||
     * <strong>Example usage:</strong>
 | 
					     * <h4>Example</h4>
 | 
				
			||||||
     * <pre>{@code
 | 
					     * {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
 | 
				
			||||||
     * protected void addUpgrades(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> addUpgrade) {
 | 
					 | 
				
			||||||
     *     simple(new ResourceLocation("mymod", "speaker"), SPEAKER_SERIALISER.get()).add(addUpgrade);
 | 
					 | 
				
			||||||
     * }
 | 
					 | 
				
			||||||
     * }</pre>
 | 
					 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param addUpgrade A callback used to register an upgrade.
 | 
					     * @param addUpgrade A callback used to register an upgrade.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import dan200.computercraft.api.filesystem.WritableMount;
 | 
				
			|||||||
import dan200.computercraft.api.lua.GenericSource;
 | 
					import dan200.computercraft.api.lua.GenericSource;
 | 
				
			||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
					import dan200.computercraft.api.lua.ILuaAPIFactory;
 | 
				
			||||||
import dan200.computercraft.api.media.MediaProvider;
 | 
					import dan200.computercraft.api.media.MediaProvider;
 | 
				
			||||||
 | 
					import dan200.computercraft.api.media.PrintoutContents;
 | 
				
			||||||
import dan200.computercraft.api.network.PacketNetwork;
 | 
					import dan200.computercraft.api.network.PacketNetwork;
 | 
				
			||||||
import dan200.computercraft.api.network.wired.WiredElement;
 | 
					import dan200.computercraft.api.network.wired.WiredElement;
 | 
				
			||||||
import dan200.computercraft.api.network.wired.WiredNode;
 | 
					import dan200.computercraft.api.network.wired.WiredNode;
 | 
				
			||||||
@@ -27,8 +28,7 @@ import net.minecraft.server.MinecraftServer;
 | 
				
			|||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import net.minecraft.world.level.Level;
 | 
					import net.minecraft.world.level.Level;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Backing interface for {@link ComputerCraftAPI}
 | 
					 * Backing interface for {@link ComputerCraftAPI}
 | 
				
			||||||
@@ -75,6 +75,9 @@ public interface ComputerCraftAPIService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    DetailRegistry<BlockReference> getBlockInWorldDetailRegistry();
 | 
					    DetailRegistry<BlockReference> getBlockInWorldDetailRegistry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    PrintoutContents getPrintoutContents(ItemStack stack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final class Instance {
 | 
					    final class Instance {
 | 
				
			||||||
        static final @Nullable ComputerCraftAPIService INSTANCE;
 | 
					        static final @Nullable ComputerCraftAPIService INSTANCE;
 | 
				
			||||||
        static final @Nullable Throwable ERROR;
 | 
					        static final @Nullable Throwable ERROR;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,7 @@ import net.minecraft.resources.ResourceKey;
 | 
				
			|||||||
import net.minecraft.resources.ResourceLocation;
 | 
					import net.minecraft.resources.ResourceLocation;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Abstraction layer for Forge and Fabric. See implementations for more details.
 | 
					 * Abstraction layer for Forge and Fabric. See implementations for more details.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@
 | 
				
			|||||||
package dan200.computercraft.impl;
 | 
					package dan200.computercraft.impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.io.Serial;
 | 
					import java.io.Serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@
 | 
				
			|||||||
package dan200.computercraft.impl;
 | 
					package dan200.computercraft.impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.jetbrains.annotations.ApiStatus;
 | 
					import org.jetbrains.annotations.ApiStatus;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.ServiceLoader;
 | 
					import java.util.ServiceLoader;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								projects/common-api/src/overview.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								projects/common-api/src/overview.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					<!--
 | 
				
			||||||
 | 
					SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPDX-License-Identifier: MPL-2.0
 | 
				
			||||||
 | 
					-->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!DOCTYPE HTML>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					    This is the documentation for CC: Tweaked $modVersion for Minecraft $mcVersion. Documentation for other versions of
 | 
				
			||||||
 | 
					    Minecraft are available on the CC: Tweaked website:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					    <li><a href="/mc-1.20.x/javadoc/">Minecraft 1.20.1</a>
 | 
				
			||||||
 | 
					    <li><a href="/mc-1.21.x/javadoc/">Minecraft 1.21.1</a>
 | 
				
			||||||
 | 
					</ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h1>Quick links</h1>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					    You probably want to start in the following places:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<ul>
 | 
				
			||||||
 | 
					    <li>{@linkplain dan200.computercraft.api.peripheral Registering new peripherals}</li>
 | 
				
			||||||
 | 
					    <li>
 | 
				
			||||||
 | 
					        {@link dan200.computercraft.api.lua.LuaFunction} and {@link dan200.computercraft.api.lua.IArguments} for
 | 
				
			||||||
 | 
					        adding methods to your peripheral or Lua objects.
 | 
				
			||||||
 | 
					    </li>
 | 
				
			||||||
 | 
					    <li>{@linkplain dan200.computercraft.api.turtle.ITurtleUpgrade Turtle upgrades}</li>
 | 
				
			||||||
 | 
					    <li>{@linkplain dan200.computercraft.api.pocket.IPocketUpgrade Pocket upgrades}</li>
 | 
				
			||||||
 | 
					</ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<h1>Using</h1>
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					    CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or
 | 
				
			||||||
 | 
					    hard) dependency in your <code>mods.toml</code> file, with the appropriate version bounds, to ensure that API
 | 
				
			||||||
 | 
					    functionality you depend on is present.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre class="language language-groovy"><code>repositories {
 | 
				
			||||||
 | 
					    maven {
 | 
				
			||||||
 | 
					        url "https://maven.squiddev.cc"
 | 
				
			||||||
 | 
					        content { includeGroup("cc.tweaked") }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					    // Vanilla (i.e. for multi-loader systems)
 | 
				
			||||||
 | 
					    compileOnly("cc.tweaked:cc-tweaked-$mcVersion-common-api:$modVersion")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Forge Gradle
 | 
				
			||||||
 | 
					    compileOnly("cc.tweaked:cc-tweaked-$mcVersion-core-api:$modVersion")
 | 
				
			||||||
 | 
					    compileOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge-api:$modVersion"))
 | 
				
			||||||
 | 
					    runtimeOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge:$modVersion"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Fabric Loom
 | 
				
			||||||
 | 
					    modCompileOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric-api:$modVersion")
 | 
				
			||||||
 | 
					    modRuntimeOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric:$modVersion")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</code></pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p>
 | 
				
			||||||
 | 
					    You should also be careful to only use classes within the <code>dan200.computercraft.api</code> package. Non-API
 | 
				
			||||||
 | 
					    classes are subject to change at any point. If you depend on functionality outside the API (or need to mixin to
 | 
				
			||||||
 | 
					    CC:T), please <a href="https://github.com/cc-tweaked/CC-Tweaked/discussions/new/choose">start a discussion</a> to
 | 
				
			||||||
 | 
					    let me know!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
@@ -6,8 +6,8 @@ import cc.tweaked.gradle.*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
    id("cc-tweaked.vanilla")
 | 
					    id("cc-tweaked.vanilla")
 | 
				
			||||||
    id("cc-tweaked.gametest")
 | 
					 | 
				
			||||||
    id("cc-tweaked.illuaminate")
 | 
					    id("cc-tweaked.illuaminate")
 | 
				
			||||||
 | 
					    id("cc-tweaked.mod")
 | 
				
			||||||
    id("cc-tweaked.publishing")
 | 
					    id("cc-tweaked.publishing")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,9 +32,9 @@ repositories {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
    // Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
 | 
					    // Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
 | 
				
			||||||
    implementation(project(":core"))
 | 
					    api(project(":core"))
 | 
				
			||||||
    implementation(commonClasses(project(":common-api")))
 | 
					    api(commonClasses(project(":common-api")))
 | 
				
			||||||
    clientImplementation(clientClasses(project(":common-api")))
 | 
					    clientApi(clientClasses(project(":common-api")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    compileOnly(libs.bundles.externalMods.common)
 | 
					    compileOnly(libs.bundles.externalMods.common)
 | 
				
			||||||
    clientCompileOnly(variantOf(libs.emi) { classifier("api") })
 | 
					    clientCompileOnly(variantOf(libs.emi) { classifier("api") })
 | 
				
			||||||
@@ -60,7 +60,7 @@ dependencies {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
illuaminate {
 | 
					illuaminate {
 | 
				
			||||||
    version.set(libs.versions.illuaminate)
 | 
					    version = libs.versions.illuaminate
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val luaJavadoc by tasks.registering(Javadoc::class) {
 | 
					val luaJavadoc by tasks.registering(Javadoc::class) {
 | 
				
			||||||
@@ -81,11 +81,7 @@ val luaJavadoc by tasks.registering(Javadoc::class) {
 | 
				
			|||||||
    options.addStringOption("project-root", rootProject.file(".").absolutePath)
 | 
					    options.addStringOption("project-root", rootProject.file(".").absolutePath)
 | 
				
			||||||
    options.noTimestamp(false)
 | 
					    options.noTimestamp(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    javadocTool.set(
 | 
					    javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JDK_VERSION }
 | 
				
			||||||
        javaToolchains.javadocToolFor {
 | 
					 | 
				
			||||||
            languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val lintLua by tasks.registering(IlluaminateExec::class) {
 | 
					val lintLua by tasks.registering(IlluaminateExec::class) {
 | 
				
			||||||
@@ -105,3 +101,32 @@ val lintLua by tasks.registering(IlluaminateExec::class) {
 | 
				
			|||||||
    doFirst { if (System.getenv("GITHUB_ACTIONS") != null) println("::add-matcher::.github/matchers/illuaminate.json") }
 | 
					    doFirst { if (System.getenv("GITHUB_ACTIONS") != null) println("::add-matcher::.github/matchers/illuaminate.json") }
 | 
				
			||||||
    doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
 | 
					    doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun MergeTrees.configureForDatagen(source: SourceSet, outputFolder: String) {
 | 
				
			||||||
 | 
					    output = layout.projectDirectory.dir(outputFolder)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (loader in listOf("forge", "fabric")) {
 | 
				
			||||||
 | 
					        mustRunAfter(":$loader:$name")
 | 
				
			||||||
 | 
					        source {
 | 
				
			||||||
 | 
					            input {
 | 
				
			||||||
 | 
					                from(project(":$loader").layout.buildDirectory.dir(source.getTaskName("generateResources", null)))
 | 
				
			||||||
 | 
					                exclude(".cache")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            output = project(":$loader").layout.projectDirectory.dir(outputFolder)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val runData by tasks.registering(MergeTrees::class) {
 | 
				
			||||||
 | 
					    configureForDatagen(sourceSets.main.get(), "src/generated/resources")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val runExampleData by tasks.registering(MergeTrees::class) {
 | 
				
			||||||
 | 
					    configureForDatagen(sourceSets.examples.get(), "src/examples/generatedResources")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// We can't create accurate module metadata for our additional capabilities, so disable it.
 | 
				
			||||||
 | 
					project.tasks.withType(GenerateModuleMetadata::class.java).configureEach {
 | 
				
			||||||
 | 
					    isEnabled = false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,8 +38,8 @@ import net.minecraft.world.item.ItemStack;
 | 
				
			|||||||
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.minecraft.world.phys.HitResult;
 | 
					import net.minecraft.world.phys.HitResult;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -64,6 +64,9 @@ public final class ClientHooks {
 | 
				
			|||||||
    public static void onWorldUnload() {
 | 
					    public static void onWorldUnload() {
 | 
				
			||||||
        MonitorRenderState.destroyAll();
 | 
					        MonitorRenderState.destroyAll();
 | 
				
			||||||
        SpeakerManager.reset();
 | 
					        SpeakerManager.reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static void onDisconnect() {
 | 
				
			||||||
        ClientPocketComputers.reset();
 | 
					        ClientPocketComputers.reset();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
 | 
				
			|||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
 | 
					import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
 | 
				
			||||||
import dan200.computercraft.client.gui.*;
 | 
					import dan200.computercraft.client.gui.*;
 | 
				
			||||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
 | 
					import dan200.computercraft.client.pocket.ClientPocketComputers;
 | 
				
			||||||
 | 
					import dan200.computercraft.client.render.CustomLecternRenderer;
 | 
				
			||||||
import dan200.computercraft.client.render.RenderTypes;
 | 
					import dan200.computercraft.client.render.RenderTypes;
 | 
				
			||||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
 | 
					import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
 | 
				
			||||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
 | 
					import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
 | 
				
			||||||
@@ -25,7 +26,6 @@ import dan200.computercraft.shared.common.IColouredItem;
 | 
				
			|||||||
import dan200.computercraft.shared.computer.core.ComputerState;
 | 
					import dan200.computercraft.shared.computer.core.ComputerState;
 | 
				
			||||||
import dan200.computercraft.shared.computer.core.ServerContext;
 | 
					import dan200.computercraft.shared.computer.core.ServerContext;
 | 
				
			||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
 | 
					import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
 | 
				
			||||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
 | 
					 | 
				
			||||||
import dan200.computercraft.shared.media.items.DiskItem;
 | 
					import dan200.computercraft.shared.media.items.DiskItem;
 | 
				
			||||||
import dan200.computercraft.shared.media.items.TreasureDiskItem;
 | 
					import dan200.computercraft.shared.media.items.TreasureDiskItem;
 | 
				
			||||||
import net.minecraft.Util;
 | 
					import net.minecraft.Util;
 | 
				
			||||||
@@ -46,8 +46,10 @@ import net.minecraft.world.entity.LivingEntity;
 | 
				
			|||||||
import net.minecraft.world.item.Item;
 | 
					import net.minecraft.world.item.Item;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
import net.minecraft.world.level.ItemLike;
 | 
					import net.minecraft.world.level.ItemLike;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.function.BiConsumer;
 | 
					import java.util.function.BiConsumer;
 | 
				
			||||||
@@ -63,6 +65,8 @@ import java.util.function.Supplier;
 | 
				
			|||||||
 * @see ModRegistry The common registry for actual game objects.
 | 
					 * @see ModRegistry The common registry for actual game objects.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class ClientRegistry {
 | 
					public final class ClientRegistry {
 | 
				
			||||||
 | 
					    private static final Logger LOG = LoggerFactory.getLogger(ClientRegistry.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ClientRegistry() {
 | 
					    private ClientRegistry() {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,6 +78,7 @@ public final class ClientRegistry {
 | 
				
			|||||||
        BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), MonitorBlockEntityRenderer::new);
 | 
					        BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), MonitorBlockEntityRenderer::new);
 | 
				
			||||||
        BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TurtleBlockEntityRenderer::new);
 | 
					        BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TurtleBlockEntityRenderer::new);
 | 
				
			||||||
        BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TurtleBlockEntityRenderer::new);
 | 
					        BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TurtleBlockEntityRenderer::new);
 | 
				
			||||||
 | 
					        BlockEntityRenderers.register(ModRegistry.BlockEntities.LECTERN.get(), CustomLecternRenderer::new);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -83,7 +88,6 @@ public final class ClientRegistry {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public static void registerMainThread(RegisterItemProperty itemProperties) {
 | 
					    public static void registerMainThread(RegisterItemProperty itemProperties) {
 | 
				
			||||||
        MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
 | 
					        MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
 | 
				
			||||||
        MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), ComputerScreen::new);
 | 
					 | 
				
			||||||
        MenuScreens.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
 | 
					        MenuScreens.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
 | 
				
			||||||
        MenuScreens.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
 | 
					        MenuScreens.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,8 +95,6 @@ public final class ClientRegistry {
 | 
				
			|||||||
        MenuScreens.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new);
 | 
					        MenuScreens.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new);
 | 
				
			||||||
        MenuScreens.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new);
 | 
					        MenuScreens.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        MenuScreens.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        registerItemProperty(itemProperties, "state",
 | 
					        registerItemProperty(itemProperties, "state",
 | 
				
			||||||
            new UnclampedPropertyFunction((stack, world, player, random) -> {
 | 
					            new UnclampedPropertyFunction((stack, world, player, random) -> {
 | 
				
			||||||
                var computer = ClientPocketComputers.get(stack);
 | 
					                var computer = ClientPocketComputers.get(stack);
 | 
				
			||||||
@@ -184,7 +186,18 @@ public final class ClientRegistry {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
 | 
					    public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
 | 
				
			||||||
        RenderTypes.registerShaders(resources, load);
 | 
					        RenderTypes.registerShaders(resources, (name, create, onLoaded) -> {
 | 
				
			||||||
 | 
					            ShaderInstance shader;
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                shader = create.get();
 | 
				
			||||||
 | 
					            } catch (Exception e) {
 | 
				
			||||||
 | 
					                LOG.error("Failed to load {}", name, e);
 | 
				
			||||||
 | 
					                onLoaded.accept(null);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            load.accept(shader, onLoaded);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private record UnclampedPropertyFunction(
 | 
					    private record UnclampedPropertyFunction(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,8 +15,8 @@ import net.minecraft.client.gui.components.ChatComponent;
 | 
				
			|||||||
import net.minecraft.network.chat.Component;
 | 
					import net.minecraft.network.chat.Component;
 | 
				
			||||||
import net.minecraft.util.Mth;
 | 
					import net.minecraft.util.Mth;
 | 
				
			||||||
import org.apache.commons.lang3.StringUtils;
 | 
					import org.apache.commons.lang3.StringUtils;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,11 +26,11 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
 | 
				
			|||||||
import net.minecraft.network.chat.Component;
 | 
					import net.minecraft.network.chat.Component;
 | 
				
			||||||
import net.minecraft.world.entity.player.Inventory;
 | 
					import net.minecraft.world.entity.player.Inventory;
 | 
				
			||||||
import net.minecraft.world.item.ItemStack;
 | 
					import net.minecraft.world.item.ItemStack;
 | 
				
			||||||
 | 
					import org.jspecify.annotations.Nullable;
 | 
				
			||||||
import org.lwjgl.glfw.GLFW;
 | 
					import org.lwjgl.glfw.GLFW;
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.ByteBuffer;
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,10 +10,10 @@ import dan200.computercraft.shared.computer.menu.ComputerMenu;
 | 
				
			|||||||
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
 | 
					import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
 | 
				
			||||||
import dan200.computercraft.shared.network.server.KeyEventServerMessage;
 | 
					import dan200.computercraft.shared.network.server.KeyEventServerMessage;
 | 
				
			||||||
import dan200.computercraft.shared.network.server.MouseEventServerMessage;
 | 
					import dan200.computercraft.shared.network.server.MouseEventServerMessage;
 | 
				
			||||||
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
 | 
					import dan200.computercraft.shared.network.server.PasteEventComputerMessage;
 | 
				
			||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
 | 
					import net.minecraft.world.inventory.AbstractContainerMenu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Nullable;
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * An {@link InputHandler} for use on the client.
 | 
					 * An {@link InputHandler} for use on the client.
 | 
				
			||||||
@@ -27,6 +27,11 @@ public final class ClientInputHandler implements InputHandler {
 | 
				
			|||||||
        this.menu = menu;
 | 
					        this.menu = menu;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void terminate() {
 | 
				
			||||||
 | 
					        ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TERMINATE));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void turnOn() {
 | 
					    public void turnOn() {
 | 
				
			||||||
        ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
 | 
					        ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
 | 
				
			||||||
@@ -42,38 +47,43 @@ public final class ClientInputHandler implements InputHandler {
 | 
				
			|||||||
        ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
 | 
					        ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void queueEvent(String event, @Nullable Object[] arguments) {
 | 
					 | 
				
			||||||
        ClientNetworking.sendToServer(new QueueEventServerMessage(menu, event, arguments));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void keyDown(int key, boolean repeat) {
 | 
					    public void keyDown(int key, boolean repeat) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key));
 | 
					        ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.Action.REPEAT : KeyEventServerMessage.Action.DOWN, key));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void keyUp(int key) {
 | 
					    public void keyUp(int key) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
 | 
					        ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.UP, key));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void charTyped(byte chr) {
 | 
				
			||||||
 | 
					        ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.CHAR, chr));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void paste(ByteBuffer contents) {
 | 
				
			||||||
 | 
					        ClientNetworking.sendToServer(new PasteEventComputerMessage(menu, contents));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void mouseClick(int button, int x, int y) {
 | 
					    public void mouseClick(int button, int x, int y) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_CLICK, button, x, y));
 | 
					        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.CLICK, button, x, y));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void mouseUp(int button, int x, int y) {
 | 
					    public void mouseUp(int button, int x, int y) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_UP, button, x, y));
 | 
					        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.UP, button, x, y));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void mouseDrag(int button, int x, int y) {
 | 
					    public void mouseDrag(int button, int x, int y) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_DRAG, button, x, y));
 | 
					        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.DRAG, button, x, y));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void mouseScroll(int direction, int x, int y) {
 | 
					    public void mouseScroll(int direction, int x, int y) {
 | 
				
			||||||
        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
 | 
					        ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.SCROLL, direction, x, y));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user