Skip to content

Commit 4290373

Browse files
Move UncivServer to own module (and jar) (yairm210#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>
1 parent 3ea9c65 commit 4290373

12 files changed

+336
-23
lines changed

.gitignore

+8
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ com_crashlytics_export_strings.xml
3939
/android/bin/
4040
/core/bin/
4141
/desktop/bin/
42+
/server/bin/
4243
/html/bin/
4344
/ios/bin/
4445
/ios-moe/bin/
@@ -57,6 +58,7 @@ com_crashlytics_export_strings.xml
5758
/android/nbproject/private/
5859
/core/nbproject/private/
5960
/desktop/nbproject/private/
61+
/server/nbproject/private/
6062
/html/nbproject/private/
6163
/ios/nbproject/private/
6264
/ios-moe/nbproject/private/
@@ -65,6 +67,7 @@ com_crashlytics_export_strings.xml
6567
/android/build/
6668
/core/build/
6769
/desktop/build/
70+
/server/build/
6871
/html/build/
6972
/ios/build/
7073
/ios-moe/build/
@@ -74,6 +77,7 @@ com_crashlytics_export_strings.xml
7477
/android/nbbuild/
7578
/core/nbbuild/
7679
/desktop/nbbuild/
80+
/server/nbbuild/
7781
/html/nbbuild/
7882
/ios/nbbuild/
7983
/ios-moe/nbbuild/
@@ -82,6 +86,7 @@ com_crashlytics_export_strings.xml
8286
/android/dist/
8387
/core/dist/
8488
/desktop/dist/
89+
/server/dist/
8590
/html/dist/
8691
/ios/dist/
8792
/ios-moe/dist/
@@ -90,6 +95,7 @@ com_crashlytics_export_strings.xml
9095
/android/nbdist/
9196
/core/nbdist/
9297
/desktop/nbdist/
98+
/server/nbdist/
9399
/html/nbdist/
94100
/ios/nbdist/
95101
/ios-moe/nbdist/
@@ -131,6 +137,8 @@ android/release/android-release.aab
131137
tests/build/
132138
desktop/packr/
133139
desktop/packrCache/
140+
server/packr/
141+
server/packrCache/
134142
deploy/
135143
android/release/
136144

build.gradle.kts

+8-2
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,18 @@ project(":desktop") {
7070
}
7171

7272
"implementation"("com.github.MinnDevelopment:java-discord-rpc:v2.0.1")
73-
73+
7474
"implementation"("net.java.dev.jna:jna:5.11.0")
7575
"implementation"("net.java.dev.jna:jna-platform:5.11.0")
76+
}
77+
}
7678

77-
// For server-side
79+
// For server-side
80+
project(":server") {
81+
apply(plugin = "kotlin")
7882

83+
dependencies {
84+
// For server-side
7985
"implementation"("io.ktor:ktor-server-core:1.6.8")
8086
"implementation"("io.ktor:ktor-server-netty:1.6.8")
8187
"implementation"("ch.qos.logback:logback-classic:1.2.5")

core/src/com/unciv/ui/utils/KeyPressDispatcher.kt

+10-9
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,16 @@ data class KeyCharAndCode(val char: Char, val code: Int) {
6363
/** 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 */
6464
val UNKNOWN = KeyCharAndCode(Input.Keys.UNKNOWN)
6565

66-
// Kludges because we got crashes: java.lang.NoSuchMethodError: 'int kotlin.CharCodeKt.access$getCode$p(char)'
67-
fun Char.toCode() =
68-
try { code } catch (ex: Throwable) { null }
69-
?: try { @Suppress("DEPRECATION") toInt() } catch (ex: Throwable) { null }
70-
?: 0
71-
fun Int.makeChar() =
72-
try { Char(this) } catch (ex: Throwable) { null }
73-
?: try { toChar() } catch (ex: Throwable) { null }
74-
?: Char.MIN_VALUE
66+
// Kludges because we got crashes: java.lang.NoSuchMethodError: 'int kotlin.CharCodeKt.access$getCode$p(char)'
67+
//TODO fixed by removing UncivServer from the desktop module - clean up comments and all uses
68+
fun Char.toCode() = code
69+
// try { code } catch (ex: Throwable) { null }
70+
// ?: try { @Suppress("DEPRECATION") toInt() } catch (ex: Throwable) { null }
71+
// ?: 0
72+
fun Int.makeChar() = Char(this)
73+
// try { Char(this) } catch (ex: Throwable) { null }
74+
// ?: try { toChar() } catch (ex: Throwable) { null }
75+
// ?: Char.MIN_VALUE
7576

7677
/** mini-factory for control codes - case insensitive */
7778
fun ctrl(letter: Char) = KeyCharAndCode((letter.toCode() and 31).makeChar(),0)

docs/Developers/Building-Locally.md

+27-4
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ So first things first - the initial "No assumptions" setup to have Unciv run fro
2020
- Select "Show Package Details" in the bottom right
2121
- Choose version 30.0.3 under "Android SDK Build-Tools <whatever version you have>"
2222
- Click "Apply"
23-
- In Android Studio, Run > Edit configurations.
23+
- In Android Studio, Run > Edit configurations (be sure the Gradle sync is finished successfully first).
2424
- Click "+" to add a new configuration
2525
- Choose "Application"
26-
- 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
26+
- Give the configuration a name, we recommend "Desktop"
27+
- 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
2728
- If you get a `../../docs/uniques.md (No such file or directory)` error that means you forgot to set the working directory!
28-
- Select the Desktop configuration and click the green arrow button to run!
29+
- 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.
2930
- I also recommend going to Settings > Version Control > Commit and turning off 'Before commit - perform code analysis'
3031

3132
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!
3233

3334
Unciv uses Grade 7.2 and the Android Gradle Plugin 7.1.0
34-
35+
36+
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.
37+
3538
## Without Android Studio
3639

3740
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
6366

6467
For actual development, you'll probably need to download Android Studio and build it yourself - see Contributing :)
6568

69+
## UncivServer
70+
71+
The simple multiplayer host included in the sources can be set up to debug or run analogously to the main game:
72+
- In Android Studio, Run > Edit configurations.
73+
- Click "+" to add a new configuration
74+
- Choose "Application" and name the config, e.g. "UncivServer"
75+
- 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.
76+
- Select the UncivServer configuration and click the green arrow button to run! Or start a debug session as above.
77+
78+
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
79+
80+
## Unit Tests
81+
82+
You can (and in some cases _should_) run and even debug the unit tests locally.
83+
- In Android Studio, Run > Edit configurations.
84+
- Click "+" to add a new configuration
85+
- Choose "Gradle" and name the config, e.g. "Unit Tests"
86+
- 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.
87+
- Select the "Unit Tests" configuration and click the green arrow button to run! Or start a debug session as above.
88+
6689
## Next steps
6790

6891
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!

docs/Developers/Project-structure-and-major-classes.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
Since LibGDX, and therefore Unciv, are built for multi-platform support, the project structure is built accordingly.
44

5-
99% of the code is in the [Core](/com/unciv) project, which contains all the platform-independant code.
5+
99% of the code is in the [core](https://github.com/yairm210/Unciv/tree/master/core) project, which contains all the platform-independant code.
66

7-
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.
7+
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.
8+
9+
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.
10+
11+
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.
812

9-
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.
1013

1114
## Translations
1215

docs/Other/Hosting-a-Multiplayer-server.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ Therefore, you can now host your own Unciv server, when not on Android.
66

77
To do so, you must have a JDK installed.
88

9-
From the directory where the Unciv.jar file is located, create a folder named "MultiplayerFiles", open a terminal and run the following line:
10-
`java -cp Unciv.jar com.unciv.app.desktop.UncivServer`
9+
From the directory where the UncivServer.jar file is located, create a folder named "MultiplayerFiles", open a terminal and run the following line:
10+
`java -jar UncivServer.jar`
1111

1212
Don't forget to use 'cd' to switch to the correct dictionary. Here's an example in Windows.
1313

@@ -16,7 +16,7 @@ D:
1616
cd Games
1717
cd unciv
1818
mkdir MultiplayerFiles
19-
java -cp Unciv.jar com.unciv.app.desktop.UncivServer
19+
java -jar UncivServer.jar
2020
```
2121

2222
Your server has now started!

server/build.gradle.kts

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import com.badlogicgames.packr.Packr
2+
import com.badlogicgames.packr.PackrConfig
3+
import com.unciv.build.BuildConfig
4+
5+
plugins {
6+
id("kotlin")
7+
}
8+
9+
java {
10+
sourceCompatibility = JavaVersion.VERSION_1_8
11+
}
12+
13+
sourceSets {
14+
main {
15+
java.srcDir("src/")
16+
}
17+
}
18+
19+
val mainClassName = "com.unciv.app.server.UncivServer"
20+
val assetsDir = file("../android/assets")
21+
val deployFolder = file("../deploy")
22+
23+
// See https://github.com/libgdx/libgdx/wiki/Starter-classes-and-configuration#common-issues
24+
// and https://github.com/yairm210/Unciv/issues/5679
25+
val jvmArgsForMac = listOf("-XstartOnFirstThread", "-Djava.awt.headless=true")
26+
tasks.register<JavaExec>("run") {
27+
jvmArgs = mutableListOf<String>()
28+
if ("mac" in System.getProperty("os.name").toLowerCase())
29+
(jvmArgs as MutableList<String>).addAll(jvmArgsForMac)
30+
// These are non-standard, only available/necessary on Mac.
31+
32+
dependsOn(tasks.getByName("classes"))
33+
34+
main = mainClassName
35+
classpath = sourceSets.main.get().runtimeClasspath
36+
standardInput = System.`in`
37+
workingDir = assetsDir
38+
isIgnoreExitValue = true
39+
}
40+
41+
tasks.register<JavaExec>("debug") {
42+
jvmArgs = jvmArgsForMac
43+
dependsOn(tasks.getByName("classes"))
44+
main = mainClassName
45+
classpath = sourceSets.main.get().runtimeClasspath
46+
standardInput = System.`in`
47+
workingDir = assetsDir
48+
isIgnoreExitValue = true
49+
debug = true
50+
}
51+
52+
tasks.register<Jar>("dist") { // Compiles the jar file
53+
dependsOn(tasks.getByName("classes"))
54+
55+
// META-INF/INDEX.LIST and META-INF/io.netty.versions.properties are duplicated, but I don't know why
56+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
57+
58+
from(files(sourceSets.main.get().output.resourcesDir))
59+
from(files(sourceSets.main.get().output.classesDirs))
60+
// see Laurent1967's comment on https://github.com/libgdx/libgdx/issues/5491
61+
from({ configurations.compileClasspath.get().resolve().map { if (it.isDirectory) it else zipTree(it) } })
62+
archiveFileName.set("UncivServer.jar")
63+
64+
manifest {
65+
attributes(mapOf("Main-Class" to mainClassName, "Specification-Version" to BuildConfig.appVersion))
66+
}
67+
}
68+
69+
for (platform in PackrConfig.Platform.values()) {
70+
val platformName = platform.toString()
71+
72+
tasks.create("packr${platformName}") {
73+
dependsOn(tasks.getByName("dist"))
74+
75+
// Needs to be here and not in doLast because the zip task depends on the outDir
76+
val jarFile = "$rootDir/server/build/libs/UncivServer.jar"
77+
val config = PackrConfig()
78+
config.platform = platform
79+
80+
config.apply {
81+
executable = "UncivServer"
82+
classpath = listOf(jarFile)
83+
removePlatformLibs = config.classpath
84+
mainClass = mainClassName
85+
vmArgs = listOf("Xmx1G")
86+
minimizeJre = "server/packrConfig.json"
87+
outDir = file("packr")
88+
}
89+
90+
91+
doLast {
92+
// https://gist.github.com/seanf/58b76e278f4b7ec0a2920d8e5870eed6
93+
fun String.runCommand(workingDir: File) {
94+
val process = ProcessBuilder(*split(" ").toTypedArray())
95+
.directory(workingDir)
96+
.redirectOutput(ProcessBuilder.Redirect.PIPE)
97+
.redirectError(ProcessBuilder.Redirect.PIPE)
98+
.start()
99+
100+
if (!process.waitFor(30, TimeUnit.SECONDS)) {
101+
process.destroy()
102+
throw RuntimeException("execution timed out: $this")
103+
}
104+
if (process.exitValue() != 0) {
105+
println("execution returned code ${process.exitValue()}: $this")
106+
}
107+
println(process.inputStream.bufferedReader().readText())
108+
}
109+
110+
111+
if (config.outDir.exists()) delete(config.outDir)
112+
113+
// Requires that both packr and the jre are downloaded, as per buildAndDeploy.yml, "Upload to itch.io"
114+
115+
// Use old version of packr - newer versions aren't Windows32-compliant
116+
if (platform == PackrConfig.Platform.Windows32) {
117+
config.jdk = "jdk-windows-32.zip"
118+
Packr().pack(config)
119+
} else {
120+
val jdkFile =
121+
when (platform) {
122+
PackrConfig.Platform.Linux64 -> "jre-linux-64.tar.gz"
123+
PackrConfig.Platform.Windows64 -> "jdk-windows-64.zip"
124+
else -> "jre-macOS.tar.gz"
125+
}
126+
127+
val platformNameForPackrCmd =
128+
if (platform == PackrConfig.Platform.MacOS) "mac"
129+
else platform.name.toLowerCase()
130+
131+
val command = "java -jar $rootDir/packr-all-4.0.0.jar" +
132+
" --platform $platformNameForPackrCmd" +
133+
" --jdk $jdkFile" +
134+
" --executable UncivServer" +
135+
" --classpath $jarFile" +
136+
" --mainclass $mainClassName" +
137+
" --vmargs Xmx1G " +
138+
(if (platform == PackrConfig.Platform.MacOS) jvmArgsForMac.joinToString(" ") {
139+
it.removePrefix("-")
140+
}
141+
else "") +
142+
" --output ${config.outDir}"
143+
command.runCommand(rootDir)
144+
}
145+
}
146+
147+
tasks.register<Zip>("zip${platformName}") {
148+
archiveFileName.set("UncivServer-${platformName}.zip")
149+
from(config.outDir)
150+
destinationDirectory.set(deployFolder)
151+
}
152+
153+
finalizedBy("zip${platformName}")
154+
}
155+
}
156+
157+
tasks.register<Zip>("zipLinuxFilesForJar") {
158+
archiveFileName.set("linuxFilesForJar.zip")
159+
from(file("linuxFilesForJar"))
160+
destinationDirectory.set(deployFolder)
161+
}

0 commit comments

Comments
 (0)