diff --git a/.run/Lwjgl3GameLauncher (MacOS).run.xml b/.run/Lwjgl3GameLauncher (MacOS).run.xml
deleted file mode 100644
index f54329d9e..000000000
--- a/.run/Lwjgl3GameLauncher (MacOS).run.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
index 9d45b33c1..24379df9c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -28,7 +28,6 @@
- The codebase mixes legacy C-inspired naming; keep existing patterns in touched files for consistency.
- When renaming critical functions, keep the old C name in a brief comment for traceability.
- Use `*Test` suffixes for test classes (for example `Vector3fTest.kt`).
-- Do not delete existing comments if they are not addressed in the change.
## Testing Guidelines
- Primary test framework is JUnit 4 (see root `build.gradle`); Kotlin tests live alongside Java tests.
diff --git a/README.md b/README.md
index e57d66c84..23a0c66b8 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,8 @@ Requirements:
Documentation & Info
--------------------
-The `info` folder contains documentation and other useful information:
-
- * [Project Overview](info/Overview.md)
+ * [Overview](info/Overview.md)
+ * [BSP file format](info/BSP.md)
* [Networking](info/Networking.md)
What is Cake? Important note about client side code
diff --git a/assets/shaders/vat.glsl b/assets/shaders/vat.glsl
index 27065b1b7..1c15c15b2 100644
--- a/assets/shaders/vat.glsl
+++ b/assets/shaders/vat.glsl
@@ -1,5 +1,5 @@
-in float a_vat_index;
-in vec2 a_texCoord1; // Diffuse Texture coordinates
+attribute float a_vat_index;
+attribute vec2 a_texCoord1; // Diffuse Texture coordinates
uniform mat4 u_worldTrans; // World transformation matrix
uniform mat4 u_projViewTrans; // View transformation matrix
@@ -11,7 +11,7 @@ uniform int u_frame1; // Index of the first frame in the animation texture
uniform int u_frame2; // Index of the second frame in the animation texture
uniform float u_interpolation; // Interpolation factor between two animation frames (0.0 to 1.0)
-out vec2 v_diffuseUV;
+varying vec2 v_diffuseUV;
void main() {
vec2 texelSize = vec2(1.0 / u_textureWidth, 1.0 / u_textureHeight);
@@ -20,8 +20,8 @@ void main() {
// Sample the vertex texture to get the animated positions for the two frames
// The texture stores vec3 positions in RGB channels (assuming float texture)
- vec3 animatedPosition1 = texture(u_vertexAnimationTexture, vertexTextureCoord1).rgb;
- vec3 animatedPosition2 = texture(u_vertexAnimationTexture, vertexTextureCoord2).rgb;
+ vec3 animatedPosition1 = texture2D(u_vertexAnimationTexture, vertexTextureCoord1).rgb;
+ vec3 animatedPosition2 = texture2D(u_vertexAnimationTexture, vertexTextureCoord2).rgb;
// Interpolate between the two animated positions
vec3 finalPosition = mix(animatedPosition1, animatedPosition2, u_interpolation);
diff --git a/build.gradle b/build.gradle
index 4c96d087a..810f90a35 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,33 +1,24 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-buildscript {
- repositories {
- mavenCentral()
- maven { url 'https://s01.oss.sonatype.org' }
- gradlePluginPortal()
- mavenLocal()
- google()
- maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
- maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
- }
- dependencies {
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
- }
+plugins {
+ alias(libs.plugins.kotlin.jvm) apply false
+ alias(libs.plugins.badass.runtime) apply false
+ alias(libs.plugins.graalvm.native) apply false
}
configure(subprojects) {
apply plugin: 'java-library'
- apply plugin: 'kotlin'
+ apply plugin: 'org.jetbrains.kotlin.jvm'
java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
}
compileJava {
options.incremental = true
}
- compileKotlin.compilerOptions.jvmTarget.set(JvmTarget.JVM_11)
- compileTestKotlin.compilerOptions.jvmTarget.set(JvmTarget.JVM_11)
+ compileKotlin.compilerOptions.jvmTarget.set(JvmTarget.JVM_21)
+ compileTestKotlin.compilerOptions.jvmTarget.set(JvmTarget.JVM_21)
}
@@ -35,16 +26,7 @@ subprojects {
group = 'org.demoth'
version = '1.0.0'
ext.appName = 'cake'
- repositories {
- mavenCentral()
- maven { url 'https://s01.oss.sonatype.org' }
- // You may want to remove the following line if you have errors downloading dependencies.
- mavenLocal()
- maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
- maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
- maven { url 'https://jitpack.io' }
- }
dependencies {
- testImplementation('junit:junit:4.12')
+ testImplementation(libs.junit)
}
}
diff --git a/cake/core/build.gradle b/cake/core/build.gradle
deleted file mode 100644
index c76ccbd92..000000000
--- a/cake/core/build.gradle
+++ /dev/null
@@ -1,23 +0,0 @@
-dependencies {
- api "com.badlogicgames.gdx-controllers:gdx-controllers-core:$gdxControllersVersion"
- api "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
- api "com.badlogicgames.gdx:gdx:$gdxVersion"
-// api "com.badlogicgames.gdx:scene2d.ui:$gdxVersion"
- api "io.github.libktx:ktx-actors:$ktxVersion"
- api "io.github.libktx:ktx-app:$ktxVersion"
- api "io.github.libktx:ktx-assets-async:$ktxVersion"
- api "io.github.libktx:ktx-assets:$ktxVersion"
- api "io.github.libktx:ktx-async:$ktxVersion"
- api "io.github.libktx:ktx-collections:$ktxVersion"
- api "io.github.libktx:ktx-freetype-async:$ktxVersion"
- api "io.github.libktx:ktx-freetype:$ktxVersion"
- api "io.github.libktx:ktx-graphics:$ktxVersion"
- api "io.github.libktx:ktx-log:$ktxVersion"
- api "io.github.libktx:ktx-scene2d:$ktxVersion"
- api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
- api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion"
-
- implementation(project(":qcommon"))
- testImplementation "com.badlogicgames.gdx:gdx-backend-headless:$gdxVersion"
- testRuntimeOnly "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
-}
diff --git a/cake/core/build.gradle.kts b/cake/core/build.gradle.kts
new file mode 100644
index 000000000..23be55468
--- /dev/null
+++ b/cake/core/build.gradle.kts
@@ -0,0 +1,20 @@
+dependencies {
+ api(libs.gdx.controllers.core)
+ api(libs.gdx.freetype)
+ api(libs.gdx)
+ // api(libs.gdx.scene2d.ui)
+ api(libs.ktx.actors)
+ api(libs.ktx.app)
+ api(libs.ktx.assets.async)
+ api(libs.ktx.assets)
+ api(libs.ktx.async)
+ api(libs.ktx.collections)
+ api(libs.ktx.freetype.async)
+ api(libs.ktx.freetype)
+ api(libs.ktx.graphics)
+ api(libs.ktx.log)
+ api(libs.ktx.scene2d)
+ api(libs.kotlinx.coroutines.core)
+
+ implementation(project(":qcommon"))
+}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/Cake.kt b/cake/core/src/main/kotlin/org/demoth/cake/Cake.kt
index a5a4d30c2..2079deca3 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/Cake.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/Cake.kt
@@ -8,9 +8,7 @@ import com.badlogic.gdx.InputProcessor
import com.badlogic.gdx.assets.AssetManager
import com.badlogic.gdx.assets.loaders.SoundLoader
import com.badlogic.gdx.audio.Sound
-import com.badlogic.gdx.graphics.glutils.ShaderProgram
import com.badlogic.gdx.graphics.Texture
-import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.utils.ScreenUtils
import com.badlogic.gdx.utils.viewport.StretchViewport
@@ -35,13 +33,8 @@ import ktx.assets.TextAssetLoader
import ktx.scene2d.Scene2DSkin
import org.demoth.cake.ClientNetworkState.*
import org.demoth.cake.assets.CakeFileResolver
-import org.demoth.cake.assets.BspLoader
-import org.demoth.cake.assets.BspMapAsset
-import org.demoth.cake.assets.Md2Asset
-import org.demoth.cake.assets.Md2Loader
import org.demoth.cake.assets.ObjectLoader
import org.demoth.cake.assets.PcxLoader
-import org.demoth.cake.assets.SkyLoader
import org.demoth.cake.assets.WalLoader
import org.demoth.cake.stages.ConsoleStage
import org.demoth.cake.stages.Game3dScreen
@@ -102,9 +95,6 @@ class Cake : KtxApplicationAdapter, KtxInputAdapter {
setLoader(Sound::class.java, SoundLoader(fileResolver))
setLoader(Texture::class.java, "pcx", PcxLoader(fileResolver))
setLoader(Texture::class.java, "wal", WalLoader(fileResolver))
- setLoader(BspMapAsset::class.java, "bsp", BspLoader(fileResolver))
- setLoader(Md2Asset::class.java, "md2", Md2Loader(fileResolver))
- setLoader(Model::class.java, "sky", SkyLoader(fileResolver))
}
@@ -117,24 +107,6 @@ class Cake : KtxApplicationAdapter, KtxInputAdapter {
}
override fun create() {
- ShaderProgram.prependVertexCode = """
- #version 150
- #define GLSL3
- #define attribute in
- #define varying out
- #define texture2D texture
- #define textureCube texture
- """.trimIndent() + "\n"
- ShaderProgram.prependFragmentCode = """
- #version 150
- #define GLSL3
- #define varying in
- #define texture2D texture
- #define textureCube texture
- out vec4 fragColor;
- #define gl_FragColor fragColor
- """.trimIndent() + "\n"
-
// load sync resources - required immediately
assetManager.load(cakeSkin, Skin::class.java)
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/BspLoader.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/BspLoader.kt
index dceecb81e..ef9f08e24 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/BspLoader.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/BspLoader.kt
@@ -1,107 +1,46 @@
package org.demoth.cake.assets
-import com.badlogic.gdx.assets.AssetDescriptor
-import com.badlogic.gdx.assets.AssetLoaderParameters
import com.badlogic.gdx.assets.AssetManager
-import com.badlogic.gdx.assets.loaders.FileHandleResolver
-import com.badlogic.gdx.assets.loaders.SynchronousAssetLoader
-import com.badlogic.gdx.files.FileHandle
+import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.GL20.GL_TRIANGLES
-import com.badlogic.gdx.graphics.Texture
-import com.badlogic.gdx.graphics.VertexAttribute
-import com.badlogic.gdx.graphics.VertexAttributes
+import com.badlogic.gdx.graphics.VertexAttributes.Usage
import com.badlogic.gdx.graphics.g3d.Material
import com.badlogic.gdx.graphics.g3d.Model
+import com.badlogic.gdx.graphics.g3d.ModelInstance
+import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute
+import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder
-import com.badlogic.gdx.utils.Array
-import com.badlogic.gdx.utils.Disposable
import jake2.qcommon.filesystem.Bsp
+import java.io.File
import java.nio.ByteBuffer
-import java.util.LinkedHashSet
-/**
- * Loaded BSP map data.
- *
- * [models] are generated GPU resources owned by this asset instance.
- * BSP textures are loaded as independent AssetManager dependencies and are not disposed here.
- */
-class BspMapAsset(
- val mapData: ByteArray,
- val models: List
-) : Disposable {
- override fun dispose() {
- models.forEach { it.dispose() }
- }
-}
-
-/**
- * Loads Quake2 BSP maps into renderable libGDX models.
- *
- * Loader flow:
- * 1. [getDependencies] parses BSP bytes and declares all referenced WAL textures.
- * 2. [load] builds one libGDX [Model] per BSP model (world model + inline brush models).
- * 3. Faces are grouped by texture and triangulated as triangle fans.
- *
- * This keeps texture lifecycle in AssetManager while model lifecycle is handled by [BspMapAsset].
- */
-class BspLoader(resolver: FileHandleResolver) : SynchronousAssetLoader(resolver) {
-
- /**
- * Parameters forwarded to dependent WAL texture loads.
- */
- data class Parameters(
- val walParameters: WalLoader.Parameters = defaultWalParameters()
- ) : AssetLoaderParameters()
+class BspLoader(private val locator: ResourceLocator, private val assetManager: AssetManager) {
- override fun load(
- manager: AssetManager,
- fileName: String,
- file: FileHandle,
- parameter: Parameters?
- ): BspMapAsset {
- val mapData = file.readBytes()
- val bsp = Bsp(ByteBuffer.wrap(mapData))
- return BspMapAsset(mapData = mapData, models = buildModels(bsp, manager))
- }
-
- override fun getDependencies(fileName: String, file: FileHandle?, parameter: Parameters?): Array>? {
- if (file == null) {
- return null
- }
-
- val walParams = parameter?.walParameters ?: defaultWalParameters()
- val texturePaths = collectWalTexturePaths(file.readBytes())
- if (texturePaths.isEmpty()) {
- return null
- }
-
- return Array>(texturePaths.size).apply {
- texturePaths.forEach { path ->
- add(AssetDescriptor(path, Texture::class.java, walParams))
- }
- }
- }
+ fun loadBspModels(bsdData: ByteArray): List {
+ val bsp = Bsp(ByteBuffer.wrap(bsdData))
- /**
- * Builds one [Model] per BSP model and one mesh part per texture group.
- */
- private fun buildModels(bsp: Bsp, manager: AssetManager): List {
- return bsp.models.map { model ->
+ // create libgdx models from bsp models
+ return bsp.models.mapIndexed { i, model ->
val modelBuilder = ModelBuilder()
modelBuilder.begin()
- val modelFaces = (0..
+
+ val params = WalLoader.Parameters().apply {
+ wrapU = Texture.TextureWrap.Repeat
+ wrapV = Texture.TextureWrap.Repeat
+ }
+
+ val texture = assetManager.getLoaded("textures/$textureName.wal", params)
val meshBuilder = modelBuilder.part(
- "part_$textureIndex",
+ "part1",
GL_TRIANGLES,
VertexAttributes(VertexAttribute.Position(), VertexAttribute.TexCoords(0)),
Material(
@@ -150,36 +89,32 @@ class BspLoader(resolver: FileHandleResolver) : SynchronousAssetLoader {
- val bsp = Bsp(ByteBuffer.wrap(bspData))
- val texturePaths = LinkedHashSet()
- bsp.models.forEach { model ->
- repeat(model.faceCount) { offset ->
- val face = bsp.faces[model.firstFace + offset]
- val textureName = bsp.textures[face.textureInfoIndex].name
- if (shouldLoadWalTexture(textureName)) {
- texturePaths.add(toWalPath(textureName))
- }
+ // unused now
+ fun loadBSPModelWireFrame(file: File): ModelInstance {
+ val bsp = Bsp(ByteBuffer.wrap(file.readBytes()))
+
+ val modelBuilder = ModelBuilder()
+ modelBuilder.begin()
+ val partBuilder: MeshPartBuilder = modelBuilder.part(
+ "lines",
+ GL20.GL_LINES,
+ (Usage.Position or Usage.ColorUnpacked).toLong(),
+ Material(ColorAttribute.createDiffuse(Color.WHITE))
+ )
+ bsp.edges.forEach {
+ val from = bsp.vertices[it.v1]
+ val to = bsp.vertices[it.v2]
+ partBuilder.line(
+ from.x,
+ from.y,
+ from.z,
+ to.x,
+ to.y,
+ to.z
+ )
}
- }
- return texturePaths.toList()
-}
+ return ModelInstance(modelBuilder.end())
-private fun toWalPath(textureName: String): String = "textures/${textureName.trim()}.wal"
-
-private fun shouldLoadWalTexture(textureName: String): Boolean {
- val normalized = textureName.trim()
- // sky is loaded separately, see SkyLoader
- return normalized.isNotEmpty() && !normalized.contains("sky", ignoreCase = true)
+ }
}
-
-private fun defaultWalParameters() = WalLoader.Parameters(
- wrapU = Texture.TextureWrap.Repeat,
- wrapV = Texture.TextureWrap.Repeat,
-)
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeFileResolver.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeFileResolver.kt
index a3d65e92c..e1e4b0d6b 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeFileResolver.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeFileResolver.kt
@@ -3,7 +3,6 @@ package org.demoth.cake.assets
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.assets.loaders.FileHandleResolver
import com.badlogic.gdx.files.FileHandle
-import com.badlogic.gdx.utils.GdxRuntimeException
import jake2.qcommon.Com
@@ -38,82 +37,44 @@ class CakeFileResolver(
* 4.1 basedir/basemod/
* 4.2 basedir/basemod/other_pak_files
* 4.3 basedir/basemod/pak\d+.pak files
- *
- * supports case-insensitive lookup if the exact match is not found
*/
override fun resolve(fileName: String): FileHandle? {
- // first try to resolve the file matching the case
- val file = resolveInternal(fileName, caseInsensitive = false)
+ val file = resolveInternal(fileName)
if (file != null) return file
- // fallback to case-insensitive lookup using libgdx FileHandle API
- val caseInsensitive = resolveInternal(fileName, caseInsensitive = true)
- if (caseInsensitive != null) {
- Com.Warn("Resource $fileName was found with different case")
- return caseInsensitive
+ // maybe add a cvar switch to disable/enable lowercase file resolving?
+ val lowercase = resolveInternal(fileName.lowercase())
+ if (lowercase != null) {
+ Com.Warn("Resource $fileName was found with lowercase")
+ return lowercase
}
Com.Warn("Resource $fileName was not found")
return null
}
- private fun resolveInternal(fileName: String, caseInsensitive: Boolean): FileHandle? {
-
- // SkyLoader uses synthetic keys like sky/.sky; no physical file is required.
- val normalized = fileName.replace('\\', '/').lowercase()
- if (normalized.startsWith("sky/") && normalized.endsWith(".sky")) {
- return Gdx.files.internal("") // return an empty file handle
- }
-
- val roots = mutableListOf()
+ private fun resolveInternal(fileName: String): FileHandle? {
// bootstrap assets - not overridable
- roots.add(Gdx.files.classpath(""))
+ var file = Gdx.files.classpath(fileName)
+ if (file.exists()) return file
+
// engine "assets" folder
- roots.add(Gdx.files.internal(""))
+ file = Gdx.files.internal(fileName)
+ if (file.exists()) return file
if (basedir != null) {
// check mod override
if (gamemod != null) {
- roots.add(Gdx.files.absolute("$basedir/$gamemod"))
+ file = Gdx.files.absolute("$basedir/$gamemod/$fileName")
+ if (file.exists()) return file
+
// todo: check the game mod pak files
}
// fallback to the base mod
- roots.add(Gdx.files.absolute("$basedir/$basemod"))
- // todo: check the basemod pak files
- }
+ file = Gdx.files.absolute("$basedir/$basemod/$fileName")
+ if (file.exists()) return file
- for (root in roots) {
- val resolved = if (caseInsensitive) {
- findCaseInsensitive(root, normalized)
- } else {
- root.child(fileName)
- }
- if (resolved != null && resolved.exists()) return resolved
+ // todo: check the basemod pak files
}
return null
- }
-
- /**
- * Resolves a relative path under [root] by matching each path segment case-insensitively.
- * This exists to handle Quake2 assets whose on-disk casing does not match the requested path.
- */
- private fun findCaseInsensitive(root: FileHandle, relativePath: String): FileHandle? {
- val parts = relativePath.split('/').filter { it.isNotEmpty() }
- if (parts.isEmpty()) return null
-
- var current = root
- for ((index, part) in parts.withIndex()) {
- if (!current.exists()) return null
- if (index < parts.lastIndex && !current.isDirectory) return null
- val entries = try {
- current.list()
- } catch (_: GdxRuntimeException) {
- // Some backends (classpath root) do not support listing; skip this root.
- return null
- }
- val next = entries.firstOrNull { it.name().equals(part, ignoreCase = true) }
- ?: return null
- current = next
- }
- return current
}
-}
+}
\ No newline at end of file
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeTextureLoaders.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeTextureLoaders.kt
index d70a5635f..41e81c022 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeTextureLoaders.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/CakeTextureLoaders.kt
@@ -65,14 +65,14 @@ class CakeTextureData(private var pixmap: Pixmap) : TextureData {
class WalLoader(resolver: FileHandleResolver) : SynchronousAssetLoader(resolver) {
- data class Parameters(
- val externalPalette: IntArray? = null,
- val paletteAssetPath: String = "q2palette.bin",
- val minFilter: Texture.TextureFilter? = null,
- val magFilter: Texture.TextureFilter? = null,
- val wrapU: Texture.TextureWrap? = null,
- val wrapV: Texture.TextureWrap? = null,
- ) : AssetLoaderParameters()
+ class Parameters : AssetLoaderParameters() {
+ var externalPalette: IntArray? = null
+ var paletteAssetPath: String = "q2palette.bin"
+ var minFilter: Texture.TextureFilter? = null
+ var magFilter: Texture.TextureFilter? = null
+ var wrapU: Texture.TextureWrap? = null
+ var wrapV: Texture.TextureWrap? = null
+ }
override fun load(
manager: AssetManager,
@@ -132,13 +132,13 @@ internal fun fromWal(wal: WAL, palette: IntArray): Pixmap {
class PcxLoader(resolver: FileHandleResolver) : SynchronousAssetLoader(resolver) {
- data class Parameters(
- val externalPalette: IntArray? = null,
- val minFilter: Texture.TextureFilter? = null,
- val magFilter: Texture.TextureFilter? = null,
- val wrapU: Texture.TextureWrap? = null,
- val wrapV: Texture.TextureWrap? = null,
- ) : AssetLoaderParameters()
+ class Parameters : AssetLoaderParameters() {
+ var externalPalette: IntArray? = null
+ var minFilter: Texture.TextureFilter? = null
+ var magFilter: Texture.TextureFilter? = null
+ var wrapU: Texture.TextureWrap? = null
+ var wrapV: Texture.TextureWrap? = null
+ }
override fun load(
manager: AssetManager,
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/GameResourceLocator.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/GameResourceLocator.kt
new file mode 100644
index 000000000..d6ea4c86e
--- /dev/null
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/GameResourceLocator.kt
@@ -0,0 +1,37 @@
+package org.demoth.cake.assets
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.files.FileHandle
+import java.io.File
+import java.util.ArrayDeque
+
+/**
+ * Responsible for finding resources, in paks or on the filesystem.
+ */
+// todo: cache? move to streams instead?
+// todo: get rid of File(...) usages where possible
+@Deprecated("Migrate to AssetManager locator logic")
+class GameResourceLocator(private val baseDir: String) : ResourceLocator {
+
+ // todo: support other gameNames - be able to locate mod resources (fallback to baseq2 or smth else)
+ var gameName: String = "baseq2"
+
+ override fun findModelPath(modelName: String): String? {
+ if (modelName.isEmpty()) {
+ // todo: throw error?
+ return null
+ } else if (modelName.startsWith("#")) {
+ // TODO: handle view models separately
+ return null
+ } else {
+ val file = File("$baseDir/$gameName/$modelName")
+ return if (file.exists()) file.absolutePath else null
+ }
+ }
+
+ override fun findSkinPath(skinName: String): String? {
+ val file = File("$baseDir/$gameName/$skinName")
+ return if (file.exists()) file.absolutePath else null
+ }
+
+}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2ModelLoader.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2ModelLoader.kt
index bdbe65127..0103518ce 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2ModelLoader.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2ModelLoader.kt
@@ -1,20 +1,10 @@
package org.demoth.cake.assets
import com.badlogic.gdx.Gdx
-import com.badlogic.gdx.assets.AssetDescriptor
import com.badlogic.gdx.assets.AssetLoaderParameters
import com.badlogic.gdx.assets.AssetManager
-import com.badlogic.gdx.assets.loaders.FileHandleResolver
-import com.badlogic.gdx.assets.loaders.SynchronousAssetLoader
-import com.badlogic.gdx.files.FileHandle
-import com.badlogic.gdx.graphics.GL20
-import com.badlogic.gdx.graphics.GL30
-import com.badlogic.gdx.graphics.Mesh
-import com.badlogic.gdx.graphics.Pixmap
-import com.badlogic.gdx.graphics.Texture
-import com.badlogic.gdx.graphics.TextureData
-import com.badlogic.gdx.graphics.VertexAttribute
-import com.badlogic.gdx.graphics.VertexAttributes
+import com.badlogic.gdx.graphics.*
+import com.badlogic.gdx.graphics.GL20.GL_TRIANGLES
import com.badlogic.gdx.graphics.VertexAttribute.TexCoords
import com.badlogic.gdx.graphics.VertexAttributes.Usage.Generic
import com.badlogic.gdx.graphics.g3d.Material
@@ -22,11 +12,10 @@ import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute.Diffuse
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder
-import com.badlogic.gdx.utils.Array
-import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.GdxRuntimeException
import jake2.qcommon.filesystem.Md2Model
import jake2.qcommon.filesystem.Md2VertexData
+import jake2.qcommon.filesystem.PCX
import jake2.qcommon.filesystem.buildVertexData
import java.nio.Buffer
import java.nio.ByteBuffer
@@ -34,98 +23,36 @@ import java.nio.ByteOrder
import java.nio.FloatBuffer
import kotlin.jvm.java
-/**
- * Loaded MD2 asset bundle.
- *
- * [model] is the renderable geometry using the VAT shader attributes.
- * [frames] is frame count metadata used by animation code.
- * [skins] contains resolved skin textures in MD2 skin index order when available.
- *
- * This allows future runtime skin switching (for example normal/injured monster skin)
- * without replacing model geometry.
- */
-class Md2Asset(
- val model: Model,
- val frames: Int,
- val skins: List,
-) : Disposable {
- override fun dispose() {
- model.dispose()
- }
-}
-
-/**
- * Loads MD2 geometry and prepares textures required by the model material.
- *
- * Dependency policy:
- * - external skin path provided -> load only that texture.
- * - embedded skins + loadAllEmbeddedSkins=true -> preload all embedded skins.
- * - embedded skins + loadAllEmbeddedSkins=false -> load only selected skinIndex.
- *
- * Geometry is turned into a mesh with VAT index attributes and a GPU VAT texture.
- */
-class Md2Loader(resolver: FileHandleResolver) : SynchronousAssetLoader(resolver) {
-
- /**
- * MD2 loading options.
- *
- * [externalSkinPath] overrides embedded MD2 skin names.
- * [skinIndex] selects default embedded skin (wrapped with modulo).
- * [loadAllEmbeddedSkins] preloads all embedded skins to support quick runtime switching.
- */
- data class Parameters(
- val externalSkinPath: String? = null,
- val skinIndex: Int = 0,
- val loadAllEmbeddedSkins: Boolean = true,
- ) : AssetLoaderParameters()
-
- override fun getDependencies(
- fileName: String,
- file: FileHandle?,
- parameter: Parameters?
- ): Array>? {
- if (file == null) {
- return null
- }
- val md2 = readMd2Model(file.readBytes())
- val skinPaths = resolveDependencySkinPaths(md2, parameter)
- if (skinPaths.isEmpty()) {
- return null
+class Md2ModelLoader(
+ private val locator: ResourceLocator,
+ private val assetManager: AssetManager
+) {
+
+ fun loadMd2ModelData(
+ modelName: String,
+ playerSkin: String? = null,
+ skinIndex: Int,
+ ): Md2ModelData? {
+ val modelPath = locator.findModelPath(modelName) ?: return null
+ val md2Model: Md2Model = readMd2Model(assetManager.getLoaded(modelPath))
+
+ val embeddedSkins = md2Model.skinNames.map {
+ val skinPath = requireNotNull(locator.findSkinPath(it)) { "Missing skin: $it" }
+ assetManager.getLoaded(skinPath)
}
- return Array>(skinPaths.size).apply {
- skinPaths.forEach { add(AssetDescriptor(it, Texture::class.java)) }
+ val modelSkin: ByteArray = if (embeddedSkins.isNotEmpty()) {
+ embeddedSkins[skinIndex]
+ } else {
+ if (playerSkin != null) {
+ val skinPath = requireNotNull(locator.findSkinPath(playerSkin)) { "Missing skin: $playerSkin" }
+ assetManager.getLoaded(skinPath)
+ } else throw IllegalStateException("No skin found in the model, no player skin provided")
}
- }
- override fun load(
- manager: AssetManager,
- fileName: String,
- file: FileHandle,
- parameter: Parameters?
- ): Md2Asset {
- val md2 = readMd2Model(file.readBytes())
+ val diffuse = Texture(CakeTextureData(fromPCX(PCX(modelSkin))))
- val selectedSkinPath = resolveSelectedSkinPath(md2, parameter)
- val dependencySkinPaths = resolveDependencySkinPaths(md2, parameter)
- val texturesByPath = dependencySkinPaths.associateWith { path ->
- manager.get(path, Texture::class.java)
- }
-
- val skinTexturesByIndex = when {
- parameter?.externalSkinPath?.isBlank() == false -> {
- listOf(texturesByPath.getValue(selectedSkinPath))
- }
- else -> {
- md2.skinNames.map { skinPath ->
- val texture = texturesByPath[skinPath]
- check(texture != null) { "Missing dependency texture for MD2 skin: $skinPath" }
- texture
- }
- }
- }
- val diffuse = texturesByPath.getValue(selectedSkinPath)
+ val vertexData = buildVertexData(md2Model.glCommands, md2Model.frames)
- val vertexData = buildVertexData(md2.glCommands, md2.frames)
val mesh = Mesh(
true,
vertexData.vertexAttributes.size,
@@ -137,58 +64,16 @@ class Md2Loader(resolver: FileHandleResolver) : SynchronousAssetLoader {
- // player models provide skin path externally
- val external = parameter?.externalSkinPath?.takeIf { it.isNotBlank() }
- if (external != null) {
- return listOf(external)
- }
- if (md2.skinNames.isEmpty()) {
- return emptyList()
- }
- val embedded = md2.skinNames
- return if (parameter?.loadAllEmbeddedSkins == false) {
- listOf(embedded[normalizedSkinIndex(parameter.skinIndex, embedded.size)])
- } else {
- embedded.distinct()
- }
- }
-
- /**
- * Computes the skin path used as diffuse texture for the created material.
- */
- private fun resolveSelectedSkinPath(md2: Md2Model, parameter: Parameters?): String {
- val external = parameter?.externalSkinPath?.takeIf { it.isNotBlank() }
- if (external != null) {
- return external
- }
-
- check(md2.skinNames.isNotEmpty()) {
- "No embedded skin found in model and no external skin was provided"
- }
- val selectedIndex = normalizedSkinIndex(parameter?.skinIndex ?: 0, md2.skinNames.size)
- return md2.skinNames[selectedIndex]
- }
-
- private fun normalizedSkinIndex(index: Int, size: Int): Int {
- check(size > 0) { "Cannot normalize skin index for empty skin set" }
- val modulo = index % size
- return if (modulo < 0) modulo + size else modulo
- }
-
private fun createMd2Material(diffuse: Texture, vat: Texture): Material {
- // required for registering the custom VAT texture attribute
+ // need to call static init explicitly?
+ // without it, I get the error about an invalid attribute type from 'register'
AnimationTextureAttribute.init()
// create the material with diffuse and an "animation" attribute
@@ -198,9 +83,6 @@ class Md2Loader(resolver: FileHandleResolver) : SynchronousAssetLoader AssetManager.getLoaded(path: String, parameter: AssetLoad
return get(path, T::class.java)
}
+class Md2ModelData(val mesh: Mesh, val material: Material, val frames: Int)
+
// Helper class to create TextureData from a vertex position data buffer
private class CustomTextureData(
private val width: Int,
@@ -270,6 +154,7 @@ private class CustomTextureData(
return false
}
+
override fun consumeCustomData(target: Int) {
if (!isPrepared) throw GdxRuntimeException("Call prepare() first")
@@ -310,7 +195,7 @@ private class CustomTextureData(
fun createModel(mesh: Mesh, material: Material): Model {
return ModelBuilder().apply {
begin()
- part("part1", mesh, GL20.GL_TRIANGLES, material)
+ part("part1", mesh, GL_TRIANGLES, material)
}.end()
}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2Shader.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2Shader.kt
index b3673452e..e9de6a002 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2Shader.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/Md2Shader.kt
@@ -17,8 +17,7 @@ data class Md2CustomData(
var frame1: Int,
var frame2: Int,
var interpolation: Float,
- val frames: Int,
- var skinIndex: Int = 0 // used for normal->pain skin switching
+ val frames: Int
)
/**
@@ -37,6 +36,7 @@ class AnimationTextureAttribute(val texture: Texture): TextureAttribute(Animatio
}
private const val md2ShaderPrefix = """
+ #version 130
#define diffuseTextureFlag
"""
@@ -110,4 +110,4 @@ class Md2ShaderProvider(private val shader: Shader): DefaultShaderProvider() {
shader
} else super.getShader(renderable)
}
-}
+}
\ No newline at end of file
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/ModelViewerResourceLocator.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/ModelViewerResourceLocator.kt
new file mode 100644
index 000000000..7fbf33ba3
--- /dev/null
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/ModelViewerResourceLocator.kt
@@ -0,0 +1,20 @@
+package org.demoth.cake.assets
+
+import java.io.File
+
+class ModelViewerResourceLocator(val currentDirectory: String) : ResourceLocator {
+
+ /**
+ * Expect the full model file path
+ */
+ override fun findModelPath(modelName: String): String? {
+ val file = File(modelName)
+ return if (file.exists()) file.absolutePath else null
+ }
+
+ override fun findSkinPath(skinName: String): String? {
+ val fileName = skinName.substring(skinName.lastIndexOf('/') + 1)
+ val file = File("$currentDirectory/$fileName")
+ return if (file.exists()) file.absolutePath else null
+ }
+}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/ObjectLoader.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/ObjectLoader.kt
index b49d0989f..7b5dd1f9a 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/ObjectLoader.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/ObjectLoader.kt
@@ -9,12 +9,6 @@ import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.utils.Array
import java.io.ObjectInputStream
-/**
- * Loads Java-serialized objects via AssetManager.
- *
- * This loader uses Java ObjectInputStream, so it must only be used with trusted data sources.
- * Deserialization runs in [loadAsync], with [loadSync] returning the cached result.
- */
class ObjectLoader(resolver: FileHandleResolver) : AsynchronousAssetLoader(resolver) {
class Parameters : AssetLoaderParameters()
@@ -36,11 +30,6 @@ class ObjectLoader(resolver: FileHandleResolver) : AsynchronousAssetLoader>? = null
-}
+}
\ No newline at end of file
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/ResourceLocator.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/ResourceLocator.kt
new file mode 100644
index 000000000..381c47c85
--- /dev/null
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/ResourceLocator.kt
@@ -0,0 +1,16 @@
+package org.demoth.cake.assets
+
+/**
+ * Abstracts the way how the resources are located (how name is resolved) and loaded.
+ * Two implementations exist for Game and ModelViewer
+ */
+// todo: reimplement as a FileHandleResolver
+interface ResourceLocator {
+
+ fun findModelPath(modelName: String): String?
+
+ /**
+ * skin name should contain the file extension
+ */
+ fun findSkinPath(skinName: String): String?
+}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/assets/SkyLoader.kt b/cake/core/src/main/kotlin/org/demoth/cake/assets/SkyLoader.kt
index 4b7cf55f0..4c7d77929 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/assets/SkyLoader.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/assets/SkyLoader.kt
@@ -1,59 +1,31 @@
package org.demoth.cake.assets
-import com.badlogic.gdx.assets.AssetDescriptor
-import com.badlogic.gdx.assets.AssetLoaderParameters
import com.badlogic.gdx.assets.AssetManager
-import com.badlogic.gdx.assets.loaders.FileHandleResolver
-import com.badlogic.gdx.assets.loaders.SynchronousAssetLoader
-import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.graphics.GL20.GL_TRIANGLES
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.VertexAttributes
import com.badlogic.gdx.graphics.g3d.Material
-import com.badlogic.gdx.graphics.g3d.Model
+import com.badlogic.gdx.graphics.g3d.ModelInstance
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute
import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder
-import com.badlogic.gdx.utils.Array
-import java.util.Locale
/**
- * Loads a skybox model and declares all six sky textures as dependencies.
+ * This class is responsible for building the skybox geometry and assigning proper textures
*/
-class SkyLoader(resolver: FileHandleResolver) : SynchronousAssetLoader(resolver) {
+class SkyLoader(private val assetManager: AssetManager) {
- class SkyLoaderParameters : AssetLoaderParameters()
-
- override fun load(
- manager: AssetManager,
- fileName: String,
- file: FileHandle,
- parameter: SkyLoaderParameters?
- ): Model {
- val skyName = skyNameFromAssetPath(fileName)
- val textures = PARTS.associateWith { part ->
- manager.get(toTexturePath(skyName, part), Texture::class.java)
- }
- return buildSkyModel(textures)
- }
-
- override fun getDependencies(
- fileName: String,
- file: FileHandle?,
- parameter: SkyLoaderParameters?
- ): Array> {
- val skyName = skyNameFromAssetPath(fileName)
- return Array>(PARTS.size).apply {
- PARTS.forEach { part ->
- add(AssetDescriptor(toTexturePath(skyName, part), Texture::class.java))
- }
- }
- }
+ private val parts = listOf("rt", "bk", "lf", "ft", "up", "dn")
+ private val s = 2048f // size
/**
- * Builds a sky cube geometry of the given size.
+ * [name] the name of the unit or set of the skybox images, usually ends with an underscore
*/
- private fun buildSkyModel(textures: Map): Model {
+ fun load(name: String): ModelInstance {
+ val textures = parts.associateWith { part ->
+ assetManager.getLoaded("env/$name$part.pcx")
+ }
+
val modelBuilder = ModelBuilder()
modelBuilder.begin()
@@ -106,28 +78,9 @@ class SkyLoader(resolver: FileHandleResolver) : SynchronousAssetLoader) : ApplicationAdapter() {
private var md2AnimationFrameTime = 0.1f
private var md2AnimationTime = 0.0f
private var playingMd2Animation = false
- private val assetManager = AssetManager(AbsoluteFileHandleResolver()).apply {
+ private val assetManager = AssetManager().apply {
setLoader(ByteArray::class.java, ByteArrayLoader(AbsoluteFileHandleResolver()))
- setLoader(Texture::class.java, "pcx", PcxLoader(AbsoluteFileHandleResolver()))
- setLoader(Md2Asset::class.java, "md2", Md2Loader(AbsoluteFileHandleResolver()))
}
override fun create() {
@@ -73,6 +70,7 @@ class CakeModelViewer(val args: Array) : ApplicationAdapter() {
println("File $file does not exist or is unreadable")
Gdx.app.exit()
}
+ val locator = ModelViewerResourceLocator(file.parent)
font = BitmapFont()
when (file.extension) {
@@ -90,8 +88,10 @@ class CakeModelViewer(val args: Array) : ApplicationAdapter() {
)
}
"md2" -> {
- val md2 = assetManager.getLoaded(file.absolutePath)
- md2Instance = ModelInstance(md2.model)
+
+ val md2 = Md2ModelLoader(locator, assetManager).loadMd2ModelData(file.absolutePath, null, 0)!!
+ val model = createModel(md2.mesh, md2.material)
+ md2Instance = ModelInstance(model) // ok
md2Instance!!.userData = Md2CustomData(
0,
if (md2.frames > 1) 1 else 0,
@@ -204,9 +204,8 @@ class CakeModelViewer(val args: Array) : ApplicationAdapter() {
override fun dispose() {
batch.dispose()
image?.dispose()
- instances.filter { it !== md2Instance }.forEach { it.model.dispose() }
+ instances.forEach { it.model.dispose() }
modelBatch.dispose()
- assetManager.dispose()
}
}
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/stages/Game3dScreen.kt b/cake/core/src/main/kotlin/org/demoth/cake/stages/Game3dScreen.kt
index 81a8269b1..ecca5308a 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/stages/Game3dScreen.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/stages/Game3dScreen.kt
@@ -9,7 +9,6 @@ import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g3d.Environment
import com.badlogic.gdx.graphics.g3d.ModelBatch
-import com.badlogic.gdx.graphics.g3d.Model
import com.badlogic.gdx.graphics.g3d.ModelInstance
import com.badlogic.gdx.graphics.g3d.Renderable
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute
@@ -25,13 +24,14 @@ import jake2.qcommon.network.messages.server.*
import ktx.app.KtxScreen
import ktx.graphics.use
import org.demoth.cake.*
-import org.demoth.cake.assets.BspMapAsset
-import org.demoth.cake.assets.Md2Asset
+import org.demoth.cake.assets.BspLoader
+import org.demoth.cake.assets.GameResourceLocator
import org.demoth.cake.assets.Md2CustomData
-import org.demoth.cake.assets.Md2Loader
+import org.demoth.cake.assets.Md2ModelLoader
import org.demoth.cake.assets.Md2Shader
import org.demoth.cake.assets.Md2ShaderProvider
import org.demoth.cake.assets.SkyLoader
+import org.demoth.cake.assets.createModel
import org.demoth.cake.assets.getLoaded
import java.util.*
import kotlin.math.abs
@@ -52,6 +52,7 @@ class Game3dScreen(
private val modelBatch: ModelBatch
private val collisionModel = CM()
+ private val locator = GameResourceLocator(System.getProperty("basedir"))
private val camera = PerspectiveCamera(90f, Gdx.graphics.width.toFloat(), Gdx.graphics.height.toFloat())
@@ -67,7 +68,6 @@ class Game3dScreen(
private var spawnCount = 0
private var skyBox: ModelInstance? = null
- private val loadedMd2AssetPaths: MutableSet = mutableSetOf()
/**
* id of the player in the game. can be used to determine if the entity is the current player
@@ -149,16 +149,16 @@ class Game3dScreen(
// fixme: make a free internal md2 model specifically for the shader initialization, don't use q2 resources
private fun initializeMd2Shader(): Md2Shader {
- val md2Path = "models/monsters/berserk/tris.md2"
- val md2Asset = assetManager.getLoaded(md2Path)
- loadedMd2AssetPaths += md2Path
- val md2Instance = ModelInstance(md2Asset.model)
+ val md2 = Md2ModelLoader(locator, assetManager)
+ .loadMd2ModelData("models/monsters/berserk/tris.md2", null, 0)!!
+ val model = createModel(md2.mesh, md2.material)
+ val md2Instance = ModelInstance(model)
md2Instance.userData = Md2CustomData(
0,
- if (md2Asset.frames > 1) 1 else 0,
+ if (md2.frames > 1) 1 else 0,
0f,
- md2Asset.frames
+ md2.frames
)
val tempRenderable = Renderable()
@@ -278,24 +278,8 @@ class Game3dScreen(
spriteBatch.dispose()
modelBatch.dispose()
gameConfig.disposeUnmanagedResources()
- loadedMd2AssetPaths.forEach { md2Path ->
- if (assetManager.isLoaded(md2Path, Md2Asset::class.java)) {
- assetManager.unload(md2Path)
- }
- }
- loadedMd2AssetPaths.clear()
- // todo: implement a clear and reusable approach for such resources that need to be disposed
- gameConfig.getSkyname()?.let { skyName ->
- val skyAssetPath = SkyLoader.assetPath(skyName)
- if (assetManager.isLoaded(skyAssetPath, Model::class.java)) {
- assetManager.unload(skyAssetPath)
- }
- }
- gameConfig.getMapName()?.let { mapAssetPath ->
- if (assetManager.isLoaded(mapAssetPath, BspMapAsset::class.java)) {
- assetManager.unload(mapAssetPath)
- }
- }
+ skyBox?.model?.dispose()
+ renderState.dispose() // fixme: what else should be disposed? move skybox into the renderState?
}
/**
@@ -307,8 +291,11 @@ class Game3dScreen(
// load the level
val mapName = gameConfig.getMapName()!! // fixme: disconnect with an error if is null
- val bspMap = assetManager.getLoaded(mapName)
- val brushModels = bspMap.models
+ val mapPath = "${System.getProperty("basedir")}/$gameName/$mapName"
+ assetManager.load(mapPath, ByteArray::class.java)
+ assetManager.finishLoadingAsset(mapPath)
+ val bsp = assetManager.get(mapPath, ByteArray::class.java)
+ val brushModels = BspLoader(locator, assetManager).loadBspModels(bsp)
// load inline bmodels
brushModels.forEachIndexed { index, model ->
@@ -317,7 +304,6 @@ class Game3dScreen(
if (index != 0)
check(configString.value == "*$index") { "Wrong config string value for inline model" }
configString.resource = model
- configString.managedByAssetManager = true
}
// the level will not come as a entity, it is expected to be all the time, so we can instantiate it right away
@@ -325,7 +311,7 @@ class Game3dScreen(
modelInstance = ModelInstance(brushModels.first())
}
- collisionModel.CM_LoadMapFile(bspMap.mapData, mapName, IntArray(1) {0})
+ collisionModel.CM_LoadMapFile(bsp, mapName, IntArray(1) {0})
// load md2 models
// index of md2 models in the config string
@@ -333,14 +319,9 @@ class Game3dScreen(
for (i in startIndex .. MAX_MODELS) {
gameConfig[i]?.let { config ->
config.value.let {
- if (assetManager.fileHandleResolver.resolve(it) != null) {
- val md2Asset = assetManager.getLoaded(
- it,
- Md2Loader.Parameters(skinIndex = 0)
- )
- loadedMd2AssetPaths += it
- config.resource = md2Asset.model
- config.managedByAssetManager = true
+ val md2 = Md2ModelLoader(locator, assetManager).loadMd2ModelData(it, skinIndex = 0)
+ if (md2 != null) {
+ config.resource = createModel(md2.mesh, md2.material)
} else {
println("Failed to load MD2 model data for config ${config.value}")
}
@@ -349,16 +330,12 @@ class Game3dScreen(
}
// temporary: load one fixed player model
- val playerMd2Asset = assetManager.getLoaded(
- playerModelPath,
- Md2Loader.Parameters(
- externalSkinPath = playerSkinPath,
- skinIndex = 0,
- loadAllEmbeddedSkins = false,
- )
- )
- loadedMd2AssetPaths += playerModelPath
- renderState.playerModel = playerMd2Asset.model
+ val playerModelData = Md2ModelLoader(locator, assetManager).loadMd2ModelData(
+ modelName = playerModelPath,
+ playerSkin = playerSkinPath,
+ skinIndex = 0,
+ )!!
+ renderState.playerModel = createModel(playerModelData.mesh, playerModelData.material)
gameConfig.getSounds().forEach { config ->
if (config != null) {
@@ -378,8 +355,7 @@ class Game3dScreen(
}
gameConfig.getSkyname()?.let { skyName ->
- val skyModel = assetManager.getLoaded(SkyLoader.assetPath(skyName))
- skyBox = ModelInstance(skyModel)
+ skyBox = SkyLoader(assetManager).load(skyName)
}
// these are expected to be loaded
@@ -528,6 +504,8 @@ class Game3dScreen(
levelString = msg.levelString
renderState.playerNumber = msg.playerNumber
spawnCount = msg.spawnCount
+
+ locator.gameName = gameName
}
override fun processConfigStringMessage(msg: ConfigStringMessage) {
diff --git a/cake/core/src/main/kotlin/org/demoth/cake/stages/RenderState.kt b/cake/core/src/main/kotlin/org/demoth/cake/stages/RenderState.kt
index ba03cc494..4de405a30 100644
--- a/cake/core/src/main/kotlin/org/demoth/cake/stages/RenderState.kt
+++ b/cake/core/src/main/kotlin/org/demoth/cake/stages/RenderState.kt
@@ -13,4 +13,8 @@ data class RenderState(
var gun: ClientEntity? = null,
var levelModel: ClientEntity? = null,
var playerModel: Model? = null
-)
+) {
+ fun dispose() {
+ playerModel?.dispose()
+ }
+}
\ No newline at end of file
diff --git a/cake/core/src/test/kotlin/org/demoth/cake/assets/BspLoaderTest.kt b/cake/core/src/test/kotlin/org/demoth/cake/assets/BspLoaderTest.kt
deleted file mode 100644
index ec2c87729..000000000
--- a/cake/core/src/test/kotlin/org/demoth/cake/assets/BspLoaderTest.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.demoth.cake.assets
-
-import jake2.qcommon.Defines
-import jake2.qcommon.filesystem.IDBSPHEADER
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import java.nio.ByteBuffer
-import java.nio.ByteOrder
-
-class BspLoaderTest {
-
- @Test
- fun collectWalTexturePathsSkipsSkyAndDeduplicates() {
- val bspData = minimalBspWithTextures(
- textureNames = listOf("floor", "skybox", "floor", " ", "lava")
- )
-
- val paths = collectWalTexturePaths(bspData)
-
- assertEquals(
- listOf(
- "textures/floor.wal",
- "textures/lava.wal",
- ),
- paths
- )
- }
-
- private fun minimalBspWithTextures(textureNames: List): ByteArray {
- val faceCount = textureNames.size
- val facesData = ByteBuffer.allocate(faceCount * 20)
- .order(ByteOrder.LITTLE_ENDIAN)
- .apply {
- repeat(faceCount) { faceIndex ->
- putShort(0) // plane
- putShort(0) // plane side
- putInt(0) // first edge index
- putShort(0) // num edges
- putShort(faceIndex.toShort()) // texture info index
- put(byteArrayOf(0, 0, 0, 0)) // light styles
- putInt(0) // light map offset
- }
- }
- .array()
-
- val texturesData = ByteBuffer.allocate(textureNames.size * 76)
- .order(ByteOrder.LITTLE_ENDIAN)
- .apply {
- textureNames.forEach { textureName ->
- repeat(8) { putFloat(0f) } // uAxis + uOffset + vAxis + vOffset
- putInt(0) // flags
- putInt(0) // value
- val nameBytes = ByteArray(32)
- val rawNameBytes = textureName.toByteArray(Charsets.US_ASCII)
- val copyLen = minOf(rawNameBytes.size, nameBytes.size)
- System.arraycopy(rawNameBytes, 0, nameBytes, 0, copyLen)
- put(nameBytes)
- putInt(0) // next
- }
- }
- .array()
-
- val modelsData = ByteBuffer.allocate(48)
- .order(ByteOrder.LITTLE_ENDIAN)
- .apply {
- repeat(9) { putFloat(0f) } // mins + maxs + origin
- putInt(0) // headNode
- putInt(0) // firstFace
- putInt(faceCount) // faceCount
- }
- .array()
-
- val headerSize = 8 + Defines.HEADER_LUMPS * 8
- val lumpOffsets = IntArray(Defines.HEADER_LUMPS) { 0 }
- val lumpLengths = IntArray(Defines.HEADER_LUMPS) { 0 }
-
- var cursor = headerSize
- // LUMP_TEXINFO
- lumpOffsets[5] = cursor
- lumpLengths[5] = texturesData.size
- cursor += texturesData.size
- // LUMP_FACES
- lumpOffsets[6] = cursor
- lumpLengths[6] = facesData.size
- cursor += facesData.size
- // LUMP_MODELS
- lumpOffsets[13] = cursor
- lumpLengths[13] = modelsData.size
- cursor += modelsData.size
-
- val result = ByteBuffer.allocate(cursor).order(ByteOrder.LITTLE_ENDIAN)
- result.putInt(IDBSPHEADER)
- result.putInt(38) // Quake2 BSP version
-
- for (i in 0 until Defines.HEADER_LUMPS) {
- result.putInt(lumpOffsets[i])
- result.putInt(lumpLengths[i])
- }
-
- result.position(lumpOffsets[5])
- result.put(texturesData)
- result.position(lumpOffsets[6])
- result.put(facesData)
- result.position(lumpOffsets[13])
- result.put(modelsData)
- return result.array()
- }
-}
diff --git a/cake/core/src/test/kotlin/org/demoth/cake/assets/CakeFileResolverTest.kt b/cake/core/src/test/kotlin/org/demoth/cake/assets/CakeFileResolverTest.kt
deleted file mode 100644
index ce44cdd76..000000000
--- a/cake/core/src/test/kotlin/org/demoth/cake/assets/CakeFileResolverTest.kt
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.demoth.cake.assets
-
-import com.badlogic.gdx.ApplicationListener
-import com.badlogic.gdx.Gdx
-import com.badlogic.gdx.backends.headless.HeadlessApplication
-import com.badlogic.gdx.backends.headless.HeadlessApplicationConfiguration
-import org.junit.AfterClass
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotNull
-import org.junit.Assert.assertNull
-import org.junit.Assert.assertTrue
-import org.junit.BeforeClass
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
-import java.io.File
-
-class CakeFileResolverTest {
-
- @get:Rule
- val temp = TemporaryFolder()
-
- @Test
- fun resolvesExactCaseInGamemod() {
- val basedir = temp.root.absolutePath
- val resolver = CakeFileResolver(basedir = basedir, gamemod = "rogue")
- val file = createFile("rogue/sound/Alert.wav")
-
- val resolved = resolver.resolve("sound/Alert.wav")
-
- assertNotNull(resolved)
- assertEquals(file.absolutePath, resolved!!.file().absolutePath)
- }
-
- @Test
- fun resolvesCaseInsensitiveInGamemod() {
- val basedir = temp.root.absolutePath
- val resolver = CakeFileResolver(basedir = basedir, gamemod = "rogue")
- val file = createFile("rogue/berserk/RUN.wav")
-
- val resolved = resolver.resolve("berserk/run.wav")
-
- assertNotNull(resolved)
- assertTrue(resolved!!.exists())
- assertTrue(resolved.file().name.equals(file.name, ignoreCase = true))
- }
-
- @Test
- fun gamemodOverridesBasemod() {
- val basedir = temp.root.absolutePath
- val resolver = CakeFileResolver(basedir = basedir, gamemod = "rogue")
- createFile("baseq2/textures/wall.tga")
- val file = createFile("rogue/textures/wall.tga")
-
- val resolved = resolver.resolve("textures/wall.tga")
-
- assertNotNull(resolved)
- assertEquals(file.absolutePath, resolved!!.file().absolutePath)
- assertTrue(resolved.file().absolutePath.contains("${File.separator}rogue${File.separator}"))
- }
-
- @Test
- fun resolvesVirtualSkyAssetWithoutPhysicalFile() {
- val resolver = CakeFileResolver()
-
- val resolved = resolver.resolve("sky/desert_.sky")
-
- assertNotNull(resolved)
- assertTrue(resolved!!.exists())
- }
-
- @Test
- fun missingAssetReturnsNullWithoutThrowing() {
- val resolver = CakeFileResolver()
-
- val resolved = resolver.resolve("models/missing/file.md2")
-
- assertNull(resolved)
- }
-
- private fun createFile(relativePath: String): File {
- val file = File(temp.root, relativePath)
- file.parentFile.mkdirs()
- file.writeText("")
- return file
- }
-
- companion object {
- private var app: HeadlessApplication? = null
-
- @BeforeClass
- @JvmStatic
- fun setupGdx() {
- if (Gdx.app == null) {
- app = HeadlessApplication(EmptyListener(), HeadlessApplicationConfiguration())
- }
- }
-
- @AfterClass
- @JvmStatic
- fun teardownGdx() {
- app?.exit()
- app = null
- }
- }
-
- private class EmptyListener : ApplicationListener {
- override fun create() = Unit
- override fun resize(width: Int, height: Int) = Unit
- override fun render() = Unit
- override fun pause() = Unit
- override fun resume() = Unit
- override fun dispose() = Unit
- }
-}
diff --git a/cake/core/src/test/kotlin/org/demoth/cake/assets/SkyLoaderTest.kt b/cake/core/src/test/kotlin/org/demoth/cake/assets/SkyLoaderTest.kt
deleted file mode 100644
index feb4f06de..000000000
--- a/cake/core/src/test/kotlin/org/demoth/cake/assets/SkyLoaderTest.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.demoth.cake.assets
-
-import com.badlogic.gdx.files.FileHandle
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-class SkyLoaderTest {
-
- @Test
- fun declaresAllSkyTextureDependencies() {
- val loader = SkyLoader { FileHandle(it) }
- val dependencies = loader.getDependencies(
- SkyLoader.assetPath("desert_"),
- null,
- null
- )
-
- assertEquals(
- listOf(
- "env/desert_rt.pcx",
- "env/desert_bk.pcx",
- "env/desert_lf.pcx",
- "env/desert_ft.pcx",
- "env/desert_up.pcx",
- "env/desert_dn.pcx",
- ),
- dependencies.map { it.fileName }
- )
- }
-}
diff --git a/cake/lwjgl3/build.gradle b/cake/lwjgl3/build.gradle
index d9e37d8e2..3cfb5f43f 100644
--- a/cake/lwjgl3/build.gradle
+++ b/cake/lwjgl3/build.gradle
@@ -1,40 +1,17 @@
-buildscript {
- repositories {
- gradlePluginPortal()
- }
- dependencies {
-// using jpackage only works if the JDK version is 14 or higher.
-// your JAVA_HOME environment variable may also need to be a JDK with version 14 or higher.
- if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) {
- classpath "org.beryx:badass-runtime-plugin:1.13.0"
- }
- if(enableGraalNative == 'true') {
- classpath "org.graalvm.buildtools.native:org.graalvm.buildtools.native.gradle.plugin:0.9.28"
- }
- }
-}
apply plugin: 'org.jetbrains.kotlin.jvm'
-
-if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) {
- apply plugin: 'org.beryx.runtime'
-}
-else {
- apply plugin: 'application'
-}
+apply plugin: 'org.beryx.runtime'
sourceSets.main.resources.srcDirs += [ rootProject.file('assets').path ]
def mainClassName = 'org.demoth.cake.lwjgl3.Lwjgl3GameLauncher'
application {
mainClass.set(mainClassName)
}
-java.sourceCompatibility = 11
-java.targetCompatibility = 11
dependencies {
- implementation "com.badlogicgames.gdx-controllers:gdx-controllers-desktop:$gdxControllersVersion"
- implementation "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion"
- implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
- implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
+ implementation libs.gdx.controllers.desktop
+ implementation libs.gdx.backend.lwjgl3
+ implementation "com.badlogicgames.gdx:gdx-freetype-platform:${libs.versions.gdx.get()}:natives-desktop"
+ implementation "com.badlogicgames.gdx:gdx-platform:${libs.versions.gdx.get()}:natives-desktop"
implementation project(':cake:core')
}
@@ -54,7 +31,7 @@ jar {
// using 'lib' instead of the default 'libs' appears to be needed by jpackageimage.
destinationDirectory = file("${project.layout.buildDirectory.asFile.get().absolutePath}/lib")
// the duplicatesStrategy matters starting in Gradle 7.0; this setting works.
- duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
+ duplicatesStrategy = DuplicatesStrategy.EXCLUDE
dependsOn configurations.runtimeClasspath
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
// these "exclude" lines remove some unnecessary duplicate files in the output JAR.
@@ -72,38 +49,36 @@ jar {
}
}
-if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_14)) {
- tasks.jpackageImage.doNotTrackState("This task both reads from and writes to the build folder.")
- runtime {
- options.set(['--strip-debug',
- '--compress', '2',
- '--no-header-files',
- '--no-man-pages',
- '--strip-native-commands',
- '--vm', 'server'])
+tasks.jpackageImage.doNotTrackState("This task both reads from and writes to the build folder.")
+runtime {
+ options.set(['--strip-debug',
+ '--compress', '2',
+ '--no-header-files',
+ '--no-man-pages',
+ '--strip-native-commands',
+ '--vm', 'server'])
// you could very easily need more modules than this one.
// use the lwjgl3:suggestModules task to see which modules may be needed.
- modules.set([
- 'jdk.unsupported'
- ])
- distDir.set(file(project.layout.buildDirectory))
- jpackage {
- imageName = appName
+ modules.set([
+ 'jdk.unsupported'
+ ])
+ distDir.set(file(project.layout.buildDirectory))
+ jpackage {
+ imageName = appName
// you can set this to false if you want to build an installer, or keep it as true to build just an app.
- skipInstaller = true
+ skipInstaller = true
// this may need to be set to a different path if your JAVA_HOME points to a low JDK version.
- jpackageHome = javaHome.getOrElse("")
- mainJar = jarName
- if (os.contains('win')) {
- imageOptions = ["--icon", "icons/logo.ico"]
- } else if (os.contains('nix') || os.contains('nux') || os.contains('bsd')) {
- imageOptions = ["--icon", "icons/logo.png"]
- } else if (os.contains('mac')) {
+ jpackageHome = javaHome.getOrElse("")
+ mainJar = jarName
+ if (os.contains('win')) {
+ imageOptions = ["--icon", "icons/logo.ico"]
+ } else if (os.contains('nix') || os.contains('nux') || os.contains('bsd')) {
+ imageOptions = ["--icon", "icons/logo.png"]
+ } else if (os.contains('mac')) {
// If you are making a jpackage image on macOS, the below line should work thanks to StartupHelper.
- imageOptions = ["--icon", "icons/logo.icns"]
+ imageOptions = ["--icon", "icons/logo.icns"]
// If the above line doesn't produce a runnable executable, you can try using the below line instead of the above one.
// imageOptions = ["--icon", "icons/logo.icns", "--java-options", "\"-XstartOnFirstThread\""]
- }
}
}
}
diff --git a/cake/lwjgl3/nativeimage.gradle b/cake/lwjgl3/nativeimage.gradle
index bc05477ad..e68d234e2 100644
--- a/cake/lwjgl3/nativeimage.gradle
+++ b/cake/lwjgl3/nativeimage.gradle
@@ -2,8 +2,8 @@ project(":cake:lwjgl3") {
apply plugin: "org.graalvm.buildtools.native"
dependencies {
- implementation "io.github.berstanio:gdx-svmhelper-backend-lwjgl3:$graalHelperVersion"
- implementation "io.github.berstanio:gdx-svmhelper-extension-freetype:$graalHelperVersion"
+ implementation libs.gdx.svmhelper.backend.lwjgl3
+ implementation libs.gdx.svmhelper.extension.freetype
}
graalvmNative {
binaries {
@@ -25,6 +25,6 @@ project(":cake:lwjgl3") {
project(":cake:core") {
dependencies {
- implementation "io.github.berstanio:gdx-svmhelper-annotations:$graalHelperVersion"
+ implementation libs.gdx.svmhelper.annotations
}
}
diff --git a/cake/lwjgl3/src/main/kotlin/org/demoth/cake/lwjgl3/Lwjgl3GameLauncher.kt b/cake/lwjgl3/src/main/kotlin/org/demoth/cake/lwjgl3/Lwjgl3GameLauncher.kt
index 6e8c82297..2547fc410 100644
--- a/cake/lwjgl3/src/main/kotlin/org/demoth/cake/lwjgl3/Lwjgl3GameLauncher.kt
+++ b/cake/lwjgl3/src/main/kotlin/org/demoth/cake/lwjgl3/Lwjgl3GameLauncher.kt
@@ -19,7 +19,6 @@ object Lwjgl3GameLauncher {
private fun getDefaultConfiguration(): Lwjgl3ApplicationConfiguration {
return Lwjgl3ApplicationConfiguration().apply {
setTitle("cake-engine")
- setOpenGLEmulation(Lwjgl3ApplicationConfiguration.GLEmulation.GL32, 3, 2)
setBackBufferConfig(
/* r = */ 8,
/* g = */ 8,
@@ -34,9 +33,9 @@ object Lwjgl3GameLauncher {
useVsync(true)
setForegroundFPS(Lwjgl3ApplicationConfiguration.getDisplayMode().refreshRate)
setResizable(false)
- setWindowedMode(640, 480)
+ setWindowedMode(1200, 900)
// setFullscreenMode(Lwjgl3ApplicationConfiguration.getDisplayMode())
setWindowIcon("libgdx128.png", "libgdx64.png", "libgdx32.png", "libgdx16.png")
}
}
-}
+}
\ No newline at end of file
diff --git a/client/src/main/java/jake2/client/CL.java b/client/src/main/java/jake2/client/CL.java
index 7e4eb03d6..866a11898 100644
--- a/client/src/main/java/jake2/client/CL.java
+++ b/client/src/main/java/jake2/client/CL.java
@@ -43,7 +43,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.sys.Timer;
import jake2.qcommon.util.Lib;
import jake2.qcommon.util.Math3D;
-import jake2.qcommon.util.Vargs;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -670,9 +669,9 @@ private static void Disconnect() {
time = (int) (Timer.Milliseconds() - ClientGlobals.cl.timedemo_start);
if (time > 0)
Com.Printf("%i frames, %3.1f seconds: %3.1f fps\n",
- new Vargs(3).add(ClientGlobals.cl.timedemo_frames).add(
- time / 1000.0).add(
- ClientGlobals.cl.timedemo_frames * 1000.0 / time));
+ ClientGlobals.cl.timedemo_frames,
+ time / 1000.0,
+ ClientGlobals.cl.timedemo_frames * 1000.0 / time);
}
Math3D.VectorClear(ClientGlobals.cl.refdef.blend);
diff --git a/client/src/main/java/jake2/client/CL_inv.java b/client/src/main/java/jake2/client/CL_inv.java
index c9dac5211..2cb4eef90 100644
--- a/client/src/main/java/jake2/client/CL_inv.java
+++ b/client/src/main/java/jake2/client/CL_inv.java
@@ -31,7 +31,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.Defines;
import jake2.qcommon.network.messages.server.InventoryMessage;
import jake2.qcommon.util.Lib;
-import jake2.qcommon.util.Vargs;
/**
* CL_inv
@@ -127,8 +126,8 @@ static void DrawInventory() {
break;
}
- string = Com.sprintf("%6s %3i %s", new Vargs(3).add(bind).add(ClientGlobals.cl.inventory[item]).add(
- ClientGlobals.cl.configstrings[Defines.CS_ITEMS + item]));
+ string = Com.sprintf("%6s %3i %s", bind, ClientGlobals.cl.inventory[item],
+ ClientGlobals.cl.configstrings[Defines.CS_ITEMS + item]);
if (item != selected)
string = getHighBitString(string);
else // draw a blinky cursor by the selected item
diff --git a/client/src/main/java/jake2/client/SCR.java b/client/src/main/java/jake2/client/SCR.java
index c25b25d1c..5dbb5d214 100644
--- a/client/src/main/java/jake2/client/SCR.java
+++ b/client/src/main/java/jake2/client/SCR.java
@@ -36,7 +36,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.filesystem.qfiles;
import jake2.qcommon.network.messages.client.StringCmdMessage;
import jake2.qcommon.sys.Timer;
-import jake2.qcommon.util.Vargs;
import java.awt.*;
import java.nio.ByteBuffer;
@@ -627,8 +626,7 @@ private static void TimeRefresh_f(List args) {
stop = Timer.Milliseconds();
time = (stop - start) / 1000.0f;
- Com.Printf("%f seconds (%f fps)\n", new Vargs(2).add(time).add(
- 128.0f / time));
+ Com.Printf("%f seconds (%f fps)\n", time, 128.0f / time);
}
static void DirtyScreen() {
@@ -991,8 +989,7 @@ private static void ExecuteLayoutString(String s) {
ping = 999;
// sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
- String block = Com.sprintf("%3d %3d %-12.12s", new Vargs(3)
- .add(score).add(ping).add(ci.name));
+ String block = Com.sprintf("%3d %3d %-12.12s", score, ping, ci.name);
if (value == ClientGlobals.cl.playernum)
Console.DrawAltString(x, y, block);
diff --git a/client/src/main/java/jake2/client/V.java b/client/src/main/java/jake2/client/V.java
index fddfaba21..c0c1d2206 100644
--- a/client/src/main/java/jake2/client/V.java
+++ b/client/src/main/java/jake2/client/V.java
@@ -34,7 +34,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.exec.cvar_t;
import jake2.qcommon.sys.Timer;
import jake2.qcommon.util.Math3D;
-import jake2.qcommon.util.Vargs;
import java.io.IOException;
import java.nio.FloatBuffer;
@@ -433,8 +432,8 @@ static void RenderView(float stereo_separation) {
// CDawg
if (cl_stats.value != 0.0f)
- Com.Printf("ent:%i lt:%i part:%i\n", new Vargs(3).add(
- r_numentities).add(r_numdlights).add(r_numparticles));
+ Com.Printf("ent:%i lt:%i part:%i\n",
+ r_numentities, r_numdlights, r_numparticles);
SCR.AddDirtyPoint(ClientGlobals.scr_vrect.x, ClientGlobals.scr_vrect.y);
SCR.AddDirtyPoint(ClientGlobals.scr_vrect.x + ClientGlobals.scr_vrect.width - 1, ClientGlobals.scr_vrect.y
@@ -446,10 +445,10 @@ static void RenderView(float stereo_separation) {
/*
* ============= V_Viewpos_f =============
*/
- private static Command Viewpos_f = (List args) -> Com.Printf("(%i %i %i) : %i\n", new Vargs(4).add(
- (int) ClientGlobals.cl.refdef.vieworg[0]).add((int) ClientGlobals.cl.refdef.vieworg[1])
- .add((int) ClientGlobals.cl.refdef.vieworg[2]).add(
- (int) ClientGlobals.cl.refdef.viewangles[YAW]));
+ private static Command Viewpos_f = (List args) -> Com.Printf("(%i %i %i) : %i\n",
+ (int) ClientGlobals.cl.refdef.vieworg[0], (int) ClientGlobals.cl.refdef.vieworg[1],
+ (int) ClientGlobals.cl.refdef.vieworg[2],
+ (int) ClientGlobals.cl.refdef.viewangles[YAW]);
public static void Init() {
Cmd.AddCommand("gun_next", Gun_Next_f);
diff --git a/client/src/main/java/jake2/client/render/fast/Image.java b/client/src/main/java/jake2/client/render/fast/Image.java
index 6955a8b90..5d5866103 100644
--- a/client/src/main/java/jake2/client/render/fast/Image.java
+++ b/client/src/main/java/jake2/client/render/fast/Image.java
@@ -32,7 +32,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.filesystem.FS;
import jake2.qcommon.filesystem.qfiles;
import jake2.qcommon.util.Lib;
-import jake2.qcommon.util.Vargs;
import java.awt.*;
import java.nio.ByteBuffer;
@@ -341,8 +340,8 @@ void GL_ImageList_f() {
Com.Printf(
Defines.PRINT_ALL,
" %3i %3i %s: %s\n",
- new Vargs(4).add(image.upload_width).add(image.upload_height).add(palstrings[(image.paletted) ? 1 : 0]).add(
- image.name));
+ image.upload_width, image.upload_height, palstrings[(image.paletted) ? 1 : 0],
+ image.name);
}
Com.Printf(Defines.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n');
}
diff --git a/client/src/main/java/jake2/client/render/fast/Main.java b/client/src/main/java/jake2/client/render/fast/Main.java
index 878f3def7..b51b32cf0 100644
--- a/client/src/main/java/jake2/client/render/fast/Main.java
+++ b/client/src/main/java/jake2/client/render/fast/Main.java
@@ -39,7 +39,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.filesystem.qfiles;
import jake2.qcommon.util.Lib;
import jake2.qcommon.util.Math3D;
-import jake2.qcommon.util.Vargs;
import java.awt.*;
import java.nio.FloatBuffer;
@@ -876,7 +875,7 @@ void R_RenderView(refdef_t fd) {
Com.Printf(
Defines.PRINT_ALL,
"%4i wpoly %4i epoly %i tex %i lmaps\n",
- new Vargs(4).add(c_brush_polys).add(c_alias_polys).add(c_visible_textures).add(c_visible_lightmaps));
+ c_brush_polys, c_alias_polys, c_visible_textures, c_visible_lightmaps);
}
}
@@ -1293,7 +1292,7 @@ else if ((gl_config.renderer & GL_RENDERER_POWERVR) != 0) {
Com.Printf(
Defines.PRINT_ALL,
"gl.glGetError() = 0x%x\n\t%s\n",
- new Vargs(2).add(err).add("" + gl.glGetString(err)));
+ err, gl.glGetString(err));
glImpl.endFrame();
return true;
diff --git a/client/src/main/java/jake2/client/sound/lwjgl/LWJGLSoundImpl.java b/client/src/main/java/jake2/client/sound/lwjgl/LWJGLSoundImpl.java
index cb2087ea8..6ae7f271d 100644
--- a/client/src/main/java/jake2/client/sound/lwjgl/LWJGLSoundImpl.java
+++ b/client/src/main/java/jake2/client/sound/lwjgl/LWJGLSoundImpl.java
@@ -17,7 +17,6 @@
import jake2.qcommon.exec.cvar_t;
import jake2.qcommon.filesystem.FS;
import jake2.qcommon.util.Lib;
-import jake2.qcommon.util.Vargs;
import org.lwjgl.LWJGLException;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
@@ -523,7 +522,7 @@ void SoundList() {
Com.Printf("L");
else
Com.Printf(" ");
- Com.Printf("(%2db) %6i : %s\n", new Vargs(3).add(sc.width * 8).add(size).add(sfx.name));
+ Com.Printf("(%2db) %6i : %s\n", sc.width * 8, size, sfx.name);
} else {
if (sfx.name.charAt(0) == '*')
Com.Printf(" placeholder : " + sfx.name + "\n");
@@ -536,10 +535,10 @@ void SoundList() {
void SoundInfo_f() {
- Com.Printf("%5d stereo\n", new Vargs(1).add(1));
- Com.Printf("%5d samples\n", new Vargs(1).add(22050));
- Com.Printf("%5d samplebits\n", new Vargs(1).add(16));
- Com.Printf("%5d speed\n", new Vargs(1).add(44100));
+ Com.Printf("%5d stereo\n", 1);
+ Com.Printf("%5d samples\n", 22050);
+ Com.Printf("%5d samplebits\n", 16);
+ Com.Printf("%5d speed\n", 44100);
}
}
diff --git a/game/build.gradle.kts b/game/build.gradle.kts
index a71259c97..20dda6241 100644
--- a/game/build.gradle.kts
+++ b/game/build.gradle.kts
@@ -1,4 +1,4 @@
dependencies {
implementation(project(":qcommon"))
- implementation("org.apache.commons:commons-csv:1.9.0")
+ implementation(libs.commons.csv)
}
diff --git a/game/src/main/java/jake2/game/Monster.java b/game/src/main/java/jake2/game/Monster.java
index 246d1d48a..e298f1c3a 100644
--- a/game/src/main/java/jake2/game/Monster.java
+++ b/game/src/main/java/jake2/game/Monster.java
@@ -182,18 +182,6 @@ public static void monster_start_go(GameEntity self, GameExportsImpl gameExports
if (self.target != null) {
boolean notcombat = false;
boolean fixup = false;
- /*
- * if (true) { Com.Printf("all entities:\n");
- *
- * for (int n = 0; n < Game.globals.num_edicts; n++) { edict_t ent =
- * gameExports.g_edicts[n]; Com.Printf( "|%4i | %25s
- * |%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f||%8.2f|%8.2f|%8.2f|\n", new
- * Vargs().add(n).add(ent.classname).
- * add(ent.s.origin[0]).add(ent.s.origin[1]).add(ent.s.origin[2])
- * .add(ent.mins[0]).add(ent.mins[1]).add(ent.mins[2])
- * .add(ent.maxs[0]).add(ent.maxs[1]).add(ent.maxs[2])); }
- * sleep(10); }
- */
EdictIterator edit = null;
diff --git a/game/src/main/kotlin/jake2/game/adapters/SuperAdapter.kt b/game/src/main/kotlin/jake2/game/adapters/SuperAdapter.kt
index 4f251e722..0c0ac6729 100644
--- a/game/src/main/kotlin/jake2/game/adapters/SuperAdapter.kt
+++ b/game/src/main/kotlin/jake2/game/adapters/SuperAdapter.kt
@@ -102,12 +102,12 @@ abstract class SuperAdapter {
return adapter
}
- fun registerTouch(id: String, touch: (self: GameEntity, other: GameEntity, plane: cplane_t, surf: csurface_t?, game: GameExportsImpl) -> Unit): EntTouchAdapter {
+ fun registerTouch(id: String, touch: (self: GameEntity, other: GameEntity, plane: cplane_t?, surf: csurface_t?, game: GameExportsImpl) -> Unit): EntTouchAdapter {
val adapter = object : EntTouchAdapter() {
override fun touch(
self: GameEntity,
other: GameEntity,
- plane: cplane_t,
+ plane: cplane_t?,
surf: csurface_t?,
game: GameExportsImpl
) {
diff --git a/gradle.properties b/gradle.properties
index 4a7f43385..5d2d31455 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,12 +7,4 @@ org.gradle.configureondemand=false
org.gradle.workers.max=4
org.gradle.jvmargs=-Xms512M -Xmx1G
-kotlinVersion=1.9.22
-kotlinxCoroutinesVersion=1.6.4
-
-graalHelperVersion=2.0.1
enableGraalNative=true
-
-gdxControllersVersion=2.2.3
-gdxVersion=1.12.1
-ktxVersion=1.12.1-rc1
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 000000000..a2c25ebe8
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,45 @@
+[versions]
+kotlin = "2.1.0"
+kotlinxCoroutines = "1.9.0"
+gdx = "1.12.1"
+gdxControllers = "2.2.3"
+ktx = "1.12.1-rc1"
+commonsCsv = "1.9.0"
+junit = "4.12"
+logback = "1.4.14"
+badassRuntime = "1.13.0"
+graalvmNative = "0.9.28"
+graalHelper = "2.0.1"
+
+[libraries]
+kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
+kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
+gdx = { group = "com.badlogicgames.gdx", name = "gdx", version.ref = "gdx" }
+gdx-freetype = { group = "com.badlogicgames.gdx", name = "gdx-freetype", version.ref = "gdx" }
+gdx-backend-lwjgl3 = { group = "com.badlogicgames.gdx", name = "gdx-backend-lwjgl3", version.ref = "gdx" }
+gdx-platform = { group = "com.badlogicgames.gdx", name = "gdx-platform", version.ref = "gdx" }
+gdx-freetype-platform = { group = "com.badlogicgames.gdx", name = "gdx-freetype-platform", version.ref = "gdx" }
+gdx-controllers-core = { group = "com.badlogicgames.gdx-controllers", name = "gdx-controllers-core", version.ref = "gdxControllers" }
+gdx-controllers-desktop = { group = "com.badlogicgames.gdx-controllers", name = "gdx-controllers-desktop", version.ref = "gdxControllers" }
+ktx-actors = { group = "io.github.libktx", name = "ktx-actors", version.ref = "ktx" }
+ktx-app = { group = "io.github.libktx", name = "ktx-app", version.ref = "ktx" }
+ktx-assets-async = { group = "io.github.libktx", name = "ktx-assets-async", version.ref = "ktx" }
+ktx-assets = { group = "io.github.libktx", name = "ktx-assets", version.ref = "ktx" }
+ktx-async = { group = "io.github.libktx", name = "ktx-async", version.ref = "ktx" }
+ktx-collections = { group = "io.github.libktx", name = "ktx-collections", version.ref = "ktx" }
+ktx-freetype-async = { group = "io.github.libktx", name = "ktx-freetype-async", version.ref = "ktx" }
+ktx-freetype = { group = "io.github.libktx", name = "ktx-freetype", version.ref = "ktx" }
+ktx-graphics = { group = "io.github.libktx", name = "ktx-graphics", version.ref = "ktx" }
+ktx-log = { group = "io.github.libktx", name = "ktx-log", version.ref = "ktx" }
+ktx-scene2d = { group = "io.github.libktx", name = "ktx-scene2d", version.ref = "ktx" }
+commons-csv = { group = "org.apache.commons", name = "commons-csv", version.ref = "commonsCsv" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
+gdx-svmhelper-backend-lwjgl3 = { group = "io.github.berstanio", name = "gdx-svmhelper-backend-lwjgl3", version.ref = "graalHelper" }
+gdx-svmhelper-extension-freetype = { group = "io.github.berstanio", name = "gdx-svmhelper-extension-freetype", version.ref = "graalHelper" }
+gdx-svmhelper-annotations = { group = "io.github.berstanio", name = "gdx-svmhelper-annotations", version.ref = "graalHelper" }
+
+[plugins]
+kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
+badass-runtime = { id = "org.beryx.runtime", version.ref = "badassRuntime" }
+graalvm-native = { id = "org.graalvm.buildtools.native", version.ref = "graalvmNative" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e6441136f..1b33c55ba 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b82aa23a4..e18bc253b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a426..23d15a936 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -112,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -203,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
@@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 25da30dbd..db3a6ac20 100755
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -68,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+set CLASSPATH=
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/info/thirdparty/BSP.md b/info/BSP.md
similarity index 100%
rename from info/thirdparty/BSP.md
rename to info/BSP.md
diff --git a/info/thirdparty/BSP2.md b/info/BSP2.md
similarity index 100%
rename from info/thirdparty/BSP2.md
rename to info/BSP2.md
diff --git a/info/thirdparty/ent_structure.txt b/info/ent_structure.txt
similarity index 100%
rename from info/thirdparty/ent_structure.txt
rename to info/ent_structure.txt
diff --git a/maptools/build.gradle.kts b/maptools/build.gradle.kts
index c8979343e..8067ec122 100644
--- a/maptools/build.gradle.kts
+++ b/maptools/build.gradle.kts
@@ -1,4 +1,4 @@
dependencies {
implementation(project(":qcommon"))
- implementation("ch.qos.logback:logback-classic:1.4.14")
+ implementation(libs.logback.classic)
}
diff --git a/qcommon/src/main/java/jake2/qcommon/CM.java b/qcommon/src/main/java/jake2/qcommon/CM.java
index facfc7a56..d278bf33f 100644
--- a/qcommon/src/main/java/jake2/qcommon/CM.java
+++ b/qcommon/src/main/java/jake2/qcommon/CM.java
@@ -29,7 +29,6 @@
import jake2.qcommon.filesystem.qfiles;
import jake2.qcommon.util.Lib;
import jake2.qcommon.util.Math3D;
-import jake2.qcommon.util.Vargs;
import jake2.qcommon.util.Vec3Cache;
import java.io.RandomAccessFile;
@@ -313,10 +312,10 @@ public void CMod_LoadSubmodels(BspLump l) {
if (debugloadmap) {
Com.DPrintf(
"|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n",
- new Vargs().add(out.headnode)
- .add(out.origin[0]).add(out.origin[1]).add(out.origin[2])
- .add(out.mins[0]).add(out.mins[1]).add(out.mins[2])
- .add(out.maxs[0]).add(out.maxs[1]).add(out.maxs[2]));
+ out.headnode,
+ out.origin[0], out.origin[1], out.origin[2],
+ out.mins[0], out.mins[1], out.mins[2],
+ out.maxs[0], out.maxs[1], out.maxs[2]);
}
}
}
@@ -355,9 +354,8 @@ public void CMod_LoadSurfaces(BspLump l) {
out.c.value = in.value;
if (debugloadmap) {
- Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs()
- .add(out.c.name).add(out.rname).add(out.c.value).add(
- out.c.flags));
+ Com.DPrintf("|%20s|%20s|%6i|%6i|\n",
+ out.c.name, out.rname, out.c.value, out.c.flags);
}
}
@@ -399,8 +397,8 @@ public void CMod_LoadNodes(BspLump l) {
out.children[j] = child;
}
if (debugloadmap) {
- Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum)
- .add(out.children[0]).add(out.children[1]));
+ Com.DPrintf("|%6i| %6i| %6i|\n", in.planenum,
+ out.children[0], out.children[1]);
}
}
}
@@ -434,9 +432,8 @@ public void CMod_LoadBrushes(BspLump l) {
out.contents = in.contents;
if (debugloadmap) {
- Com.DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(
- out.firstbrushside).add(out.numsides).add(
- out.contents));
+ Com.DPrintf("| %6i| %6i| %8X|\n",
+ out.firstbrushside, out.numsides, out.contents);
}
}
}
@@ -483,9 +480,9 @@ public void CMod_LoadLeafs(BspLump l) {
numclusters = out.cluster + 1;
if (debugloadmap) {
- Com.DPrintf("|%8x|%6i|%6i|%6i|\n", new Vargs()
- .add(out.contents).add(out.cluster).add(out.area).add(
- out.firstleafbrush).add(out.numleafbrushes));
+ Com.DPrintf("|%8x|%6i|%6i|%6i|\n",
+ out.contents, out.cluster, out.area,
+ out.firstleafbrush, out.numleafbrushes);
}
}
@@ -558,9 +555,9 @@ public void CMod_LoadPlanes(BspLump l) {
if (debugloadmap) {
Com.DPrintf("|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n",
- new Vargs().add(out.normal[0]).add(out.normal[1]).add(
- out.normal[2]).add(out.dist).add(out.type).add(
- out.signbits));
+ out.normal[0], out.normal[1],
+ out.normal[2], out.dist, out.type,
+ out.signbits);
}
}
}
@@ -596,7 +593,7 @@ public void CMod_LoadLeafBrushes(BspLump l) {
for (int i = 0; i < count; i++) {
out[i] = bb.getShort();
if (debugloadmap) {
- Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i]));
+ Com.DPrintf("|%6i|%6i|\n", i, out[i]);
}
}
}
@@ -649,7 +646,7 @@ public void CMod_LoadBrushSides(BspLump l) {
out.surface = map_surfaces[j];
if (debugloadmap) {
- Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j));
+ Com.DPrintf("| %6i| %6i|\n", num, j);
}
}
}
@@ -688,8 +685,8 @@ public void CMod_LoadAreas(BspLump l) {
out.floodvalid = 0;
out.floodnum = 0;
if (debugloadmap) {
- Com.DPrintf("| %6i| %6i|\n", new Vargs()
- .add(out.numareaportals).add(out.firstareaportal));
+ Com.DPrintf("| %6i| %6i|\n",
+ out.numareaportals, out.firstareaportal);
}
}
}
@@ -725,8 +722,7 @@ public void CMod_LoadAreaPortals(BspLump l) {
out.otherarea = in.otherarea;
if (debugloadmap) {
- Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(
- out.otherarea));
+ Com.DPrintf("|%6i|%6i|\n", out.portalnum, out.otherarea);
}
}
}
diff --git a/qcommon/src/main/java/jake2/qcommon/Com.java b/qcommon/src/main/java/jake2/qcommon/Com.java
index a39670103..d8303cbe8 100644
--- a/qcommon/src/main/java/jake2/qcommon/Com.java
+++ b/qcommon/src/main/java/jake2/qcommon/Com.java
@@ -28,7 +28,6 @@ of the License, or (at your option) any later version.
import jake2.qcommon.exec.Cmd;
import jake2.qcommon.sys.Sys;
import jake2.qcommon.util.PrintfFormat;
-import jake2.qcommon.util.Vargs;
/**
* Common print related functions including redirection
@@ -41,14 +40,14 @@ public final class Com
private static String _debugContext = "";
public static void Printf(int print_level, String fmt) {
- Printf(print_level, fmt, null);
+ Printf(print_level, fmt, (Object[]) null);
}
- public static void Printf(int print_level, String fmt, Vargs vargs) {
+ public static void Printf(int print_level, String fmt, Object... args) {
if (print_level == Defines.PRINT_ALL)
- Printf(fmt, vargs);
+ Printf(fmt, args);
else
- DPrintf(fmt, vargs);
+ DPrintf(fmt, args);
}
public interface RD_Flusher {
@@ -235,10 +234,10 @@ public static String Parse(ParseHelp hlp) {
public static void Error(int code, String fmt) throws longjmpException
{
- Error(code, fmt, null);
+ Error(code, fmt, (Object[]) null);
}
- public static void Error(int code, String fmt, Vargs vargs) throws longjmpException
+ public static void Error(int code, String fmt, Object... args) throws longjmpException
{
if (recursive)
{
@@ -246,7 +245,7 @@ public static void Error(int code, String fmt, Vargs vargs) throws longjmpExcept
}
recursive= true;
- msg= sprintf(fmt, vargs);
+ msg= sprintf(fmt, args);
if (code == Defines.ERR_DISCONNECT)
{
@@ -271,36 +270,24 @@ else if (code == Defines.ERR_DROP)
Sys.Error(msg);
}
- public static void DPrintf(String fmt)
- {
- _debugContext = debugContext;
- DPrintf(fmt, null);
- _debugContext = "";
- }
-
- public static void dprintln(String fmt)
- {
- DPrintf(_debugContext + fmt + "\n", null);
- }
-
- public static void Printf(String fmt)
- {
- Printf(_debugContext + fmt, null);
- }
-
- public static void DPrintf(String fmt, Vargs vargs)
+ public static void DPrintf(String fmt, Object... args)
{
if (Globals.developer == null || Globals.developer.value == 0)
return; // don't confuse non-developers with techie stuff...
_debugContext = debugContext;
- Printf(fmt, vargs);
+ Printf(fmt, args);
_debugContext="";
}
+ public static void dprintln(String fmt)
+ {
+ DPrintf(_debugContext + fmt + "\n");
+ }
+
/** Prints out messages, which can also be redirected to a remote client. */
- public static void Printf(String fmt, Vargs vargs)
+ public static void Printf(String fmt, Object... args)
{
- String msg= sprintf(_debugContext + fmt, vargs);
+ String msg= sprintf(_debugContext + fmt, args);
if (rd_flusher != null)
{
if ((msg.length() + rd_buffer.length()) > (rd_buffersize - 1))
@@ -329,12 +316,11 @@ public static void Warn(String fmt) {
Printf("Warn: " + fmt + "\n");
}
- @Deprecated
- public static String sprintf(String fmt, Vargs vargs) {
- if (vargs == null || vargs.size() == 0) {
+ public static String sprintf(String fmt, Object... args) {
+ if (args == null || args.length == 0) {
return fmt;
} else {
- return new PrintfFormat(fmt).sprintf(vargs.toArray());
+ return new PrintfFormat(fmt).sprintf(args);
}
}
diff --git a/qcommon/src/main/java/jake2/qcommon/MainCommon.java b/qcommon/src/main/java/jake2/qcommon/MainCommon.java
index 826833a58..fc3986066 100644
--- a/qcommon/src/main/java/jake2/qcommon/MainCommon.java
+++ b/qcommon/src/main/java/jake2/qcommon/MainCommon.java
@@ -1,7 +1,5 @@
package jake2.qcommon;
-import jake2.qcommon.util.Vargs;
-
import java.io.FileWriter;
import java.io.IOException;
@@ -11,7 +9,7 @@
public class MainCommon {
public static void debugLogTraces() {
if (Globals.showtrace.value != 0.0f) {
- Com.Printf("%4i traces %4i points\n", new Vargs(2).add(Globals.c_traces).add(Globals.c_pointcontents));
+ Com.Printf("%4i traces %4i points\n", Globals.c_traces, Globals.c_pointcontents);
Globals.c_traces= 0;
Globals.c_brush_traces= 0;
Globals.c_pointcontents= 0;
diff --git a/qcommon/src/main/java/jake2/qcommon/util/Lib.java b/qcommon/src/main/java/jake2/qcommon/util/Lib.java
index 2c96db402..3a84b21d4 100644
--- a/qcommon/src/main/java/jake2/qcommon/util/Lib.java
+++ b/qcommon/src/main/java/jake2/qcommon/util/Lib.java
@@ -51,7 +51,7 @@ public static String vtofs(float[] v) {
/** Converts a vector to a beatiful string. */
public static String vtofsbeaty(float[] v) {
- return Com.sprintf("%8.2f %8.2f %8.2f", new Vargs().add(v[0]).add(v[1]).add(v[2]));
+ return Com.sprintf("%8.2f %8.2f %8.2f", v[0], v[1], v[2]);
}
/** Like in libc. */
diff --git a/qcommon/src/main/java/jake2/qcommon/util/Vargs.java b/qcommon/src/main/java/jake2/qcommon/util/Vargs.java
deleted file mode 100644
index 82caf950f..000000000
--- a/qcommon/src/main/java/jake2/qcommon/util/Vargs.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Vargs.java
- * Copyright (C) 2003
- *
- * $Id: Vargs.java,v 1.1 2004-07-07 19:59:56 hzi Exp $
- */
-/*
-Copyright (C) 1997-2001 Id Software, Inc.
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-package jake2.qcommon.util;
-
-import java.util.Vector;
-
-/**
- * Vargs is a helper class to encapsulate printf arguments.
- *
- * @author cwei
- */
-@Deprecated
-public class Vargs {
-
- // initial capacity
- static final int SIZE = 5;
-
- Vector v;
-
- public Vargs() {
- this(SIZE);
- }
-
- public Vargs(int initialSize) {
- if (v != null)
- v.clear(); // clear previous list for GC
- v = new Vector(initialSize);
- }
-
- public Vargs add(boolean value) {
- v.add(Boolean.valueOf(value));
- return this;
- }
-
- public Vargs add(byte value) {
- v.add(Byte.valueOf(value));
- return this;
- }
-
- public Vargs add(char value) {
- v.add(Character.valueOf(value));
- return this;
- }
-
- public Vargs add(short value) {
- v.add(Short.valueOf(value));
- return this;
- }
-
- public Vargs add(int value) {
- v.add(Integer.valueOf(value));
- return this;
- }
-
- public Vargs add(long value) {
- v.add(Long.valueOf(value));
- return this;
- }
-
- public Vargs add(float value) {
- v.add(Float.valueOf(value));
- return this;
- }
-
- public Vargs add(double value) {
- v.add(Double.valueOf(value));
- return this;
- }
-
- public Vargs add(String value) {
- v.add(value);
- return this;
- }
-
- public Vargs add(Object value) {
- v.add(value);
- return this;
- }
-
- public Vargs clear() {
- v.clear();
- return this;
- }
-
- public Vector toVector() {
- // Vector tmp = v;
- // v = null;
- // return tmp;
- return (Vector) v.clone();
- }
-
- public Object[] toArray() {
- return v.toArray();
- }
-
- public int size() {
- return v.size();
- }
-}
diff --git a/server/src/main/java/jake2/server/GameImportsImpl.java b/server/src/main/java/jake2/server/GameImportsImpl.java
index 089b0fc0d..79e69ace1 100644
--- a/server/src/main/java/jake2/server/GameImportsImpl.java
+++ b/server/src/main/java/jake2/server/GameImportsImpl.java
@@ -36,7 +36,6 @@
import jake2.qcommon.network.messages.server.ServerMessage;
import jake2.qcommon.network.messages.server.StuffTextMessage;
import jake2.qcommon.util.Lib;
-import jake2.qcommon.util.Vargs;
import java.io.IOException;
import java.util.Date;
@@ -453,8 +452,8 @@ private void SV_Status_f(List args) {
if (ClientStates.CS_FREE == cl.state)
continue;
- Com.Printf("%3i ", new Vargs().add(i));
- Com.Printf("%5i ", new Vargs().add(cl.edict.getClient().getPlayerState().stats[Defines.STAT_FRAGS]));
+ Com.Printf("%3i ", i);
+ Com.Printf("%5i ", cl.edict.getClient().getPlayerState().stats[Defines.STAT_FRAGS]);
if (cl.state == ClientStates.CS_CONNECTED)
Com.Printf("CNCT ");
@@ -462,16 +461,16 @@ else if (cl.state == ClientStates.CS_ZOMBIE)
Com.Printf("ZMBI ");
else {
int ping = cl.ping < 9999 ? cl.ping : 9999;
- Com.Printf("%4i ", new Vargs().add(ping));
+ Com.Printf("%4i ", ping);
}
- Com.Printf("%s", new Vargs().add(cl.name));
+ Com.Printf("%s", cl.name);
int l = 16 - cl.name.length();
int j;
for (j = 0; j < l; j++)
Com.Printf(" ");
- Com.Printf("%7i ", new Vargs().add(realtime - cl.lastmessage));
+ Com.Printf("%7i ", realtime - cl.lastmessage);
String s = cl.netchan.remote_address.toString();
Com.Printf(s);
@@ -479,7 +478,7 @@ else if (cl.state == ClientStates.CS_ZOMBIE)
for (j = 0; j < l; j++)
Com.Printf(" ");
- Com.Printf("%5i", new Vargs().add(cl.netchan.qport));
+ Com.Printf("%5i", cl.netchan.qport);
Com.Printf("\n");
i++;
diff --git a/server/src/main/java/jake2/server/SV_WORLD.java b/server/src/main/java/jake2/server/SV_WORLD.java
index 87ed2ac6a..caab0f45c 100644
--- a/server/src/main/java/jake2/server/SV_WORLD.java
+++ b/server/src/main/java/jake2/server/SV_WORLD.java
@@ -118,15 +118,6 @@ private static areanode_t SV_CreateAreaNode(int depth, float[] mins,
static void SV_ClearWorld(GameImportsImpl gameImports) {
gameImports.world.clearAreaNodes();
SV_CreateAreaNode(0, gameImports.sv.models[1].mins, gameImports.sv.models[1].maxs, gameImports);
- /*
- * Com.p("areanodes:" + sv_numareanodes + " (sollten 32 sein)."); for
- * (int n = 0; n < sv_numareanodes; n++) { Com.Printf( "|%3i|%2i|%8.2f
- * |%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n", new Vargs() .add(n)
- * .add(sv_areanodes[n].axis) .add(sv_areanodes[n].dist)
- * .add(sv_areanodes[n].mins_rst[0]) .add(sv_areanodes[n].mins_rst[1])
- * .add(sv_areanodes[n].mins_rst[2]) .add(sv_areanodes[n].maxs_rst[0])
- * .add(sv_areanodes[n].maxs_rst[1]) .add(sv_areanodes[n].maxs_rst[2])); }
- */
}
/*
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 8fd5772bd..cb9b878af 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,23 @@
+pluginManagement {
+ repositories {
+ mavenCentral()
+ gradlePluginPortal()
+ google()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ mavenCentral()
+ maven { url = uri("https://s01.oss.sonatype.org") }
+ mavenLocal()
+ maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
+ maven { url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") }
+ maven { url = uri("https://jitpack.io") }
+ google()
+ }
+}
+
rootProject.name = "jake2"
include (":qcommon")
include (":game")