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")