Skip to content

Commit

Permalink
Merge pull request #179 from Poeschl/obfuscate-map-data
Browse files Browse the repository at this point in the history
Minimize map tile transfer
  • Loading branch information
Poeschl authored Jul 28, 2024
2 parents 88fb71d + 88cf333 commit 58acdfd
Show file tree
Hide file tree
Showing 16 changed files with 289 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import xyz.poeschl.roborush.configuration.OpenApiConfig
import xyz.poeschl.roborush.controller.restmodels.PlaygroundMap
import xyz.poeschl.roborush.gamelogic.GameHandler
import xyz.poeschl.roborush.models.Game
import xyz.poeschl.roborush.repositories.Map

@RestController
@RequestMapping("/game")
class GameRestController(private val gameHandler: GameHandler) {

@GetMapping("/map", produces = [MediaType.APPLICATION_JSON_VALUE])
fun getMap(): Map {
return gameHandler.getCurrentMap()
fun getMap(): PlaygroundMap {
return gameHandler.getCurrentPlaygroundMap()
}

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.stereotype.Controller
import xyz.poeschl.roborush.gamelogic.GameState
import xyz.poeschl.roborush.models.ActiveRobot
import xyz.poeschl.roborush.models.Position
import xyz.poeschl.roborush.models.PublicRobot
import xyz.poeschl.roborush.models.settings.ClientSettings
import xyz.poeschl.roborush.repositories.Map

@Controller
class WebsocketController(private val messageTemplate: SimpMessagingTemplate) {
Expand Down Expand Up @@ -37,7 +37,7 @@ class WebsocketController(private val messageTemplate: SimpMessagingTemplate) {
messageTemplate.convertAndSendToUser(user, "/queue/robot/knownPositions", robot.knownPositions)
}

fun sendGlobalKnownPositionsUpdate(knownPositions: Set<Position>) {
messageTemplate.convertAndSend("/topic/robot/knownPositions", knownPositions)
fun sendMapTileUpdate(map: Map) {
messageTemplate.convertAndSend("/topic/map/tiles", map.mapData)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,41 @@
package xyz.poeschl.roborush.controller.restmodels

import xyz.poeschl.roborush.models.Position
import xyz.poeschl.roborush.models.Size
import xyz.poeschl.roborush.repositories.Map
import xyz.poeschl.roborush.repositories.Tile

data class MapGenerationResult(val warnings: List<String>)

data class MapActiveDto(val active: Boolean)

data class MapAttributeSaveDto(val mapName: String, val maxRobotFuel: Int, val solarChargeRate: Double)

data class PlaygroundMap(
val id: Long,
val mapName: String,
val size: Size,
val possibleStartPositions: List<Position>,
val targetPosition: Position,
val maxRobotFuel: Int = 300,
val solarChargeRate: Double = 0.0,
val active: Boolean = false,
val mapData: List<Tile> = mutableListOf(),
val minHeight: Int,
val maxHeight: Int
) {

constructor(map: Map, minHeight: Int, maxHeight: Int) : this(
map.id!!,
map.mapName,
map.size,
map.possibleStartPositions,
map.targetPosition,
map.maxRobotFuel,
map.solarChargeRate,
map.active,
map.mapData,
minHeight,
maxHeight
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import xyz.poeschl.roborush.configuration.GameLogic
import xyz.poeschl.roborush.controller.WebsocketController
import xyz.poeschl.roborush.controller.restmodels.PlaygroundMap
import xyz.poeschl.roborush.exceptions.PositionNotAllowedException
import xyz.poeschl.roborush.exceptions.PositionOutOfMapException
import xyz.poeschl.roborush.gamelogic.actions.RobotAction
Expand Down Expand Up @@ -40,8 +41,19 @@ class GameHandler(
private var currentTurn = 0
private var detectedIdleTurns = 0

@Cacheable("knownMap")
fun getCurrentMap(): Map {
return mapHandler.getCurrentMap()
return mapHandler.getMapWithPositions(getGlobalKnownPositions())
}

@Cacheable("playgroundMap")
fun getCurrentPlaygroundMap(): PlaygroundMap {
val fullMap = mapHandler.getCurrentFullMap()

val minHeight = fullMap.mapData.minOf { it.height }
val maxHeight = fullMap.mapData.maxOf { it.height }

return PlaygroundMap(getCurrentMap(), minHeight, maxHeight)
}

fun getTileAtPosition(position: Position): Tile {
Expand Down Expand Up @@ -80,7 +92,6 @@ class GameHandler(
websocketController.sendRobotUpdate(activeRobot)
websocketController.sendUserRobotData(activeRobot)
websocketController.sendKnownPositionsUpdate(activeRobot)
websocketController.sendGlobalKnownPositionsUpdate(robotHandler.getAllActiveRobots().map { it.knownPositions }.flatten().toSet())
}

fun getFuelCostForMove(current: Position, next: Position): Int {
Expand Down Expand Up @@ -118,9 +129,11 @@ class GameHandler(
}
}

@CacheEvict(cacheNames = ["knownMap", "playgroundMap"], allEntries = true)
fun executeAllRobotActions() {
robotHandler.executeRobotActions(this)
setGameTurn(currentTurn + 1)
websocketController.sendMapTileUpdate(getCurrentMap())
}

fun registerRobotForNextGame(robotId: Long) {
Expand All @@ -136,7 +149,7 @@ class GameHandler(
websocketController.sendRobotUpdate(registeredRobot)
websocketController.sendUserRobotData(registeredRobot)
websocketController.sendKnownPositionsUpdate(registeredRobot)
websocketController.sendGlobalKnownPositionsUpdate(robotHandler.getAllActiveRobots().map { it.knownPositions }.flatten().toSet())
websocketController.sendMapTileUpdate(getCurrentMap())
}
} else {
throw PositionNotAllowedException("Could not place robot at a empty start position.")
Expand All @@ -156,7 +169,6 @@ class GameHandler(
robotHandler.setRobotMaxFuel(map.maxRobotFuel)
robotHandler.clearActiveRobots()
setGameTurn(0)
websocketController.sendGlobalKnownPositionsUpdate(emptySet())
}

@Cacheable("gameInfoCache")
Expand All @@ -172,7 +184,7 @@ class GameHandler(
gameEnd = configService.getDurationSetting(SettingKey.TIMEOUT_GAME_END).value.inWholeMilliseconds
),
nameOfWinningRobot = robotHandler.getWinningRobot()?.user?.username,
mapSize = mapHandler.getCurrentMap().size,
mapSize = mapHandler.getCurrentFullMap().size,
fullMapScanPossible = configService.getBooleanSetting(SettingKey.ENABLE_FULL_MAP_SCAN).value
)
}
Expand All @@ -195,4 +207,18 @@ class GameHandler(
}

fun isFullMapScanPossible() = configService.getBooleanSetting(SettingKey.ENABLE_FULL_MAP_SCAN).value

fun getKnownPositionsForRobot(robotId: Long): Set<Position>? {
return robotHandler.getActiveRobot(robotId)?.knownPositions
}

fun getGlobalKnownPositions(): Set<Position> {
val positions = robotHandler.getAllActiveRobots().map { it.knownPositions }.flatten().toMutableSet()

if (configService.getBooleanSetting(SettingKey.TARGET_POSITION_IN_GAMEINFO).value) {
positions.add(mapHandler.getTargetPosition())
}

return positions
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ class MapHandler {
private const val TILE_SCAN_COST = 0.1
}

fun getCurrentMap(): Map {
fun getCurrentFullMap(): Map {
return currentMap
}

fun getMapWithPositions(positions: Set<Position>): Map {
val reducedMap = Map(
currentMap.id,
currentMap.mapName,
currentMap.size,
currentMap.possibleStartPositions,
currentMap.targetPosition,
currentMap.maxRobotFuel,
currentMap.solarChargeRate,
currentMap.active
)

positions.forEach { pos -> reducedMap.addTile(getTileAtPosition(pos)) }
return reducedMap
}

fun getStartPositions(): List<Position> {
return currentMap.possibleStartPositions
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ class RobotService(private val robotRepository: RobotRepository, private val gam
}

fun getKnownPositionsForRobot(robotId: Long): Set<Position> {
return gameHandler.getActiveRobot(robotId)?.knownPositions ?: throw RobotNotActiveException("No active Robot found")
return gameHandler.getKnownPositionsForRobot(robotId) ?: throw RobotNotActiveException("No active Robot found")
}

fun getKnownPositionsForAllRobots(): Set<Position> {
return gameHandler.getActiveRobots().map { it.knownPositions }.flatten().toSet()
return gameHandler.getGlobalKnownPositions()
}
}
2 changes: 2 additions & 0 deletions backend/src/test/kotlin/xyz/poeschl/roborush/GamePlayTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import xyz.poeschl.roborush.service.MapService
import xyz.poeschl.roborush.service.PlayedGamesService
import xyz.poeschl.roborush.test.utils.builder.Builders.Companion.a
import xyz.poeschl.roborush.test.utils.builder.Builders.Companion.listWithOne
import xyz.poeschl.roborush.test.utils.builder.ConfigTypes.Companion.`$BooleanSetting`
import xyz.poeschl.roborush.test.utils.builder.ConfigTypes.Companion.`$IntSetting`
import xyz.poeschl.roborush.test.utils.builder.GameLogicBuilder.Companion.`$Map`
import xyz.poeschl.roborush.test.utils.builder.GameLogicBuilder.Companion.`$Position`
Expand Down Expand Up @@ -53,6 +54,7 @@ class GamePlayTest {
every { mapService.getNextChallengeMap() } returns createMapWithFuelStation()
every { robotRepository.findById(robot.id!!) } returns Optional.of(robot)
every { configService.getIntSetting(SettingKey.DISTANCE_ROBOT_SIGHT_ON_MOVE) } returns a(`$IntSetting`().withValue(1))
every { configService.getBooleanSetting(SettingKey.TARGET_POSITION_IN_GAMEINFO) } returns a(`$BooleanSetting`())

gameStateMachine.setGameState(GameState.PREPARE)
gameHandler.prepareNewGame()
Expand Down
Loading

0 comments on commit 58acdfd

Please sign in to comment.