Skip to content

Commit a7391af

Browse files
authored
Merge pull request #38 from dm432/feature/local-pack-hosting
feat: add local resource pack hosting for dev environment
2 parents 986c52f + 7ff508b commit a7391af

5 files changed

Lines changed: 182 additions & 26 deletions

File tree

CONTRIBUTING.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu
1515

1616
1. Fork the repo and create your branch from `master`. You don't need to run BuildTools or any other setup, everything is setup using Gradle tasks.
1717
2. Make your changes.
18-
3. Make sure to build and test the plugin extensively. You can run the `runServer` Gradle Task, which builds the plugin and starts a local test server for you.
18+
3. Make sure to build and test the plugin extensively. You can run the `runServer` Gradle Task, which builds the plugin and starts a local test server for you. Be sure to use the local resource pack hosting server. See [below](#how-we-handle-the-custom-resource-pack) for more information
1919
4. We use [ktlint](https://github.com/pinterest/ktlint) to enforce the kotlin code styleguides. Please run the `ktlintFormat` Gradle task to check your code.
2020
5. Please use [Conventional Commit Messages](https://www.conventionalcommits.org/en/v1.0.0/) for your Commits.
2121
6. Issue your pull request!
22+
23+
## How we handle the custom Resource Pack
24+
MPP uses a custom Resource Pack that needed for the custom blocks and items. You can generate this pack by running the `buildResourcePack` Gradle Task.
25+
26+
The plugin first checks for a Resource Pack with the correct version locally and then on Github Releases. If no pack is found an error is logged. The plugin version is calculated from the commit amount on the current branch.
27+
28+
If you are in a development or testing environment you should run the local Resource Pack hosting server with the `runResourcePackServer` Gradle Task. This is to make sure that the plugin always finds and uses the matching Resource Pack.

build.gradle.kts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import net.minecrell.pluginyml.bukkit.BukkitPluginDescription
22
import java.io.BufferedReader
3+
import java.nio.file.Paths
34

45
val javaVersion = 17
56
val minecraftVersion = "1.19.4"
@@ -49,7 +50,8 @@ bukkit {
4950
libraries = listOf(
5051
"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$embeddedKotlinVersion",
5152
"org.apache.commons:commons-compress:1.21",
52-
"com.konghq:unirest-java:3.13.13"
53+
"com.konghq:unirest-java:3.13.13",
54+
"com.squareup.okhttp3:okhttp:4.9.1"
5355
)
5456
commands {
5557
register("mpp") {
@@ -79,6 +81,7 @@ dependencies {
7981
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0-SNAPSHOT")
8082
compileOnly("org.apache.commons:commons-compress:1.21")
8183
compileOnly("com.konghq:unirest-java:3.13.13")
84+
compileOnly("com.squareup.okhttp3:okhttp:4.9.1")
8285
}
8386

8487
tasks {
@@ -106,7 +109,6 @@ tasks {
106109
}
107110

108111
runServer {
109-
dependsOn("runResourcePackServer")
110112
doFirst {
111113
download.run {
112114
src("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/target/ProtocolLib.jar")
@@ -135,20 +137,18 @@ tasks {
135137
// endregion
136138
}
137139

138-
abstract class RunResourcePackServer : DefaultTask() {
139-
140-
@TaskAction
141-
fun runResourcePackServer() {
142-
println("hello world")
143-
}
144-
}
145-
146140
tasks.register<JavaExec>("buildResourcePack") {
147141
mainClass.set("de.danielmaile.resourcepack.PackBuilderKt")
148142
classpath(sourceSets["main"].runtimeClasspath, configurations.compileClasspath)
149143
group = "mpp"
150144
args = listOf(getPluginVersion(), project.projectDir.absolutePath)
151145
}
152146
tasks.register<RunResourcePackServer>("runResourcePackServer") {
147+
dependsOn("buildResourcePack")
153148
group = "mpp"
149+
port = 8080
150+
resourcePackZip = File(
151+
projectDir.toPath().resolve(Paths.get("build", "resourcepack")).toFile(),
152+
"MPP-${getPluginVersion()}.zip"
153+
)
154154
}

buildSrc/build.gradle.kts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
plugins {
2+
`java-library`
3+
`embedded-kotlin`
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
}
9+
10+
dependencies {
11+
implementation("com.sparkjava:spark-core:2.9.3")
12+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* This file is part of MPP.
3+
* Copyright (c) 2023 by it's authors. All rights reserved.
4+
* MPP is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* MPP is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with MPP. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
import org.gradle.api.DefaultTask
19+
import org.gradle.api.tasks.Input
20+
import org.gradle.api.tasks.InputFile
21+
import org.gradle.api.tasks.TaskAction
22+
import spark.Spark
23+
import java.io.File
24+
import java.net.InetAddress
25+
26+
open class RunResourcePackServer : DefaultTask() {
27+
28+
@Input
29+
var port: Int = 8080
30+
31+
@InputFile
32+
var resourcePackZip: File = File(project.projectDir, "ResourcePack.zip")
33+
34+
@TaskAction
35+
fun startServer() {
36+
37+
val ipAddress = InetAddress.getLocalHost().hostAddress
38+
39+
Spark.port(port)
40+
Spark.get("/${resourcePackZip.name}") { _, res ->
41+
res.header("Content-Disposition", "attachment; filename=${resourcePackZip.name}")
42+
res.header("Content-Type", "application/zip")
43+
res.header("Content-Length", resourcePackZip.length().toString())
44+
res.raw().outputStream.use { outputStream ->
45+
resourcePackZip.inputStream().use { inputStream ->
46+
inputStream.copyTo(outputStream)
47+
}
48+
}
49+
}
50+
51+
println("Local Resource Pack Hosting Server started at http://$ipAddress:$port")
52+
println("Resource Pack ZIP file available at http://$ipAddress:$port/${resourcePackZip.name}")
53+
54+
// keep server running
55+
while (true) {
56+
Thread.sleep(1000)
57+
}
58+
}
59+
}

src/main/kotlin/de/danielmaile/mpp/data/ResourcePackManager.kt

Lines changed: 93 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,118 @@ package de.danielmaile.mpp.data
1919

2020
import de.danielmaile.mpp.inst
2121
import de.danielmaile.mpp.util.logError
22+
import de.danielmaile.mpp.util.logInfo
23+
import okhttp3.OkHttpClient
24+
import okhttp3.Request
25+
import org.apache.commons.codec.digest.DigestUtils
2226
import org.bukkit.event.EventHandler
2327
import org.bukkit.event.Listener
2428
import org.bukkit.event.player.PlayerJoinEvent
2529
import org.bukkit.event.player.PlayerResourcePackStatusEvent
26-
import java.net.HttpURLConnection
30+
import java.io.File
31+
import java.io.FileInputStream
32+
import java.net.InetAddress
2733
import java.net.URL
34+
import java.util.concurrent.TimeUnit
2835

2936
class ResourcePackManager : Listener {
3037

31-
private val githubPackLink: String
32-
private val packEnabled: Boolean
38+
private val httpClient = OkHttpClient.Builder()
39+
.callTimeout(5, TimeUnit.SECONDS)
40+
.connectTimeout(5, TimeUnit.SECONDS)
41+
.build()
42+
43+
private val pluginVersion = "MPP-${inst().pluginMeta.version}"
44+
private val ipAddress = InetAddress.getLocalHost().hostAddress
45+
private val localPackLink = "http://$ipAddress:8080/$pluginVersion.zip"
46+
private val githubPackLink = "https://github.com/dm432/MPP/releases/download/$pluginVersion/$pluginVersion.zip"
47+
48+
private val resourcePackLink: String?
49+
private val packHash: String?
3350

3451
init {
35-
val pluginVersion = "MPP-${inst().pluginMeta.version}"
36-
githubPackLink = "https://github.com/dm432/MPP/releases/download/$pluginVersion/$pluginVersion.zip"
52+
val localPackExists = doesPackExist(URL(localPackLink))
53+
val githubPackExists = doesPackExist(URL(githubPackLink))
54+
55+
resourcePackLink = when {
56+
localPackExists -> {
57+
logInfo("Using local hosted mpp resource pack.")
58+
localPackLink
59+
}
60+
61+
githubPackExists -> {
62+
logInfo("Using remote hosted mpp resource pack.")
63+
githubPackLink
64+
}
3765

38-
packEnabled = doesPackExist(URL(githubPackLink))
39-
if (!packEnabled) {
40-
logError("The MPP Resource Pack was not found on Github! Please make sure to download the latest official Release from https://github.com/dm432/MPP/releases")
66+
else -> {
67+
logError(
68+
"No mpp resource pack found! Make sure that you are using the latest plugin version. " +
69+
"If you're running the plugin in a development environment make sure that the local " +
70+
"ResourcePackHostingServer is running."
71+
)
72+
null
73+
}
4174
}
75+
76+
// Download pack
77+
val request = Request.Builder()
78+
.url(resourcePackLink ?: "")
79+
.build()
80+
81+
val packFile = File(inst().dataFolder, "$pluginVersion.zip")
82+
try {
83+
val response = httpClient.newCall(request).execute()
84+
if (response.isSuccessful && response.body != null) {
85+
response.body!!.byteStream().use { input ->
86+
packFile.outputStream().use { output ->
87+
input.copyTo(output)
88+
}
89+
}
90+
} else {
91+
logError("Error while downloading mpp resource pack to calculate the hash! Please restart the server to try again.")
92+
}
93+
} catch (e: Exception) {
94+
logError("Error while downloading mpp resource pack to calculate the hash! Please restart the server to try again.")
95+
}
96+
97+
packHash = calculateSHA1Hash(packFile)
98+
if (packHash != null) {
99+
logInfo("Resource pack hash is $packHash")
100+
}
101+
102+
packFile.delete()
42103
}
43104

44-
// Checks if the resource pack exits at the given link
105+
// Checks if the resource pack exists at the given link
45106
private fun doesPackExist(url: URL): Boolean {
46-
val connection = url.openConnection() as HttpURLConnection
47-
connection.requestMethod = "HEAD"
48-
return connection.responseCode == HttpURLConnection.HTTP_OK
107+
val request = Request.Builder()
108+
.head()
109+
.url(url)
110+
.build()
111+
112+
return try {
113+
val response = httpClient.newCall(request).execute()
114+
val exists = response.code == 200
115+
response.close()
116+
return exists
117+
} catch (e: Exception) {
118+
false
119+
}
120+
}
121+
122+
// calculates and returns the sha1 hash of a given File or null if the file does not exist
123+
private fun calculateSHA1Hash(file: File): String? {
124+
if (!file.exists()) return null
125+
FileInputStream(file).use {
126+
return DigestUtils.sha1Hex(it)
127+
}
49128
}
50129

51130
@EventHandler
52131
fun onJoin(event: PlayerJoinEvent) {
53-
if (!packEnabled) return
54-
// TODO use pack hash
55-
event.player.setResourcePack(githubPackLink)
132+
if (resourcePackLink == null || packHash == null) return
133+
event.player.setResourcePack(resourcePackLink, packHash, true)
56134
}
57135

58136
// kick players when they decline the mpp resource pack and

0 commit comments

Comments
 (0)