@@ -765,6 +765,42 @@ tasks.register('isolateEclipseProductionRuns') {
765765 ' <booleanAttribute key="org.eclipse.jdt.launching.ATTR_EXCLUDE_TEST_CODE" value="true"/>'
766766 contents = contents. replace(marker, attribute + ' \n ' + marker)
767767 }
768+
769+ // Buildship exposes compileOnly dependencies through its project
770+ // container. Replace that container in production launches with
771+ // Gradle's actual runtime classpath so API-only jars cannot be
772+ // discovered by FML as installed mods.
773+ Set<File > mainOutputs = sourceSets. main. output. files. collect {
774+ it. canonicalFile
775+ } as Set<File >
776+ List<File > productionRuntime = configurations. runtimeClasspath. files. collect {
777+ it. canonicalFile
778+ }. findAll { File runtimeFile ->
779+ ! mainOutputs. contains(runtimeFile)
780+ }. sort { File left , File right ->
781+ left. canonicalPath <=> right. canonicalPath
782+ }
783+ List<String > launchLines = contents. readLines()
784+ int buildshipContainerLine = launchLines. findIndexOf {
785+ it. contains(' org.eclipse.buildship.core.gradleclasspathcontainer' )
786+ }
787+ if (buildshipContainerLine < 0 ) {
788+ throw new GradleException (" ${ name} is missing the Buildship classpath container" )
789+ }
790+ List<String > runtimeEntries = productionRuntime. collect { File runtimeFile ->
791+ String escapedPath = runtimeFile. canonicalPath
792+ .replace(' &' , ' &amp;' )
793+ .replace(' <' , ' &lt;' )
794+ .replace(' >' , ' &gt;' )
795+ (' <listEntry value="<?xml version="1.0" encoding="UTF-8" '
796+ + ' standalone="no"?><runtimeClasspathEntry externalArchive="'
797+ + escapedPath
798+ + ' " type="2" path="5" />"/>' )
799+ }
800+ launchLines. remove(buildshipContainerLine)
801+ launchLines. addAll(buildshipContainerLine, runtimeEntries)
802+ contents = launchLines. join(' \n ' ) + ' \n '
803+
768804 [' --cache' , ' --metadata' , ' --to-srg' , ' --to-obf' ]. each { option ->
769805 String prefix = option + ' '
770806 int valueStart = contents. indexOf(prefix)
@@ -823,6 +859,18 @@ tasks.register('verifyEclipseProductionClasspath') {
823859 if (! contents. contains(' PROJECT_ATTR" value="PowerAdvantage"' )) {
824860 throw new GradleException (" ${ name} targets the wrong Eclipse project" )
825861 }
862+ if (contents. contains(' org.eclipse.buildship.core.gradleclasspathcontainer' )) {
863+ throw new GradleException (" ${ name} exposes compileOnly dependencies at runtime" )
864+ }
865+ [' RF-API.jar' , ' RebornCore-1.12.2' ]. each { forbiddenDependency ->
866+ if (contents. toLowerCase(Locale . ROOT ). contains(forbiddenDependency. toLowerCase(Locale . ROOT ))) {
867+ throw new GradleException (
868+ " ${ name} includes compile-only dependency ${ forbiddenDependency} " )
869+ }
870+ }
871+ if (! contents. contains(" forge-${ project.minecraft_version} -${ project.forge_version} " )) {
872+ throw new GradleException (" ${ name} is missing the Forge development runtime" )
873+ }
826874 if (contents. contains(' ${MC_VERSION}' )
827875 || ! contents. contains(
828876 " key=\" MC_VERSION\" value=\" ${ project.minecraft_version} \" " )) {
@@ -832,6 +880,67 @@ tasks.register('verifyEclipseProductionClasspath') {
832880 }
833881}
834882
883+ tasks. register(' verifyModelAssets' ) {
884+ group = ' verification'
885+ description = ' Verifies that PowerAdvantage model references resolve to packaged assets.'
886+ File resourceRoot = file(' src/main/resources' )
887+ File modelRoot = new File (resourceRoot, " assets/${ project.mod_id} /models" )
888+ File blockstateRoot = new File (resourceRoot, " assets/${ project.mod_id} /blockstates" )
889+ inputs. dir(modelRoot)
890+ inputs. dir(blockstateRoot)
891+
892+ doLast {
893+ def verifyReference = { String reference , String assetType , String sourcePath ->
894+ if (reference. startsWith(' #' )) return
895+ int separator = reference. indexOf(' :' )
896+ String namespace = separator >= 0 ? reference. substring(0 , separator) : ' minecraft'
897+ String path = separator >= 0 ? reference. substring(separator + 1 ) : reference
898+ if (namespace != project. mod_id) return
899+
900+ File target = new File (resourceRoot,
901+ " assets/${ namespace} /${ assetType} /${ path} .json" )
902+ if (assetType == ' textures' ) {
903+ target = new File (resourceRoot, " assets/${ namespace} /textures/${ path} .png" )
904+ }
905+ if (! target. isFile()) {
906+ throw new GradleException (
907+ " ${ sourcePath} references missing ${ assetType} asset ${ reference} " )
908+ }
909+ }
910+
911+ fileTree(modelRoot) { include ' **/*.json' }. files. sort(). each { File modelFile ->
912+ def model = new JsonSlurper (). parse(modelFile)
913+ if (model. parent instanceof String ) {
914+ verifyReference(model. parent, ' models' , modelFile. path)
915+ }
916+ if (model. textures instanceof Map ) {
917+ model. textures. values(). findAll { it instanceof String }. each { String texture ->
918+ verifyReference(texture, ' textures' , modelFile. path)
919+ }
920+ }
921+ }
922+
923+ Closure verifyBlockstateModels
924+ verifyBlockstateModels = { Object node , String sourcePath ->
925+ if (node instanceof Map ) {
926+ node. each { key , value ->
927+ if (key == ' model' && value instanceof String ) {
928+ verifyReference(value, ' models/block' , sourcePath)
929+ } else {
930+ verifyBlockstateModels(value, sourcePath)
931+ }
932+ }
933+ } else if (node instanceof Collection ) {
934+ node. each { verifyBlockstateModels(it, sourcePath) }
935+ }
936+ }
937+ fileTree(blockstateRoot) { include ' **/*.json' }. files. sort(). each { File blockstateFile ->
938+ verifyBlockstateModels(new JsonSlurper (). parse(blockstateFile), blockstateFile. path)
939+ }
940+ }
941+ }
942+
835943tasks. named(' check' ) {
836944 dependsOn tasks. named(' verifyReleaseConfiguration' )
945+ dependsOn tasks. named(' verifyModelAssets' )
837946}
0 commit comments