+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-import ru.deadsoftware.cavedroid.game.GameScope
-import ru.deadsoftware.cavedroid.game.actions.placeblock.IPlaceBlockAction
-import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceBlockItemToBackgroundAction
-import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceBlockItemToForegroundAction
-import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceSlabAction
-
-@Module
-class PlaceBlockActionsModule {
-
- @Binds
- @IntoMap
- @StringKey(PlaceBlockItemToForegroundAction.ACTION_KEY)
- @GameScope
- fun bindPlaceBlockItemToForegroundAction(action: PlaceBlockItemToForegroundAction): IPlaceBlockAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(PlaceBlockItemToBackgroundAction.ACTION_KEY)
- @GameScope
- fun bindPlaceBlockItemToBackgroundAction(action: PlaceBlockItemToBackgroundAction): IPlaceBlockAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(PlaceSlabAction.ACTION_KEY)
- @GameScope
- fun bindPlaceSlabAction(action: PlaceSlabAction): IPlaceBlockAction {
- return action
- }
-
-}
\ No newline at end of file
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-import ru.deadsoftware.cavedroid.game.GameScope
-import ru.deadsoftware.cavedroid.game.actions.updateblock.*
-
-@Module
-class UpdateBlockActionsModule {
-
- @Binds
- @IntoMap
- @StringKey(UpdateSandAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateSandAction(action: UpdateSandAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateGravelAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateGravelAction(action: UpdateGravelAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateRequiresBlockAction.ACTION_KEY)
- @GameScope
- fun bindUpdateRequiresBlockAction(action: UpdateRequiresBlockAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateGrassAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateGrassAction(action: UpdateGrassAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateSnowedGrassAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateSnowedGrassAction(action: UpdateSnowedGrassAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateBedLeftAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateBedLeftAction(action: UpdateBedLeftAction): IUpdateBlockAction {
- return action;
- }
-
- @Binds
- @IntoMap
- @StringKey(UpdateBedRightAction.BLOCK_KEY)
- @GameScope
- fun bindUpdateBedRightAction(action: UpdateBedRightAction): IUpdateBlockAction {
- return action;
- }
-}
\ No newline at end of file
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-import ru.deadsoftware.cavedroid.game.GameScope
-import ru.deadsoftware.cavedroid.game.actions.useblock.IUseBlockAction
-import ru.deadsoftware.cavedroid.game.actions.useblock.UseChestAction
-import ru.deadsoftware.cavedroid.game.actions.useblock.UseCraftingTableAction
-import ru.deadsoftware.cavedroid.game.actions.useblock.UseFurnaceAction
-
-@Module
-class UseBlockActionsModule {
-
- @Binds
- @IntoMap
- @StringKey(UseCraftingTableAction.KEY)
- @GameScope
- fun bindUseCraftingTableAction(action: UseCraftingTableAction): IUseBlockAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UseFurnaceAction.KEY)
- @GameScope
- fun bindUseFurnaceTableAction(action: UseFurnaceAction): IUseBlockAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UseChestAction.KEY)
- @GameScope
- fun bindUseChestAction(action: UseChestAction): IUseBlockAction {
- return action
- }
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions
-
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-import ru.deadsoftware.cavedroid.game.GameScope
-import ru.deadsoftware.cavedroid.game.actions.useitem.*
-
-@Module
-class UseItemActionsModule {
-
- @Binds
- @IntoMap
- @StringKey(UseWaterBucketAction.ACTION_KEY)
- @GameScope
- fun bindUseWaterBucketAction(action: UseWaterBucketAction): IUseItemAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UseLavaBucketAction.ACTION_KEY)
- @GameScope
- fun bindUseLavaBucketAction(action: UseLavaBucketAction): IUseItemAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UseEmptyBucketAction.ACTION_KEY)
- @GameScope
- fun bindUseEmptyBucketAction(action: UseEmptyBucketAction): IUseItemAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UsePigSpawnEggAction.ACTION_KEY)
- @GameScope
- fun bindUsePigSpawnEgg(action: UsePigSpawnEggAction): IUseItemAction {
- return action
- }
-
- @Binds
- @IntoMap
- @StringKey(UseBedAction.ACTION_KEY)
- @GameScope
- fun bindUseBedAction(action: UseBedAction): IUseItemAction {
- return action
- }
-
-}
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions.placeblock
-
-import ru.deadsoftware.cavedroid.game.model.item.Item
-
-interface IPlaceBlockAction {
-
- fun place(placeable: Item.Placeable, x: Int, y: Int)
-
-}
--- /dev/null
+package ru.deadsoftware.cavedroid.game.actions.placeblock
+
+import ru.deadsoftware.cavedroid.game.model.item.Item
+import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
+
+@GenerateMapMultibindingsModule(
+ interfaceClass = IPlaceBlockAction::class,
+ modulePackage = "ru.deadsoftware.cavedroid.game.actions",
+ moduleName = "PlaceBlockActionsModule"
+)
+annotation class PlaceBlockAction(val stringKey: String)
+
+interface IPlaceBlockAction {
+
+ fun place(placeable: Item.Placeable, x: Int, y: Int)
+
+}
import javax.inject.Inject
@GameScope
+@PlaceBlockAction(stringKey = PlaceBlockItemToBackgroundAction.ACTION_KEY)
class PlaceBlockItemToBackgroundAction @Inject constructor(
private val gameWorld: GameWorld,
private val gameItemsHolder: GameItemsHolder,
import javax.inject.Inject
@GameScope
+@PlaceBlockAction(stringKey = PlaceBlockItemToForegroundAction.ACTION_KEY)
class PlaceBlockItemToForegroundAction @Inject constructor(
private val gameWorld: GameWorld,
private val placeSlabAction: PlaceSlabAction,
import javax.inject.Inject
@GameScope
+@PlaceBlockAction(stringKey = PlaceSlabAction.ACTION_KEY)
class PlaceSlabAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
package ru.deadsoftware.cavedroid.game.actions.updateblock
+import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
+
+@GenerateMapMultibindingsModule(
+ interfaceClass = IUpdateBlockAction::class,
+ modulePackage = "ru.deadsoftware.cavedroid.game.actions",
+ moduleName = "UpdateBlockActionsModule"
+)
+annotation class UpdateBlockAction(val stringKey: String)
+
interface IUpdateBlockAction {
fun update(x: Int, y: Int)
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateBedLeftAction.BLOCK_KEY)
class UpdateBedLeftAction @Inject constructor(
private val gameWorld: GameWorld,
private val gameItemsHolder: GameItemsHolder,
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateBedRightAction.BLOCK_KEY)
class UpdateBedRightAction @Inject constructor(
private val gameWorld: GameWorld,
private val gameItemsHolder: GameItemsHolder,
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateGrassAction.BLOCK_KEY)
class UpdateGrassAction @Inject constructor(
private val gameWorld: GameWorld,
private val mGameItemsHolder: GameItemsHolder,
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateGravelAction.BLOCK_KEY)
class UpdateGravelAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateRequiresBlockAction.ACTION_KEY)
class UpdateRequiresBlockAction @Inject constructor(
private val gameWorld: GameWorld,
) : IUpdateBlockAction {
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateSandAction.BLOCK_KEY)
class UpdateSandAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
import javax.inject.Inject
@GameScope
+@UpdateBlockAction(stringKey = UpdateSnowedGrassAction.BLOCK_KEY)
class UpdateSnowedGrassAction @Inject constructor(
private val gameWorld: GameWorld,
private val mGameItemsHolder: GameItemsHolder,
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions.useblock
-
-import ru.deadsoftware.cavedroid.game.model.block.Block
-
-interface IUseBlockAction {
-
- fun perform(block: Block, x: Int, y: Int)
-
-}
\ No newline at end of file
--- /dev/null
+package ru.deadsoftware.cavedroid.game.actions.useblock
+
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
+
+@GenerateMapMultibindingsModule(
+ interfaceClass = IUseBlockAction::class,
+ modulePackage = "ru.deadsoftware.cavedroid.game.actions",
+ moduleName = "UseBlockActionsModule"
+)
+annotation class UseBlockAction(val stringKey: String)
+
+interface IUseBlockAction {
+
+ fun perform(block: Block, x: Int, y: Int)
+
+}
\ No newline at end of file
import javax.inject.Inject
@GameScope
+@UseBlockAction(stringKey = UseChestAction.KEY)
class UseChestAction @Inject constructor(
private val gameWorld: GameWorld,
private val gameWindowsManager: GameWindowsManager,
import javax.inject.Inject
@GameScope
+@UseBlockAction(stringKey = UseCraftingTableAction.KEY)
class UseCraftingTableAction @Inject constructor(
private val gameWindowsManager: GameWindowsManager
) : IUseBlockAction {
import javax.inject.Inject
@GameScope
+@UseBlockAction(stringKey = UseFurnaceAction.KEY)
class UseFurnaceAction @Inject constructor(
private val gameWorld: GameWorld,
private val gameWindowsManager: GameWindowsManager,
+++ /dev/null
-package ru.deadsoftware.cavedroid.game.actions.useitem
-
-import ru.deadsoftware.cavedroid.game.model.item.Item
-
-interface IUseItemAction {
-
- fun perform(item: Item.Usable, x: Int, y: Int)
-
-}
\ No newline at end of file
import javax.inject.Inject
@GameScope
+@UseItemAction(UseBedAction.ACTION_KEY)
class UseBedAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
import javax.inject.Inject
@GameScope
+@UseItemAction(UseEmptyBucketAction.ACTION_KEY)
class UseEmptyBucketAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
--- /dev/null
+package ru.deadsoftware.cavedroid.game.actions.useitem
+
+import ru.deadsoftware.cavedroid.game.model.item.Item
+import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
+
+@GenerateMapMultibindingsModule(
+ interfaceClass = IUseItemAction::class,
+ modulePackage = "ru.deadsoftware.cavedroid.game.actions",
+ moduleName = "UseItemActionsModule"
+)
+annotation class UseItemAction(val stringKey: String)
+
+interface IUseItemAction {
+
+ fun perform(item: Item.Usable, x: Int, y: Int)
+
+}
\ No newline at end of file
import javax.inject.Inject
@GameScope
+@UseItemAction(UseLavaBucketAction.ACTION_KEY)
class UseLavaBucketAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
import javax.inject.Inject
@GameScope
+@UseItemAction(UsePigSpawnEggAction.ACTION_KEY)
class UsePigSpawnEggAction @Inject constructor(
private val mobsController: MobsController,
private val gameItemsHolder: GameItemsHolder,
import javax.inject.Inject
@GameScope
+@UseItemAction(UseWaterBucketAction.ACTION_KEY)
class UseWaterBucketAction @Inject constructor(
private val gameWorld: GameWorld,
private val mobsController: MobsController,
--- /dev/null
+package ru.fredboy.cavedroid.ksp.annotations
+
+import kotlin.reflect.KClass
+
+/**
+ * Annotation annotated with this must include stringKey parameter for key selection in generated module
+ */
+@Target(AnnotationTarget.ANNOTATION_CLASS)
+@Retention(AnnotationRetention.SOURCE)
+annotation class GenerateMapMultibindingsModule(
+ val interfaceClass: KClass<*>,
+ val modulePackage: String,
+ val moduleName: String,
+)
--- /dev/null
+package ru.fredboy.cavedroid.ksp.processor
+
+import com.google.devtools.ksp.processing.*
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.symbol.KSClassDeclaration
+import com.google.devtools.ksp.symbol.KSType
+import com.squareup.kotlinpoet.*
+import com.squareup.kotlinpoet.ksp.toClassName
+import com.squareup.kotlinpoet.ksp.writeTo
+import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
+
+class GenerateMapMultibindingsSymbolProcessor(
+ private val codeGenerator: CodeGenerator,
+ private val logger: KSPLogger,
+) : SymbolProcessor {
+
+ private fun generateModule(
+ annotationName: String,
+ interfaceName: ClassName,
+ moduleName: ClassName,
+ classes: List<KSClassDeclaration>
+ ): FileSpec? {
+ if (classes.isEmpty()) {
+ return null
+ }
+
+ val bindings = classes.map { decl ->
+ val stringKey = decl.annotations.first { declAnn ->
+ declAnn.shortName.getShortName() == annotationName
+ }.arguments.firstOrNull { arg ->
+ arg.name!!.getShortName() == "stringKey"
+ }?.value as? String ?: run {
+ logger.error("@${annotationName} must include stringKey parameter for key selection in generated module")
+ throw IllegalArgumentException()
+ }
+
+ val clazz = decl.toClassName()
+
+ FunSpec.builder("bind${clazz.simpleName}")
+ .addAnnotation(ClassName("dagger", "Binds"))
+ .addAnnotation(ClassName("dagger.multibindings", "IntoMap"))
+ .addAnnotation(
+ AnnotationSpec.builder(ClassName("dagger.multibindings", "StringKey"))
+ .addMember("\"$stringKey\"")
+ .build()
+ )
+ .addParameter(ParameterSpec("impl", clazz))
+ .returns(interfaceName)
+ .addCode("return impl")
+ .build()
+ }
+
+ val moduleObject = TypeSpec.objectBuilder(moduleName)
+ .addAnnotation(ClassName("dagger", "Module"))
+ .addFunctions(bindings)
+ .build()
+
+ return FileSpec.builder(moduleName)
+ .addType(moduleObject)
+ .build()
+
+ }
+
+ private fun processAnnotation(resolver: Resolver, annotation: KSClassDeclaration) {
+ val args = annotation.annotations.first {
+ it.shortName.getShortName() == "GenerateMapMultibindingsModule"
+ }.arguments.takeIf { it.size == 3 } ?: run {
+ logger.error("GenerateMapMultibindingsModule should have 3 arguments")
+ throw IllegalArgumentException()
+ }
+
+ val interfaceName = args.first { it.name?.getShortName() == "interfaceClass" }.value as KSType
+ val modulePackage = args.first { it.name?.getShortName() == "modulePackage" }.value as String
+ val moduleName = args.first { it.name?.getShortName() == "moduleName" }.value as String
+
+ val moduleClassName = ClassName(modulePackage, moduleName)
+ val elements = resolver.getSymbolsWithAnnotation(annotation.qualifiedName!!.asString())
+ .filterIsInstance<KSClassDeclaration>()
+ .toList()
+
+ logger.info("Found elements: ${elements.joinToString()}")
+
+ generateModule(
+ annotationName = annotation.qualifiedName!!.getShortName(),
+ interfaceName = interfaceName.toClassName(),
+ moduleName = moduleClassName,
+ classes = elements
+ )?.writeTo(codeGenerator, Dependencies(true))
+ }
+
+ override fun process(resolver: Resolver): List<KSAnnotated> {
+ val annotations = resolver.getAnnotatedClasses(GenerateMapMultibindingsModule::class.qualifiedName!!, logger)
+ logger.info("Found annotations: ${annotations.joinToString { it.qualifiedName!!.asString() }}")
+ annotations.forEach { processAnnotation(resolver, it) }
+ return emptyList()
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package ru.fredboy.cavedroid.ksp.provider
+
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.processing.SymbolProcessorProvider
+import ru.fredboy.cavedroid.ksp.processor.GenerateMapMultibindingsSymbolProcessor
+
+internal class GenerateMapMultibindingsSymbolProcessorProvider : SymbolProcessorProvider {
+
+ override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+ return GenerateMapMultibindingsSymbolProcessor(
+ codeGenerator = environment.codeGenerator,
+ logger = environment.logger,
+ )
+ }
+
+}
\ No newline at end of file
ru.fredboy.cavedroid.ksp.provider.GenerateSetMultibindingsSymbolProcessorProvider
+ru.fredboy.cavedroid.ksp.provider.GenerateMapMultibindingsSymbolProcessorProvider