summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1b645ed)
raw | patch | inline | side by side (parent: 1b645ed)
author | fredboy <fredboy@protonmail.com> | |
Sat, 20 Apr 2024 13:02:13 +0000 (20:02 +0700) | ||
committer | fredboy <fredboy@protonmail.com> | |
Sat, 20 Apr 2024 13:02:13 +0000 (20:02 +0700) |
12 files changed:
diff --git a/build.gradle b/build.gradle
index 10228bd66a6bed664013db7868a828f298737fec..821b6e351e96248da3692ba798cbe6debba26370 100644 (file)
--- a/build.gradle
+++ b/build.gradle
buildscript {
+ ext {
+ appName = "CaveDroid"
+ gdxVersion = '1.12.0'
+ guavaVersion = '28.1'
+ daggerVersion = '2.51.1'
+ kotlinVersion = '1.9.23'
+ kotlinSerializationVersion = '1.6.3'
+ }
+
repositories {
mavenLocal()
mavenCentral()
dependencies {
classpath 'com.android.tools.build:gradle:8.2.2'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.23"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
allprojects {
version = 'alpha0.5.2'
- ext {
- appName = "CaveDroid"
- gdxVersion = '1.12.0'
- guavaVersion = '28.1'
- daggerVersion = '2.51.1'
- }
repositories {
mavenLocal()
project(":core") {
apply plugin: "java-library"
+
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion"
api "com.google.guava:guava:$guavaVersion-android"
api "com.google.dagger:dagger:$daggerVersion"
implementation 'org.jetbrains:annotations:23.1.0'
- implementation "org.jetbrains.kotlin:kotlin-stdlib:1.9.23"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
}
}
\ No newline at end of file
diff --git a/core/build.gradle b/core/build.gradle
index d968841dbff78228ef471c0889b4b0a190d0530d..cdf2ee7e4708ffec3ab49447cc63298a1f77caab 100644 (file)
--- a/core/build.gradle
+++ b/core/build.gradle
id "org.jetbrains.kotlin.jvm"
id "kotlin"
id "idea"
+ id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlinVersion"
}
sourceCompatibility = 17
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameItems.java b/core/src/ru/deadsoftware/cavedroid/game/GameItems.java
index 7cf525263a52dec4c252f87d6e91129b45ada223..4024c3614c111a17c64c689ad8fc80b5a500a05e 100644 (file)
import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin;
+import java.io.FileInputStream;
import java.util.*;
public class GameItems {
);
Block newBlock = switch (meta) {
- case "water" -> new Block.Water(params, 5);
- case "lava" -> new Block.Lava(params, 5);
+ case "water" -> new Block.Water(params);
+ case "lava" -> new Block.Lava(params);
case "slab" -> new Block.Slab(params, fullBlock);
default -> new Block.Normal(params);
};
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt b/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt
--- /dev/null
@@ -0,0 +1,96 @@
+package ru.deadsoftware.cavedroid.game
+
+import com.badlogic.gdx.Gdx
+import kotlinx.serialization.json.Json
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.model.dto.BlockDto
+import ru.deadsoftware.cavedroid.game.model.dto.GameItemsDto
+import ru.deadsoftware.cavedroid.game.model.dto.ItemDto
+import ru.deadsoftware.cavedroid.game.model.item.Item
+import ru.deadsoftware.cavedroid.game.model.mapper.BlockMapper
+import ru.deadsoftware.cavedroid.game.model.mapper.ItemMapper
+import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
+import javax.inject.Inject
+
+@GameScope
+class GameItemsHolder @Inject constructor(
+ private val blockMapper: BlockMapper,
+ private val itemMapper: ItemMapper,
+) {
+
+ private var _initialized: Boolean = false
+
+ private val blocksMap = LinkedHashMap<String, Block>()
+ private val itemsMap = LinkedHashMap<String, Item>()
+
+ private lateinit var fallbackBlock: Block
+ private lateinit var fallbackItem: Item
+
+
+
+ private fun loadBlocks(dtoMap: Map<String, BlockDto>) {
+ dtoMap.forEach { (key, dto) ->
+ blocksMap[key] = blockMapper.map(key, dto)
+ }
+
+ fallbackBlock = blocksMap[FALLBACK_BLOCK_KEY]
+ ?: throw IllegalArgumentException("Fallback block key '$FALLBACK_BLOCK_KEY' not found")
+ }
+
+ private fun loadItems(dtoMap: Map<String, ItemDto>) {
+ if (dtoMap.isNotEmpty() && blocksMap.isEmpty()) {
+ throw IllegalStateException("items should be loaded after blocks")
+ }
+
+ dtoMap.forEach { (key, dto) ->
+ itemsMap[key] = itemMapper.map(key, dto, blocksMap[key])
+ }
+
+ fallbackItem = itemsMap[FALLBACK_ITEM_KEY]
+ ?: throw IllegalArgumentException("Fallback item key '$FALLBACK_ITEM_KEY' not found")
+ }
+
+ fun initialize(assetLoader: AssetLoader) {
+ if (_initialized) {
+ Gdx.app.debug(TAG, "Attempted to init when already initialized")
+ return
+ }
+
+ val jsonString = assetLoader.getAssetHandle("json/game_items.json").readString()
+ val gameItemsDto = JsonFormat.decodeFromString(GameItemsDto.GameItemsDtoJsonSerializer, jsonString)
+
+ loadBlocks(gameItemsDto.blocks)
+ loadItems(gameItemsDto.items)
+
+ _initialized = true
+ }
+
+ private fun <T> Map<String, T>.getOrFallback(key: String, fallback: T, lazyErrorMessage: () -> String): T {
+ val t = this[key] ?: run {
+ Gdx.app.error(TAG, lazyErrorMessage.invoke())
+ return fallback
+ }
+ return t
+ }
+
+ fun getBlock(key: String): Block {
+ return blocksMap.getOrFallback(key, fallbackBlock) {
+ "No block with key '$key' found. Returning $FALLBACK_BLOCK_KEY"
+ }
+ }
+
+ fun getItem(key: String): Item {
+ return itemsMap.getOrFallback(key, fallbackItem) {
+ "No item with key '$key' found. Returning $FALLBACK_BLOCK_KEY"
+ }
+ }
+
+ companion object {
+ private const val TAG = "GameItemsHolder"
+
+ private val JsonFormat = Json { ignoreUnknownKeys = true }
+
+ const val FALLBACK_BLOCK_KEY = "none"
+ const val FALLBACK_ITEM_KEY = "none"
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameProc.java b/core/src/ru/deadsoftware/cavedroid/game/GameProc.java
index 139a31ba61e8dbe98d54fb458944de45450a35f2..0c3947b499e789a144cad218de8bf294b90e0e9c 100644 (file)
import ru.deadsoftware.cavedroid.game.mobs.MobsController;
import ru.deadsoftware.cavedroid.game.world.GameWorldBlocksLogicControllerTask;
import ru.deadsoftware.cavedroid.game.world.GameWorldFluidsLogicControllerTask;
+import ru.deadsoftware.cavedroid.misc.utils.AssetLoader;
import javax.inject.Inject;
private final MobsController mMobsController;
private final GameWorldFluidsLogicControllerTask mGameWorldFluidsLogicControllerTask;
private final GameWorldBlocksLogicControllerTask mGameWorldBlocksLogicControllerTask;
+ private final GameItemsHolder mGameItemsHolder;
private final Timer mWorldLogicTimer = new Timer();
GameRenderer gameRenderer,
MobsController mobsController,
GameWorldFluidsLogicControllerTask gameWorldFluidsLogicControllerTask,
- GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask
+ GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask,
+ GameItemsHolder gameItemsHolder,
+ AssetLoader assetLoader
) {
mGamePhysics = gamePhysics;
mGameInput = gameInput;
mMobsController = mobsController;
mGameWorldFluidsLogicControllerTask = gameWorldFluidsLogicControllerTask;
mGameWorldBlocksLogicControllerTask = gameWorldBlocksLogicControllerTask;
+ mGameItemsHolder = gameItemsHolder;
+
+ mGameItemsHolder.initialize(assetLoader);
mWorldLogicTimer.scheduleTask(gameWorldFluidsLogicControllerTask, 0,
GameWorldFluidsLogicControllerTask.FLUID_UPDATE_INTERVAL_SEC);
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt b/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt
index 62c6f493e0f8d66221bc54d1a297dc506a28f688..45363440e290fad732955cddb78424b7c2e6c01f 100644 (file)
val fullBlockKey: String,
): Block()
- sealed class Fluid: Block() {
- abstract val statesCount: Int
- }
+ sealed class Fluid: Block()
data class Water(
override val params: CommonBlockParams,
- override val statesCount: Int
) : Fluid()
data class Lava(
override val params: CommonBlockParams,
- override val statesCount: Int
) : Fluid()
/* Legacy accessors below */
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt b/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt
--- /dev/null
@@ -0,0 +1,29 @@
+package ru.deadsoftware.cavedroid.game.model.dto
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class BlockDto(
+ @Deprecated("numeric ids will be removed") @SerialName("id") val id: Int,
+ @SerialName("left") val left: Int = 0,
+ @SerialName("top") val top: Int = 0,
+ @SerialName("right") val right: Int = 0,
+ @SerialName("bottom") val bottom: Int = 0,
+ @SerialName("sprite_left") val spriteLeft: Int = 0,
+ @SerialName("sprite_top") val spriteTop: Int = 0,
+ @SerialName("sprite_right") val spriteRight: Int = 0,
+ @SerialName("sprite_bottom") val spriteBottom: Int = 0,
+ @SerialName("hp") val hp: Int = -1,
+ @SerialName("collision") val collision: Boolean = true,
+ @SerialName("background") val background: Boolean = false,
+ @SerialName("transparent") val transparent: Boolean = false,
+ @SerialName("block_required") val blockRequired: Boolean = false,
+ @SerialName("drop") val drop: String,
+ @SerialName("meta") val meta: String? = null,
+ @SerialName("texture") val texture: String,
+ @SerialName("animated") val animated: Boolean = false,
+ @SerialName("frames") val frames: Int = 0,
+ @SerialName("drop_count") val dropCount: Int = 1,
+ @SerialName("full_block") val fullBlock: String? = null,
+)
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/dto/GameItemsDto.kt b/core/src/ru/deadsoftware/cavedroid/game/model/dto/GameItemsDto.kt
--- /dev/null
@@ -0,0 +1,50 @@
+package ru.deadsoftware.cavedroid.game.model.dto
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.json.*
+
+@Serializable
+data class GameItemsDto(
+ @SerialName("blocks") val blocks: Map<String, BlockDto>,
+ @SerialName("items") val items: Map<String, ItemDto>,
+) {
+ object GameItemsDtoJsonSerializer : JsonTransformingSerializer<GameItemsDto>(GameItemsDto.serializer()) {
+ private val defaultBlockValuesEqualKeyFieldNames = listOf("drop", "texture")
+ private val defaultItemValuesEqualKeyFieldNames = listOf("name", "texture")
+
+ override fun transformDeserialize(element: JsonElement): JsonElement {
+ val root = element.jsonObject
+ val blocks = root["blocks"]!!.jsonObject
+ val items = root["items"]!!.jsonObject
+
+ return buildJsonObject {
+ putJsonObject("blocks") {
+ blocks.forEach { (key, blockObj) ->
+ putJsonObject(key) {
+ defaultBlockValuesEqualKeyFieldNames.forEach { fieldName ->
+ put(fieldName, key)
+ }
+ blockObj.jsonObject.forEach { (prop, propValue) ->
+ put(prop, propValue)
+ }
+ }
+ }
+ }
+
+ putJsonObject("items") {
+ items.forEach { (key, itemObj) ->
+ putJsonObject(key) {
+ defaultItemValuesEqualKeyFieldNames.forEach { fieldName ->
+ put(fieldName, key)
+ }
+ itemObj.jsonObject.forEach { (prop, propValue) ->
+ put(prop, propValue)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt b/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt
--- /dev/null
@@ -0,0 +1,17 @@
+package ru.deadsoftware.cavedroid.game.model.dto
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ItemDto(
+ @Deprecated("numeric ids will be removed") @SerialName("id") val id: Int,
+ @SerialName("name") val name: String,
+ @SerialName("type") val type: String,
+ @SerialName("texture") val texture: String,
+ @SerialName("origin_x") val originX: Float = 0f,
+ @SerialName("origin_y") val origin_y: Float = 1f,
+ @SerialName("action_key") val actionKey: String? = null,
+ @SerialName("mob_damage_multiplier") val mobDamageMultiplier: Float = 1f,
+ @SerialName("block_damage_multiplier") val blockDamageMultiplier: Float = 1f,
+)
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt
--- /dev/null
@@ -0,0 +1,87 @@
+package ru.deadsoftware.cavedroid.game.model.mapper
+
+import com.badlogic.gdx.graphics.Texture
+import dagger.Reusable
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.model.block.*
+import ru.deadsoftware.cavedroid.game.model.block.Block.*
+import ru.deadsoftware.cavedroid.game.model.dto.BlockDto
+import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
+import javax.inject.Inject
+
+@Reusable
+class BlockMapper @Inject constructor(
+ private val assetLoader: AssetLoader,
+) {
+
+ fun map(key: String, dto: BlockDto): Block {
+ val commonBlockParams = mapCommonParams(key, dto)
+
+ return when (dto.meta) {
+ "water" -> Water(commonBlockParams)
+ "lava" -> Lava(commonBlockParams)
+ "slab" -> Slab(commonBlockParams, requireNotNull(dto.fullBlock))
+ else -> Normal(commonBlockParams)
+ }
+ }
+
+ private fun mapCommonParams(key: String, dto: BlockDto): CommonBlockParams {
+ return CommonBlockParams(
+ id = dto.id,
+ key = key,
+ collisionMargins = BlockMargins(
+ left = dto.left,
+ top = dto.top,
+ right = dto.right,
+ bottom = dto.bottom
+ ),
+ hitPoints = dto.hp,
+ dropInfo = mapBlockDropInfo(dto),
+ hasCollision = dto.collision,
+ isBackground = dto.background,
+ isTransparent = dto.transparent,
+ requiresBlock = dto.blockRequired,
+ animationInfo = mapBlockAnimationInfo(dto),
+ texture = loadTexture(dto.texture),
+ spriteMargins = BlockMargins(
+ left = dto.spriteLeft,
+ top = dto.spriteTop,
+ right = dto.spriteRight,
+ bottom = dto.spriteBottom,
+ )
+ )
+ }
+
+ private fun mapBlockDropInfo(dto: BlockDto): BlockDropInfo? {
+ val drop = dto.drop
+ val dropCount = dto.dropCount
+
+ if (drop == GameItemsHolder.FALLBACK_ITEM_KEY || dropCount == 0) {
+ return null
+ }
+
+ return BlockDropInfo(
+ itemKey = drop,
+ count = dropCount,
+ )
+ }
+
+ private fun mapBlockAnimationInfo(dto: BlockDto): BlockAnimationInfo? {
+ if (!dto.animated) {
+ return null
+ }
+
+ return BlockAnimationInfo(
+ framesCount = dto.frames,
+ )
+ }
+
+ private fun loadTexture(textureName: String): Texture? {
+ if (textureName == GameItemsHolder.FALLBACK_BLOCK_KEY) {
+ return null
+ }
+
+ return Texture(assetLoader.getAssetHandle("textures/blocks/$textureName.png"))
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt
--- /dev/null
@@ -0,0 +1,53 @@
+package ru.deadsoftware.cavedroid.game.model.mapper
+
+import com.badlogic.gdx.graphics.Texture
+import com.badlogic.gdx.graphics.g2d.Sprite
+import dagger.Reusable
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.model.dto.ItemDto
+import ru.deadsoftware.cavedroid.game.model.item.CommonItemParams
+import ru.deadsoftware.cavedroid.game.model.item.Item
+import ru.deadsoftware.cavedroid.game.model.item.Item.*
+import ru.deadsoftware.cavedroid.misc.utils.AssetLoader
+import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin
+import javax.inject.Inject
+
+@Reusable
+class ItemMapper @Inject constructor(
+ private val assetLoader: AssetLoader,
+) {
+
+ fun map(key: String, dto: ItemDto, block: Block?): Item {
+ val params = mapCommonParams(key, dto)
+
+ return when (dto.type) {
+ "bucket" -> Bucket(params, requireNotNull(loadSprite(dto)), requireNotNull(dto.actionKey))
+ "shovel" -> Shovel(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier)
+ "sword" -> Sword(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier)
+ "block" -> Placeable(params, requireNotNull(block))
+ else -> throw IllegalArgumentException("Unknown item type ${dto.type}")
+ }
+ }
+
+ private fun mapCommonParams(key: String, dto: ItemDto): CommonItemParams {
+ return CommonItemParams(
+ id = dto.id,
+ key = key,
+ name = dto.name,
+ inHandSpriteOrigin = SpriteOrigin(
+ x = dto.originX,
+ y = dto.origin_y,
+ )
+ )
+ }
+
+ private fun loadSprite(dto: ItemDto): Sprite? {
+ if (dto.type == "block" || dto.texture == GameItemsHolder.FALLBACK_ITEM_KEY) {
+ return null
+ }
+
+ return Sprite(Texture(assetLoader.getAssetHandle("textures/items/${dto.texture}.png")))
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/AssetLoader.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/AssetLoader.kt
index 5b897199a19c6d21e28727d58efac86923ef4fd8..7fb5df176396b8b0c28675477fd4f09e61a5e6dc 100644 (file)
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import ru.deadsoftware.cavedroid.MainConfig
+import ru.deadsoftware.cavedroid.game.GameScope
import java.io.File
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class AssetLoader @Inject constructor(
private val mainConfig: MainConfig,
) {