|
| 1 | +import groovy.json.JsonOutput |
| 2 | +import groovy.json.JsonSlurper |
| 3 | + |
| 4 | +import javax.imageio.ImageIO |
| 5 | + |
| 6 | +// KiriCattus's two-layer model uses the legacy texture paths on these Forge versions. |
| 7 | +def hosts = [ |
| 8 | + adamantine_ore: 'netherrack', antimony_ore: 'stone', bismuth_ore: 'stone', |
| 9 | + coldiron_ore: 'netherrack', copper_ore: 'stone', lead_ore: 'stone', |
| 10 | + mercury_ore: 'stone', nickel_ore: 'stone', platinum_ore: 'stone', |
| 11 | + silver_ore: 'stone', starsteel_ore: 'end_stone', tin_ore: 'stone', zinc_ore: 'stone' |
| 12 | +].asImmutable() |
| 13 | +ext.baseMetalsOreOverlayIds = hosts.keySet().toList().asImmutable() |
| 14 | + |
| 15 | +def assets = layout.projectDirectory.dir('src/main/resources/assets/basemetals') |
| 16 | +def textures = assets.dir('textures/blocks/ore_overlays') |
| 17 | +def overlayFiles = fileTree(textures) { include '*_ore.png' } |
| 18 | +def oreStates = fileTree(assets.dir('blockstates')) { include '*_ore.json' } |
| 19 | +def oreItems = fileTree(assets.dir('models/item')) { include '*_ore.json' } |
| 20 | +def generated = layout.buildDirectory.dir('generated/ore-models') |
| 21 | +def sides = ['down', 'up', 'north', 'south', 'west', 'east'] |
| 22 | + |
| 23 | +def cube = { Number from, Number to, String texture -> |
| 24 | + def faces = sides.collectEntries { side -> |
| 25 | + [(side): [texture: texture, cullface: side, uv: [0, 0, 16, 16]]] |
| 26 | + } |
| 27 | + [from: [from, from, from], to: [to, to, to], faces: faces] |
| 28 | +} |
| 29 | + |
| 30 | +def models = [ore_overlay: [ |
| 31 | + parent: 'minecraft:block/block', |
| 32 | + elements: [cube(0, 16, '#base'), cube(-0.05, 16.05, '#overlay')] |
| 33 | +]] |
| 34 | +hosts.each { id, host -> |
| 35 | + def base = "minecraft:blocks/${host}".toString() |
| 36 | + models[id] = [ |
| 37 | + parent: 'basemetals:block/ore_overlay', |
| 38 | + textures: [particle: base, base: base, overlay: "basemetals:blocks/ore_overlays/${id}".toString()] |
| 39 | + ] |
| 40 | +} |
| 41 | + |
| 42 | +def generateOreModels = tasks.register('generateOreModels') { |
| 43 | + group = 'build' |
| 44 | + description = 'Generates the ore models from KiriCattus’s textures and vanilla rock.' |
| 45 | + inputs.files(overlayFiles, oreStates, oreItems).withPathSensitivity(PathSensitivity.RELATIVE) |
| 46 | + inputs.property('models', JsonOutput.toJson(models)) |
| 47 | + outputs.dir(generated) |
| 48 | + |
| 49 | + doLast { |
| 50 | + def found = overlayFiles.files.collect { it.name - '.png' }.toSet() |
| 51 | + if (found != hosts.keySet()) { |
| 52 | + throw new GradleException("Ore textures do not match the model list: missing ${hosts.keySet() - found}, extra ${found - hosts.keySet()}") |
| 53 | + } |
| 54 | + |
| 55 | + def json = new JsonSlurper() |
| 56 | + hosts.keySet().each { id -> |
| 57 | + def state = json.parse(assets.file("blockstates/${id}.json").asFile) |
| 58 | + def item = json.parse(assets.file("models/item/${id}.json").asFile) |
| 59 | + if (state.variants?.normal?.model != "basemetals:${id}" || item.parent != "basemetals:block/${id}") { |
| 60 | + throw new GradleException("The block and item must both use the generated model for ${id}") |
| 61 | + } |
| 62 | + |
| 63 | + def image = ImageIO.read(textures.file("${id}.png").asFile) |
| 64 | + if (image == null) throw new GradleException("Cannot read the overlay for ${id}") |
| 65 | + def alpha = image.getRGB(0, 0, image.width, image.height, null, 0, image.width).collect { it >>> 24 } |
| 66 | + if (!alpha.contains(0) || !alpha.any { it >= 128 }) { |
| 67 | + throw new GradleException("The overlay for ${id} must show both the ore and the rock behind it") |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + def dir = generated.get().dir('assets/basemetals/models/block').asFile |
| 72 | + dir.mkdirs() |
| 73 | + models.each { id, model -> |
| 74 | + new File(dir, "${id}.json").setText(JsonOutput.prettyPrint(JsonOutput.toJson(model)) + '\n', 'UTF-8') |
| 75 | + } |
| 76 | + dir.listFiles().findAll { it.isFile() && it.name.endsWith('.json') && !models.containsKey(it.name - '.json') }.each { |
| 77 | + if (!it.delete()) throw new GradleException("Could not remove stale generated model ${it.name}") |
| 78 | + } |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +// Eclipse copies these models into bin/main just like the other game resources. |
| 83 | +sourceSets.main.resources.srcDir(generateOreModels) |
| 84 | + |
| 85 | +['genEclipseRuns', 'eclipseClasspath'].each { taskName -> |
| 86 | + tasks.named(taskName) { dependsOn generateOreModels } |
| 87 | +} |
| 88 | + |
| 89 | +def processResources = tasks.named('processResources', ProcessResources) |
| 90 | + |
| 91 | +def verifyOreOverlayModels = tasks.register('verifyOreOverlayModels') { |
| 92 | + group = 'verification' |
| 93 | + description = 'Checks that the processed block and item resources use the generated ore overlays.' |
| 94 | + dependsOn processResources |
| 95 | + |
| 96 | + doLast { |
| 97 | + def root = new File(processResources.get().destinationDir, 'assets/basemetals') |
| 98 | + def json = new JsonSlurper() |
| 99 | + models.each { id, expected -> |
| 100 | + def path = new File(root, "models/block/${id}.json") |
| 101 | + if (!path.isFile() || json.parse(path) != expected) { |
| 102 | + throw new GradleException("Missing or incorrect processed ore model: ${id}") |
| 103 | + } |
| 104 | + } |
| 105 | + hosts.keySet().each { id -> |
| 106 | + def packaged = new File(root, "textures/blocks/ore_overlays/${id}.png") |
| 107 | + if (!packaged.isFile() || !Arrays.equals(packaged.bytes, textures.file("${id}.png").asFile.bytes)) { |
| 108 | + throw new GradleException("Missing or changed processed ore overlay: ${id}") |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +tasks.named('check') { dependsOn verifyOreOverlayModels } |
0 commit comments