mirror of
https://github.com/yairm210/Unciv.git
synced 2024-12-22 16:04:23 +07:00
Move UncivServer to own module (and jar) (#6468)
* Move UncivServer to own module (and jar) * UncivServer isalive logged * Separate UncivServer - some wiki hints * Separate UncivServer - how to build UncivServer.jar Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
parent
3ea9c6503b
commit
4290373cf1
8
.gitignore
vendored
8
.gitignore
vendored
@ -39,6 +39,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/bin/
|
||||
/core/bin/
|
||||
/desktop/bin/
|
||||
/server/bin/
|
||||
/html/bin/
|
||||
/ios/bin/
|
||||
/ios-moe/bin/
|
||||
@ -57,6 +58,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/nbproject/private/
|
||||
/core/nbproject/private/
|
||||
/desktop/nbproject/private/
|
||||
/server/nbproject/private/
|
||||
/html/nbproject/private/
|
||||
/ios/nbproject/private/
|
||||
/ios-moe/nbproject/private/
|
||||
@ -65,6 +67,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/build/
|
||||
/core/build/
|
||||
/desktop/build/
|
||||
/server/build/
|
||||
/html/build/
|
||||
/ios/build/
|
||||
/ios-moe/build/
|
||||
@ -74,6 +77,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/nbbuild/
|
||||
/core/nbbuild/
|
||||
/desktop/nbbuild/
|
||||
/server/nbbuild/
|
||||
/html/nbbuild/
|
||||
/ios/nbbuild/
|
||||
/ios-moe/nbbuild/
|
||||
@ -82,6 +86,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/dist/
|
||||
/core/dist/
|
||||
/desktop/dist/
|
||||
/server/dist/
|
||||
/html/dist/
|
||||
/ios/dist/
|
||||
/ios-moe/dist/
|
||||
@ -90,6 +95,7 @@ com_crashlytics_export_strings.xml
|
||||
/android/nbdist/
|
||||
/core/nbdist/
|
||||
/desktop/nbdist/
|
||||
/server/nbdist/
|
||||
/html/nbdist/
|
||||
/ios/nbdist/
|
||||
/ios-moe/nbdist/
|
||||
@ -131,6 +137,8 @@ android/release/android-release.aab
|
||||
tests/build/
|
||||
desktop/packr/
|
||||
desktop/packrCache/
|
||||
server/packr/
|
||||
server/packrCache/
|
||||
deploy/
|
||||
android/release/
|
||||
|
||||
|
@ -70,12 +70,18 @@ project(":desktop") {
|
||||
}
|
||||
|
||||
"implementation"("com.github.MinnDevelopment:java-discord-rpc:v2.0.1")
|
||||
|
||||
|
||||
"implementation"("net.java.dev.jna:jna:5.11.0")
|
||||
"implementation"("net.java.dev.jna:jna-platform:5.11.0")
|
||||
}
|
||||
}
|
||||
|
||||
// For server-side
|
||||
project(":server") {
|
||||
apply(plugin = "kotlin")
|
||||
|
||||
dependencies {
|
||||
// For server-side
|
||||
|
||||
"implementation"("io.ktor:ktor-server-core:1.6.8")
|
||||
"implementation"("io.ktor:ktor-server-netty:1.6.8")
|
||||
"implementation"("ch.qos.logback:logback-classic:1.2.5")
|
||||
|
@ -63,15 +63,16 @@ data class KeyCharAndCode(val char: Char, val code: Int) {
|
||||
/** Guaranteed to be ignored by [KeyPressDispatcher.set] and never to be generated for an actual event, used as fallback to ensure no action is taken */
|
||||
val UNKNOWN = KeyCharAndCode(Input.Keys.UNKNOWN)
|
||||
|
||||
// Kludges because we got crashes: java.lang.NoSuchMethodError: 'int kotlin.CharCodeKt.access$getCode$p(char)'
|
||||
fun Char.toCode() =
|
||||
try { code } catch (ex: Throwable) { null }
|
||||
?: try { @Suppress("DEPRECATION") toInt() } catch (ex: Throwable) { null }
|
||||
?: 0
|
||||
fun Int.makeChar() =
|
||||
try { Char(this) } catch (ex: Throwable) { null }
|
||||
?: try { toChar() } catch (ex: Throwable) { null }
|
||||
?: Char.MIN_VALUE
|
||||
// Kludges because we got crashes: java.lang.NoSuchMethodError: 'int kotlin.CharCodeKt.access$getCode$p(char)'
|
||||
//TODO fixed by removing UncivServer from the desktop module - clean up comments and all uses
|
||||
fun Char.toCode() = code
|
||||
// try { code } catch (ex: Throwable) { null }
|
||||
// ?: try { @Suppress("DEPRECATION") toInt() } catch (ex: Throwable) { null }
|
||||
// ?: 0
|
||||
fun Int.makeChar() = Char(this)
|
||||
// try { Char(this) } catch (ex: Throwable) { null }
|
||||
// ?: try { toChar() } catch (ex: Throwable) { null }
|
||||
// ?: Char.MIN_VALUE
|
||||
|
||||
/** mini-factory for control codes - case insensitive */
|
||||
fun ctrl(letter: Char) = KeyCharAndCode((letter.toCode() and 31).makeChar(),0)
|
||||
|
@ -20,18 +20,21 @@ So first things first - the initial "No assumptions" setup to have Unciv run fro
|
||||
- Select "Show Package Details" in the bottom right
|
||||
- Choose version 30.0.3 under "Android SDK Build-Tools <whatever version you have>"
|
||||
- Click "Apply"
|
||||
- In Android Studio, Run > Edit configurations.
|
||||
- In Android Studio, Run > Edit configurations (be sure the Gradle sync is finished successfully first).
|
||||
- Click "+" to add a new configuration
|
||||
- Choose "Application"
|
||||
- Set the module to `Unciv.desktop`, main class to `com.unciv.app.desktop.DesktopLauncher` and `<repo_folder>\android\assets\` as the Working directory, OK to close the window
|
||||
- Give the configuration a name, we recommend "Desktop"
|
||||
- Set the module classpath (the box to the right of the Java selection) to `Unciv.desktop`, main class to `com.unciv.app.desktop.DesktopLauncher` and `<repo_folder>\android\assets\` as the Working directory, OK to close the window
|
||||
- If you get a `../../docs/uniques.md (No such file or directory)` error that means you forgot to set the working directory!
|
||||
- Select the Desktop configuration and click the green arrow button to run!
|
||||
- Select the Desktop configuration (or however you chose to name it) and click the green arrow button to run! Or you can use the next button -the green critter with six legs and two feelers - to start debugging.
|
||||
- I also recommend going to Settings > Version Control > Commit and turning off 'Before commit - perform code analysis'
|
||||
|
||||
Unciv uses Gradle to specify dependencies and how to run. In the background, the Gradle gnomes will be off fetching the packages (a one-time effort) and, once that's done, will build the project!
|
||||
|
||||
Unciv uses Grade 7.2 and the Android Gradle Plugin 7.1.0
|
||||
|
||||
|
||||
Note advanced build commands as described in the next paragraph, specifically the `gradlew desktop:dist` one to build a jar, run just fine in Android Studio's terminal (Alt+F12), with most dependencies already taken care of.
|
||||
|
||||
## Without Android Studio
|
||||
|
||||
If you also have JDK 11 installed, you can compile Unciv on your own by cloning (or downloading and unzipping) the project, opening a terminal in the Unciv folder and run the following commands:
|
||||
@ -63,6 +66,26 @@ After building, the output .JAR file should be in /desktop/build/libs/Unciv.jar
|
||||
|
||||
For actual development, you'll probably need to download Android Studio and build it yourself - see Contributing :)
|
||||
|
||||
## UncivServer
|
||||
|
||||
The simple multiplayer host included in the sources can be set up to debug or run analogously to the main game:
|
||||
- In Android Studio, Run > Edit configurations.
|
||||
- Click "+" to add a new configuration
|
||||
- Choose "Application" and name the config, e.g. "UncivServer"
|
||||
- Set the module to `Unciv.server`, main class to `com.unciv.app.server.DesktopLauncher` and `<repo_folder>/android/assets/` as the Working directory, OK to close the window.
|
||||
- Select the UncivServer configuration and click the green arrow button to run! Or start a debug session as above.
|
||||
|
||||
To build a jar file, refer to [Without Android Studio](#Without-Android-Studio) and replace 'desktop' with 'server'. That is, run `./gradlew server:dist` and when it's done look for /server/build/libs/UncivServer.jar
|
||||
|
||||
## Unit Tests
|
||||
|
||||
You can (and in some cases _should_) run and even debug the unit tests locally.
|
||||
- In Android Studio, Run > Edit configurations.
|
||||
- Click "+" to add a new configuration
|
||||
- Choose "Gradle" and name the config, e.g. "Unit Tests"
|
||||
- Under "Gradle Project", choose "Unciv" from the dropdown (or type it), set "Tasks" to `:tests:test` and "Arguments" to `--tests "com.unciv.*"`, OK to close the window.
|
||||
- Select the "Unit Tests" configuration and click the green arrow button to run! Or start a debug session as above.
|
||||
|
||||
## Next steps
|
||||
|
||||
Congratulations! Unciv should now be running on your computer! Now we can start changing some code, and later we'll see how your changes make it into the main repository!
|
||||
|
@ -2,11 +2,14 @@
|
||||
|
||||
Since LibGDX, and therefore Unciv, are built for multi-platform support, the project structure is built accordingly.
|
||||
|
||||
99% of the code is in the [Core](/com/unciv) project, which contains all the platform-independant code.
|
||||
99% of the code is in the [core](https://github.com/yairm210/Unciv/tree/master/core) project, which contains all the platform-independant code.
|
||||
|
||||
The [Desktop](/) and [Android](/) folders contain platform-specific things, and the Android folder also contains the game Images and the all-important Assets, which are required for running from Desktop as well, so we bundle them up into the .jar file when releasing.
|
||||
The [desktop](https://github.com/yairm210/Unciv/tree/master/desktop) and [android](https://github.com/yairm210/Unciv/tree/master/android) folders contain platform-specific things, and the Android folder also contains the game Images and the all-important Assets, which are required for running from Desktop as well, so we bundle them up into the .jar file when releasing.
|
||||
|
||||
The [tests](https://github.com/yairm210/Unciv/tree/master/tests) folder contains tests that can be run manually via gradle with `./gradlew tests:test`, and are run automatically by Travis for every push.
|
||||
|
||||
The [server](https://github.com/yairm210/Unciv/tree/master/server) folder contains the sources for the UncivServer (a host enabling communication between multiplayer game instances), which is packaged into its own separate jar.
|
||||
|
||||
The [Test](/com/unciv) folder contains tests that can be run manually via gradle with `./gradlew tests:test`, and are run automatically by Travis for every push.
|
||||
|
||||
## Translations
|
||||
|
||||
|
@ -6,8 +6,8 @@ Therefore, you can now host your own Unciv server, when not on Android.
|
||||
|
||||
To do so, you must have a JDK installed.
|
||||
|
||||
From the directory where the Unciv.jar file is located, create a folder named "MultiplayerFiles", open a terminal and run the following line:
|
||||
`java -cp Unciv.jar com.unciv.app.desktop.UncivServer`
|
||||
From the directory where the UncivServer.jar file is located, create a folder named "MultiplayerFiles", open a terminal and run the following line:
|
||||
`java -jar UncivServer.jar`
|
||||
|
||||
Don't forget to use 'cd' to switch to the correct dictionary. Here's an example in Windows.
|
||||
|
||||
@ -16,7 +16,7 @@ D:
|
||||
cd Games
|
||||
cd unciv
|
||||
mkdir MultiplayerFiles
|
||||
java -cp Unciv.jar com.unciv.app.desktop.UncivServer
|
||||
java -jar UncivServer.jar
|
||||
```
|
||||
|
||||
Your server has now started!
|
||||
|
161
server/build.gradle.kts
Normal file
161
server/build.gradle.kts
Normal file
@ -0,0 +1,161 @@
|
||||
import com.badlogicgames.packr.Packr
|
||||
import com.badlogicgames.packr.PackrConfig
|
||||
import com.unciv.build.BuildConfig
|
||||
|
||||
plugins {
|
||||
id("kotlin")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDir("src/")
|
||||
}
|
||||
}
|
||||
|
||||
val mainClassName = "com.unciv.app.server.UncivServer"
|
||||
val assetsDir = file("../android/assets")
|
||||
val deployFolder = file("../deploy")
|
||||
|
||||
// See https://github.com/libgdx/libgdx/wiki/Starter-classes-and-configuration#common-issues
|
||||
// and https://github.com/yairm210/Unciv/issues/5679
|
||||
val jvmArgsForMac = listOf("-XstartOnFirstThread", "-Djava.awt.headless=true")
|
||||
tasks.register<JavaExec>("run") {
|
||||
jvmArgs = mutableListOf<String>()
|
||||
if ("mac" in System.getProperty("os.name").toLowerCase())
|
||||
(jvmArgs as MutableList<String>).addAll(jvmArgsForMac)
|
||||
// These are non-standard, only available/necessary on Mac.
|
||||
|
||||
dependsOn(tasks.getByName("classes"))
|
||||
|
||||
main = mainClassName
|
||||
classpath = sourceSets.main.get().runtimeClasspath
|
||||
standardInput = System.`in`
|
||||
workingDir = assetsDir
|
||||
isIgnoreExitValue = true
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("debug") {
|
||||
jvmArgs = jvmArgsForMac
|
||||
dependsOn(tasks.getByName("classes"))
|
||||
main = mainClassName
|
||||
classpath = sourceSets.main.get().runtimeClasspath
|
||||
standardInput = System.`in`
|
||||
workingDir = assetsDir
|
||||
isIgnoreExitValue = true
|
||||
debug = true
|
||||
}
|
||||
|
||||
tasks.register<Jar>("dist") { // Compiles the jar file
|
||||
dependsOn(tasks.getByName("classes"))
|
||||
|
||||
// META-INF/INDEX.LIST and META-INF/io.netty.versions.properties are duplicated, but I don't know why
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
|
||||
from(files(sourceSets.main.get().output.resourcesDir))
|
||||
from(files(sourceSets.main.get().output.classesDirs))
|
||||
// see Laurent1967's comment on https://github.com/libgdx/libgdx/issues/5491
|
||||
from({ configurations.compileClasspath.get().resolve().map { if (it.isDirectory) it else zipTree(it) } })
|
||||
archiveFileName.set("UncivServer.jar")
|
||||
|
||||
manifest {
|
||||
attributes(mapOf("Main-Class" to mainClassName, "Specification-Version" to BuildConfig.appVersion))
|
||||
}
|
||||
}
|
||||
|
||||
for (platform in PackrConfig.Platform.values()) {
|
||||
val platformName = platform.toString()
|
||||
|
||||
tasks.create("packr${platformName}") {
|
||||
dependsOn(tasks.getByName("dist"))
|
||||
|
||||
// Needs to be here and not in doLast because the zip task depends on the outDir
|
||||
val jarFile = "$rootDir/server/build/libs/UncivServer.jar"
|
||||
val config = PackrConfig()
|
||||
config.platform = platform
|
||||
|
||||
config.apply {
|
||||
executable = "UncivServer"
|
||||
classpath = listOf(jarFile)
|
||||
removePlatformLibs = config.classpath
|
||||
mainClass = mainClassName
|
||||
vmArgs = listOf("Xmx1G")
|
||||
minimizeJre = "server/packrConfig.json"
|
||||
outDir = file("packr")
|
||||
}
|
||||
|
||||
|
||||
doLast {
|
||||
// https://gist.github.com/seanf/58b76e278f4b7ec0a2920d8e5870eed6
|
||||
fun String.runCommand(workingDir: File) {
|
||||
val process = ProcessBuilder(*split(" ").toTypedArray())
|
||||
.directory(workingDir)
|
||||
.redirectOutput(ProcessBuilder.Redirect.PIPE)
|
||||
.redirectError(ProcessBuilder.Redirect.PIPE)
|
||||
.start()
|
||||
|
||||
if (!process.waitFor(30, TimeUnit.SECONDS)) {
|
||||
process.destroy()
|
||||
throw RuntimeException("execution timed out: $this")
|
||||
}
|
||||
if (process.exitValue() != 0) {
|
||||
println("execution returned code ${process.exitValue()}: $this")
|
||||
}
|
||||
println(process.inputStream.bufferedReader().readText())
|
||||
}
|
||||
|
||||
|
||||
if (config.outDir.exists()) delete(config.outDir)
|
||||
|
||||
// Requires that both packr and the jre are downloaded, as per buildAndDeploy.yml, "Upload to itch.io"
|
||||
|
||||
// Use old version of packr - newer versions aren't Windows32-compliant
|
||||
if (platform == PackrConfig.Platform.Windows32) {
|
||||
config.jdk = "jdk-windows-32.zip"
|
||||
Packr().pack(config)
|
||||
} else {
|
||||
val jdkFile =
|
||||
when (platform) {
|
||||
PackrConfig.Platform.Linux64 -> "jre-linux-64.tar.gz"
|
||||
PackrConfig.Platform.Windows64 -> "jdk-windows-64.zip"
|
||||
else -> "jre-macOS.tar.gz"
|
||||
}
|
||||
|
||||
val platformNameForPackrCmd =
|
||||
if (platform == PackrConfig.Platform.MacOS) "mac"
|
||||
else platform.name.toLowerCase()
|
||||
|
||||
val command = "java -jar $rootDir/packr-all-4.0.0.jar" +
|
||||
" --platform $platformNameForPackrCmd" +
|
||||
" --jdk $jdkFile" +
|
||||
" --executable UncivServer" +
|
||||
" --classpath $jarFile" +
|
||||
" --mainclass $mainClassName" +
|
||||
" --vmargs Xmx1G " +
|
||||
(if (platform == PackrConfig.Platform.MacOS) jvmArgsForMac.joinToString(" ") {
|
||||
it.removePrefix("-")
|
||||
}
|
||||
else "") +
|
||||
" --output ${config.outDir}"
|
||||
command.runCommand(rootDir)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Zip>("zip${platformName}") {
|
||||
archiveFileName.set("UncivServer-${platformName}.zip")
|
||||
from(config.outDir)
|
||||
destinationDirectory.set(deployFolder)
|
||||
}
|
||||
|
||||
finalizedBy("zip${platformName}")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Zip>("zipLinuxFilesForJar") {
|
||||
archiveFileName.set("linuxFilesForJar.zip")
|
||||
from(file("linuxFilesForJar"))
|
||||
destinationDirectory.set(deployFolder)
|
||||
}
|
46
server/linuxFilesForJar/UncivServer.sh
Normal file
46
server/linuxFilesForJar/UncivServer.sh
Normal file
@ -0,0 +1,46 @@
|
||||
#!/bin/sh
|
||||
|
||||
CONFIG_DIR="$HOME/.local/share/Unciv"
|
||||
|
||||
USAGE="UncivServer [--help | -h | --config-dir PATH]
|
||||
|
||||
Run the Unciv Multiplayer Server.
|
||||
|
||||
With '--help' or '-h', show this help info and exit.
|
||||
|
||||
With '--config-dir PATH', use/make configuration files in PATH instead
|
||||
of the default of '$CONFIG_DIR'.
|
||||
|
||||
"
|
||||
|
||||
usage() {
|
||||
echo "$USAGE"
|
||||
exit 0
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "Error: $1"
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$#" -gt "0" ]; then
|
||||
case "$1" in
|
||||
--help|-h)
|
||||
shift
|
||||
usage
|
||||
;;
|
||||
--config-dir)
|
||||
CONFIG_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
fi
|
||||
if ! [ "$#" -eq "0" ]; then
|
||||
fail "Unknown argument(s): $*"
|
||||
fi
|
||||
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
cd "$CONFIG_DIR" || fail "Could not 'cd' to '$CONFIG_DIR'"
|
||||
java -jar /usr/share/Unciv/UncivServer.jar
|
12
server/linuxFilesForJar/uncivserver.desktop
Normal file
12
server/linuxFilesForJar/uncivserver.desktop
Normal file
@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Comment=Open-source Android/Desktop remake of Civ V, Multiplayer Server
|
||||
Exec=UncivServer
|
||||
GenericName=4X Game
|
||||
Icon=unciv
|
||||
Name=Unciv
|
||||
NoDisplay=false
|
||||
StartupNotify=true
|
||||
Terminal=true
|
||||
Type=Application
|
||||
Categories=Game
|
||||
Name[en_US]=uncivserver.desktop
|
52
server/packrConfig.json
Normal file
52
server/packrConfig.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"reduce": [
|
||||
{
|
||||
"archive": "jre/lib/rt.jar",
|
||||
"paths": [
|
||||
"com/sun/corba",
|
||||
"com/sun/jmx",
|
||||
"com/sun/jndi",
|
||||
"com/sun/media",
|
||||
"com/sun/naming",
|
||||
"com/sun/org",
|
||||
"com/sun/rowset",
|
||||
"com/sun/script",
|
||||
"com/sun/xml",
|
||||
"sun/applet",
|
||||
"sun/corba",
|
||||
"sun/management"
|
||||
]
|
||||
},
|
||||
{
|
||||
"archive": "jre/lib/charsets.jar",
|
||||
"paths": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"archive": "jre/lib/jsse.jar",
|
||||
"paths": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"archive": "jre/lib/resources.jar",
|
||||
"paths": [
|
||||
]
|
||||
}
|
||||
],
|
||||
"remove": [
|
||||
{
|
||||
"platform": "*",
|
||||
"paths": [
|
||||
"jre/lib/rhino.jar",
|
||||
"jre/lib/amd64/libjfxwebkit.so"
|
||||
]
|
||||
},
|
||||
{
|
||||
"platform": "windows",
|
||||
"paths": [
|
||||
"jre/bin/*.exe",
|
||||
"jre/bin/client"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.unciv.app.desktop
|
||||
package com.unciv.app.server
|
||||
|
||||
import com.github.ajalt.clikt.core.CliktCommand
|
||||
import com.github.ajalt.clikt.parameters.options.default
|
||||
@ -43,6 +43,7 @@ private class UncivServerRunner : CliktCommand() {
|
||||
embeddedServer(Netty, port = serverPort) {
|
||||
routing {
|
||||
get("/isalive") {
|
||||
println("Received isalive request from ${call.request.local.remoteHost}")
|
||||
call.respondText("true")
|
||||
}
|
||||
put("/files/{fileName}") {
|
@ -1 +1 @@
|
||||
include("desktop", "android", "ios", "core", "tests")
|
||||
include("desktop", "android", "ios", "core", "tests", "server")
|
Loading…
Reference in New Issue
Block a user