refactor web-map to be SPA
This commit is contained in:
parent
de419aeae8
commit
a84c4a2f76
17 changed files with 329 additions and 267 deletions
|
|
@ -173,3 +173,8 @@ val installThemeCss by tasks.registering(Copy::class) {
|
|||
tasks.assemble {
|
||||
dependsOn(installThemeCss)
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<io.kvision.gradle.tasks.KVConvertPoTask>().configureEach {
|
||||
enabled = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
FROM nginx
|
||||
|
||||
COPY ./nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
COPY ./build/distributions /usr/share/nginx/html
|
||||
|
|
|
|||
25
modules/web-map/docker/nginx.conf
Normal file
25
modules/web-map/docker/nginx.conf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
http {
|
||||
# what times to include
|
||||
# include /etc/nginx/mime.types;
|
||||
# what is the default one
|
||||
#default_type application/octet-stream;
|
||||
|
||||
# Sets the path, format, and configuration for a buffered log write
|
||||
#log_format compression '$remote_addr - $remote_user [$time_local] '
|
||||
#'"$request" $status $upstream_addr '
|
||||
#'"$http_referer" "$http_user_agent"';
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
# First attempt to serve request as file, then
|
||||
# as directory, then fall back to redirecting to index.html
|
||||
try_files $uri $uri/ $uri.html /index.html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,15 +4,19 @@ import dev.adamko.kafkatorio.schema.packets.EventServerPacket
|
|||
import dev.adamko.kafkatorio.webmap.layout.headerNav
|
||||
import dev.adamko.kafkatorio.webmap.layout.homePage
|
||||
import dev.adamko.kafkatorio.webmap.layout.servers.serverPage
|
||||
import dev.adamko.kafkatorio.webmap.routing.SiteRouter
|
||||
import dev.adamko.kafkatorio.webmap.routing.SiteView
|
||||
import dev.adamko.kafkatorio.webmap.services.WebsocketService
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteAction
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteState
|
||||
import io.kvision.Application
|
||||
import io.kvision.BootstrapIconsModule
|
||||
import io.kvision.BootstrapModule
|
||||
import io.kvision.ChartModule
|
||||
import io.kvision.CoreModule
|
||||
import io.kvision.FontAwesomeModule
|
||||
import io.kvision.html.Link
|
||||
import io.kvision.html.div
|
||||
import io.kvision.html.h3
|
||||
import io.kvision.html.header
|
||||
import io.kvision.html.main
|
||||
import io.kvision.module
|
||||
|
|
@ -20,7 +24,6 @@ import io.kvision.panel.root
|
|||
import io.kvision.redux.ReduxStore
|
||||
import io.kvision.redux.createReduxStore
|
||||
import io.kvision.require
|
||||
import io.kvision.routing.Routing
|
||||
import io.kvision.startApplication
|
||||
import io.kvision.state.bind
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
|
|
@ -51,6 +54,7 @@ object App : Application() {
|
|||
var siteStateStore: ReduxStore<SiteState, SiteAction> by appState
|
||||
private set
|
||||
|
||||
|
||||
init {
|
||||
this.siteStateStore = createReduxStore(SiteState::plus, SiteState())
|
||||
|
||||
|
|
@ -65,27 +69,17 @@ object App : Application() {
|
|||
}.launchIn(coroutineScope)
|
||||
}
|
||||
|
||||
// private val gameState: FactorioGameState
|
||||
// get() = reduxStore.getState()
|
||||
|
||||
// private val kvMaps: Maps
|
||||
// get() = gameState.map.kvMap
|
||||
|
||||
override fun start(state: Map<String, Any>) {
|
||||
Routing.init(useHash = false)
|
||||
SiteRouter.init()
|
||||
|
||||
this.appState = state.toMutableMap()
|
||||
|
||||
SiteRouting.init()
|
||||
|
||||
root("kvapp") {
|
||||
|
||||
header().bind(siteStateStore) { state ->
|
||||
headerNav(state)
|
||||
}
|
||||
|
||||
h3("Kafkatorio Web Map")
|
||||
|
||||
main().bind(siteStateStore) { state ->
|
||||
div(className = "container-fluid") {
|
||||
when (state.view) {
|
||||
|
|
@ -93,6 +87,7 @@ object App : Application() {
|
|||
SiteView.SERVER -> serverPage(state)
|
||||
}
|
||||
}
|
||||
SiteRouter.updatePageLinks()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +102,7 @@ object App : Application() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
override fun dispose(): Map<String, Any> {
|
||||
rootJob.cancelChildren()
|
||||
rootJob.cancel("app dispose")
|
||||
|
|
@ -119,7 +115,10 @@ object App : Application() {
|
|||
|
||||
fun main() {
|
||||
startApplication(
|
||||
{ App },
|
||||
{
|
||||
Link.useDataNavigoForLinks = true
|
||||
App
|
||||
},
|
||||
module.hot,
|
||||
BootstrapModule,
|
||||
// BootstrapCssModule,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
package dev.adamko.kafkatorio.webmap.layout
|
||||
|
||||
import dev.adamko.kafkatorio.webmap.SiteState
|
||||
import dev.adamko.kafkatorio.webmap.SiteView
|
||||
import dev.adamko.kafkatorio.webmap.routing.SiteView
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteState
|
||||
import io.kvision.core.Container
|
||||
import io.kvision.navbar.nav
|
||||
import io.kvision.navbar.navLink
|
||||
import io.kvision.navbar.navbar
|
||||
|
||||
|
||||
fun Container.headerNav(state: SiteState) {
|
||||
navbar {
|
||||
navbar(label = "Kafkatorio", link = SiteView.HOME.path) {
|
||||
nav {
|
||||
navLink("Home", SiteView.HOME.path)
|
||||
// navLink("Home", SiteView.HOME.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +1,89 @@
|
|||
package dev.adamko.kafkatorio.webmap.layout
|
||||
|
||||
import dev.adamko.kafkatorio.webmap.SiteRouting
|
||||
import dev.adamko.kafkatorio.webmap.SiteState
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteState
|
||||
import io.kvision.core.Container
|
||||
import io.kvision.html.ButtonSize
|
||||
import io.kvision.html.ButtonStyle
|
||||
import io.kvision.html.button
|
||||
import io.kvision.html.ListType
|
||||
import io.kvision.html.div
|
||||
import io.kvision.html.h5
|
||||
import io.kvision.html.span
|
||||
import io.kvision.html.li
|
||||
import io.kvision.html.link
|
||||
import io.kvision.html.listTag
|
||||
import io.kvision.html.p
|
||||
|
||||
|
||||
fun Container.homePage(state: SiteState) {
|
||||
div(className = "home-page") {
|
||||
introduction()
|
||||
servers(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun Container.introduction() {
|
||||
div {
|
||||
h5("Introduction")
|
||||
// <a target="_blank" href="https://github.com/adamko-dev/kafkatorio">Kafkatorio</a>
|
||||
p(
|
||||
"""
|
||||
Kafkatorio is a platform used for creating
|
||||
<a target="_blank" href="https://www.factorio.com/">Factorio</a> mods that require communication with an external server.
|
||||
""".trimIndent(),
|
||||
rich = true,
|
||||
)
|
||||
p(
|
||||
"""
|
||||
It was created to explore the possibilities of using
|
||||
<a target="_blank" href="https://kafka.apache.org/">Apache Kafka</a>
|
||||
to process updates from a Factorio server.
|
||||
""".trimIndent(),
|
||||
rich = true,
|
||||
)
|
||||
p("To keep up to date on progress, check out:")
|
||||
listTag(ListType.UL) {
|
||||
link(
|
||||
label = "Factorio Mod Portal",
|
||||
url = "https://mods.factorio.com/mod/kafkatorio-events",
|
||||
target = "_blank"
|
||||
)
|
||||
link(
|
||||
label = "Factorio forum discussion",
|
||||
url = "https://forums.factorio.com/viewtopic.php?f=190&t=102841&p=570598#p570598",
|
||||
target = "_blank"
|
||||
)
|
||||
}
|
||||
p(
|
||||
"""
|
||||
Development is ongoing. Presently it used to create a live-updating web-map of a Factorio
|
||||
server.
|
||||
""".trimIndent(),
|
||||
rich = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun Container.servers(state: SiteState) {
|
||||
div(className = "servers") {
|
||||
h5("Servers")
|
||||
h5("Factorio Servers Live maps")
|
||||
if (state.serverIds != null) {
|
||||
p("View live-updating maps of the following Factorio servers")
|
||||
p("Available servers: ${state.serverIds.size}")
|
||||
listTag(ListType.UL) {
|
||||
state.serverIds.forEach { serverId ->
|
||||
li {
|
||||
div {
|
||||
span("Available servers: ${state.serverIds.size}")
|
||||
link(
|
||||
label = "$serverId",
|
||||
url = "/servers/$serverId",
|
||||
// url = routing.link("servers/$serverId"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
state.serverIds.forEach { serverId ->
|
||||
// div {
|
||||
// state.serverIds.forEach { serverId ->
|
||||
// div {
|
||||
// link(
|
||||
// label = "$serverId",
|
||||
|
|
@ -39,17 +95,17 @@ private fun Container.servers(state: SiteState) {
|
|||
//// }
|
||||
// }
|
||||
// }
|
||||
|
||||
button(text = "$serverId", className = "btn btn-link") {
|
||||
style = ButtonStyle.PRIMARY
|
||||
size = ButtonSize.SMALL
|
||||
|
||||
onClick {
|
||||
SiteRouting.serverView(serverId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// button(text = "$serverId", className = "btn btn-link") {
|
||||
// style = ButtonStyle.PRIMARY
|
||||
// size = ButtonSize.SMALL
|
||||
//
|
||||
// onClick {
|
||||
// SiteRouting.serverView(serverId)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
div("no servers available")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package dev.adamko.kafkatorio.webmap.layout.servers
|
||||
|
||||
import dev.adamko.kafkatorio.webmap.SiteState
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteState
|
||||
import io.kvision.core.Container
|
||||
import io.kvision.html.div
|
||||
import io.kvision.maps.externals.leaflet.layer.tile.GridLayer
|
||||
|
|
|
|||
|
|
@ -1,174 +0,0 @@
|
|||
package dev.adamko.kafkatorio.webmap
|
||||
|
||||
import dev.adamko.kafkatorio.schema.common.FactorioServerId
|
||||
import dev.adamko.kafkatorio.schema.common.Tick
|
||||
import dev.adamko.kafkatorio.schema.packets.EventServerPacket
|
||||
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
|
||||
import dev.adamko.kafkatorio.webmap.services.EventsServerClient
|
||||
import dev.adamko.kafkatorio.webmap.state.FactorioGameState
|
||||
import io.kvision.navigo.Match
|
||||
import io.kvision.navigo.Navigo
|
||||
import io.kvision.redux.RAction
|
||||
import io.kvision.routing.routing
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.js.RegExp
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
object SiteRouting : CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
Dispatchers.Default + SupervisorJob(rootJob) + CoroutineName("SiteRouting")
|
||||
|
||||
|
||||
fun init() {
|
||||
routing
|
||||
.on(SiteView.HOME) { homepageView() }
|
||||
.on(SiteView.SERVER) { match ->
|
||||
val serverId = match.data[0] as? String ?: error("invalid server id")
|
||||
serverView(FactorioServerId(serverId))
|
||||
}
|
||||
.resolve()
|
||||
}
|
||||
|
||||
fun homepageView() {
|
||||
App.siteStateStore.dispatch(SiteAction.HomePage)
|
||||
launch {
|
||||
val serverIds = EventsServerClient.serverIds()
|
||||
App.siteStateStore.dispatch(SiteAction.ServerIdsLoaded(serverIds))
|
||||
}
|
||||
}
|
||||
|
||||
fun serverView(serverId: FactorioServerId) {
|
||||
App.siteStateStore.dispatch(SiteAction.ServerPage(serverId))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
data class SiteState(
|
||||
val view: SiteView = SiteView.HOME,
|
||||
|
||||
val serverIds: List<FactorioServerId>? = null,
|
||||
|
||||
val factorioGameState: FactorioGameState? = null,
|
||||
) : CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
Dispatchers.Default + SupervisorJob(rootJob) + CoroutineName("SiteState")
|
||||
|
||||
operator fun plus(action: SiteAction): SiteState = when (action) {
|
||||
is SiteAction.HomePage -> copy(view = SiteView.HOME)
|
||||
|
||||
is SiteAction.ServerPage -> copy(
|
||||
view = SiteView.SERVER,
|
||||
factorioGameState = FactorioGameState(action.serverId),
|
||||
)
|
||||
|
||||
is SiteAction.ServerIdsLoaded -> copy(serverIds = action.serverIds)
|
||||
|
||||
is SiteAction.FactorioUpdate -> copy(
|
||||
factorioGameState = factorioGameState?.let { it + action }
|
||||
)
|
||||
|
||||
is SiteAction.EventServerUpdate -> when (action.packet) {
|
||||
is EventServerPacket.ChunkTileSaved -> {
|
||||
if (factorioGameState?.map != null) {
|
||||
launch {
|
||||
factorioGameState.map.refreshUpdatedTilePng(action.packet.filename)
|
||||
}
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
is EventServerPacket.Kafkatorio -> {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed interface SiteAction : RAction {
|
||||
object HomePage : SiteAction
|
||||
data class ServerPage(val serverId: FactorioServerId) : SiteAction
|
||||
|
||||
|
||||
data class ServerIdsLoaded(val serverIds: List<FactorioServerId>) : SiteAction
|
||||
|
||||
|
||||
/** Updates from `events-server` */
|
||||
sealed class FactorioUpdate : SiteAction {
|
||||
data class Player(val tick: Tick, val data: PlayerUpdate) : FactorioUpdate()
|
||||
}
|
||||
|
||||
data class EventServerUpdate(val packet: EventServerPacket) : SiteAction
|
||||
}
|
||||
|
||||
|
||||
sealed interface SiteView {
|
||||
|
||||
sealed interface StaticPath : SiteView {
|
||||
val path: String
|
||||
}
|
||||
|
||||
sealed interface DynamicPath : SiteView {
|
||||
val pathMatcher: RegExp
|
||||
}
|
||||
|
||||
|
||||
object HOME : StaticPath {
|
||||
override val path: String = "/"
|
||||
}
|
||||
|
||||
object SERVER : DynamicPath {
|
||||
override val pathMatcher: RegExp = RegExp("^servers/${FactorioServerId.validIdRegex}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun Navigo.on(view: SiteView, handler: (Match) -> Unit): Navigo {
|
||||
return when (view) {
|
||||
is SiteView.StaticPath -> on(view.path, { match: Match -> handler(match) })
|
||||
is SiteView.DynamicPath -> on(view.pathMatcher, { match: Match -> handler(match) })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//private fun Navigo.on(
|
||||
// view: SiteView,
|
||||
// before: BeforeHook? = null,
|
||||
// after: AfterHook? = null,
|
||||
// leave: LeaveHook? = null,
|
||||
// already: AlreadyHook? = null,
|
||||
// handler: (Match) -> Unit,
|
||||
//): Navigo {
|
||||
//
|
||||
// val hooks: RouteHooks? =
|
||||
// if (before != null || after != null || leave != null || already != null) {
|
||||
// jso {
|
||||
// if (before != null) this@jso.before = before
|
||||
// if (after != null) this@jso.after = after
|
||||
// if (leave != null) this@jso.leave = leave
|
||||
// if (already != null) this@jso.already = already
|
||||
// }
|
||||
// } else {
|
||||
// null
|
||||
// }
|
||||
//
|
||||
// return when (view) {
|
||||
// is SiteView.StaticPath -> when (hooks) {
|
||||
// null -> on(view.pathMatcher, { match: Match -> handler(match) })
|
||||
// else -> on(view.pathMatcher, { match: Match -> handler(match) }, hooks)
|
||||
// }
|
||||
//
|
||||
// is SiteView.DynamicPath -> when (hooks) {
|
||||
// null -> on(view.pathMatcher, { match: Match -> handler(match) })
|
||||
// else -> on(view.pathMatcher, { match: Match -> handler(match) }, hooks)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package dev.adamko.kafkatorio.webmap.routing
|
||||
|
||||
import dev.adamko.kafkatorio.schema.common.FactorioServerId
|
||||
import dev.adamko.kafkatorio.webmap.App
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteAction
|
||||
import dev.adamko.kafkatorio.webmap.rootJob
|
||||
import dev.adamko.kafkatorio.webmap.services.EventsServerClient
|
||||
import io.kvision.navigo.Match
|
||||
import io.kvision.navigo.Navigo
|
||||
import io.kvision.routing.Routing
|
||||
import io.kvision.routing.Strategy
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
object SiteRouter : CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
Dispatchers.Default + SupervisorJob(rootJob) + CoroutineName("SiteRouting")
|
||||
|
||||
|
||||
private val navigo: Routing = Routing(
|
||||
root = "/",
|
||||
useHash = false,
|
||||
strategy = Strategy.ONE
|
||||
)
|
||||
|
||||
|
||||
fun init() {
|
||||
navigo
|
||||
.on(SiteView.HOME) {
|
||||
log("routing.on HOME")
|
||||
homepageView()
|
||||
}
|
||||
.on(SiteView.SERVER) { match ->
|
||||
println("routing.on SERVER ${JSON.stringify(match)}")
|
||||
val serverId = match.data["serverId"] as? String ?: error("invalid server id")
|
||||
println("routing.on SERVER serverId:$serverId")
|
||||
serverView(FactorioServerId(serverId))
|
||||
}
|
||||
.resolve()
|
||||
|
||||
log("routing.lastResolved(): " + JSON.stringify(navigo.lastResolved()))
|
||||
}
|
||||
|
||||
|
||||
fun updatePageLinks() {
|
||||
window.setTimeout(
|
||||
handler = {
|
||||
log("updating page links")
|
||||
navigo.updatePageLinks()
|
||||
},
|
||||
timeout = 0,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun homepageView() {
|
||||
App.siteStateStore.dispatch(SiteAction.HomePage)
|
||||
launch {
|
||||
val serverIds = EventsServerClient.serverIds()
|
||||
log("loaded server IDs $serverIds")
|
||||
App.siteStateStore.dispatch(SiteAction.ServerIdsLoaded(serverIds))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun serverView(serverId: FactorioServerId) {
|
||||
App.siteStateStore.dispatch(SiteAction.ServerPage(serverId))
|
||||
}
|
||||
|
||||
|
||||
private fun log(message: String) = println("[SiteRouting] $message")
|
||||
}
|
||||
|
||||
|
||||
private fun Navigo.on(view: SiteView, handler: (Match) -> Unit): Navigo {
|
||||
return when (view) {
|
||||
is SiteView.StaticPath -> on(view.path, { match: Match -> handler(match) })
|
||||
is SiteView.DynamicPath -> on(view.path, { match: Match -> handler(match) })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package dev.adamko.kafkatorio.webmap.routing
|
||||
|
||||
|
||||
sealed interface SiteView {
|
||||
|
||||
sealed interface StaticPath : SiteView {
|
||||
val path: String
|
||||
}
|
||||
|
||||
sealed interface DynamicPath : SiteView {
|
||||
val path: String
|
||||
}
|
||||
|
||||
|
||||
object HOME : StaticPath {
|
||||
override val path: String = "/"
|
||||
}
|
||||
|
||||
object SERVER : DynamicPath {
|
||||
override val path: String = "/servers/:serverId/"
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
|
|||
import dev.adamko.kafkatorio.schema.packets.PrototypesUpdate
|
||||
import dev.adamko.kafkatorio.schema.packets.SurfaceUpdate
|
||||
import dev.adamko.kafkatorio.webmap.App
|
||||
import dev.adamko.kafkatorio.webmap.SiteAction
|
||||
import dev.adamko.kafkatorio.webmap.state.SiteAction
|
||||
import dev.adamko.kafkatorio.webmap.config.ApplicationProperties
|
||||
import dev.adamko.kafkatorio.webmap.config.jsonMapper
|
||||
import dev.adamko.kafkatorio.webmap.rootJob
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package dev.adamko.kafkatorio.webmap.state
|
||||
|
||||
import dev.adamko.kafkatorio.schema.common.FactorioServerId
|
||||
import dev.adamko.kafkatorio.schema.common.Tick
|
||||
import dev.adamko.kafkatorio.schema.packets.EventServerPacket
|
||||
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
|
||||
import io.kvision.redux.RAction
|
||||
|
||||
|
||||
sealed interface SiteAction : RAction {
|
||||
object HomePage : SiteAction
|
||||
data class ServerPage(val serverId: FactorioServerId) : SiteAction
|
||||
|
||||
|
||||
data class ServerIdsLoaded(val serverIds: List<FactorioServerId>) : SiteAction
|
||||
|
||||
|
||||
/** Updates from `events-server` */
|
||||
sealed class FactorioUpdate : SiteAction {
|
||||
data class Player(val tick: Tick, val data: PlayerUpdate) : FactorioUpdate()
|
||||
}
|
||||
|
||||
data class EventServerUpdate(val packet: EventServerPacket) : SiteAction
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package dev.adamko.kafkatorio.webmap.state
|
||||
|
||||
import dev.adamko.kafkatorio.schema.common.FactorioServerId
|
||||
import dev.adamko.kafkatorio.schema.packets.EventServerPacket
|
||||
import dev.adamko.kafkatorio.webmap.rootJob
|
||||
import dev.adamko.kafkatorio.webmap.routing.SiteView
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
data class SiteState(
|
||||
val view: SiteView = SiteView.HOME,
|
||||
|
||||
val serverIds: List<FactorioServerId>? = null,
|
||||
|
||||
val factorioGameState: FactorioGameState? = null,
|
||||
) : CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
Dispatchers.Default + SupervisorJob(rootJob) + CoroutineName("SiteState")
|
||||
|
||||
operator fun plus(action: SiteAction): SiteState = when (action) {
|
||||
is SiteAction.HomePage -> copy(view = SiteView.HOME)
|
||||
|
||||
is SiteAction.ServerPage -> copy(
|
||||
view = SiteView.SERVER,
|
||||
factorioGameState = FactorioGameState(action.serverId),
|
||||
)
|
||||
|
||||
is SiteAction.ServerIdsLoaded -> copy(serverIds = action.serverIds)
|
||||
|
||||
is SiteAction.FactorioUpdate -> copy(
|
||||
factorioGameState = factorioGameState?.let { it + action }
|
||||
)
|
||||
|
||||
is SiteAction.EventServerUpdate -> when (action.packet) {
|
||||
is EventServerPacket.ChunkTileSaved -> {
|
||||
if (factorioGameState?.map != null) {
|
||||
launch {
|
||||
factorioGameState.map.refreshUpdatedTilePng(action.packet.filename)
|
||||
}
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
is EventServerPacket.Kafkatorio -> {
|
||||
this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ package dev.adamko.kafkatorio.webmap.state
|
|||
import dev.adamko.kafkatorio.schema.common.PlayerIndex
|
||||
import dev.adamko.kafkatorio.schema.common.Tick
|
||||
import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
|
||||
import dev.adamko.kafkatorio.webmap.SiteAction
|
||||
import io.kvision.maps.Maps
|
||||
import io.kvision.maps.externals.leaflet.layer.vector.CircleMarker
|
||||
import kotlinx.js.jso
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package dev.adamko.kafkatorio.webmap.state
|
|||
import dev.adamko.kafkatorio.schema.common.FactorioServerId
|
||||
import dev.adamko.kafkatorio.schema.common.PlayerIndex
|
||||
import dev.adamko.kafkatorio.webmap.FactorioMap
|
||||
import dev.adamko.kafkatorio.webmap.SiteAction
|
||||
import io.kvision.maps.externals.leaflet.layer.LayerGroup
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Kafkatorio Web Map</title>
|
||||
<!-- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.1.0/dist/superhero/bootstrap.min.css" integrity="sha256-T8h7oW5tHp4MhFhmRoDI8xjnB2ld89qSgc3s9g8T0uU=" crossorigin="anonymous">-->
|
||||
<link rel="stylesheet" href="/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/css/kafkatorio.css">
|
||||
<link rel="icon" type="image/png" href="/img/kafkatorio-logo.png"/>
|
||||
<!--suppress HtmlUnknownTarget -->
|
||||
<script type="text/javascript" src="main.bundle.js"></script>
|
||||
<script type="text/javascript" src="/main.bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="kvapp"></div>
|
||||
|
|
|
|||
|
|
@ -15,41 +15,5 @@ config.performance = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
// // dev server
|
||||
// config.devServer = {
|
||||
// open: false,
|
||||
// // devMiddleware: {
|
||||
// // index: false, // specify to enable root proxying
|
||||
// // },
|
||||
// port: 3000,
|
||||
// proxy: {
|
||||
// // context: () => true,
|
||||
// // target: "http://localhost:12080",
|
||||
// // secure: false,
|
||||
// // ws: true,
|
||||
// // changeOrigin: true,
|
||||
//
|
||||
// // "/tiles": {
|
||||
// // target: "http://localhost:12080",
|
||||
// // // "pathRewrite": { "^/tiles": "" },
|
||||
// // // "logger": "console",
|
||||
// // // "logLevel": "debug",
|
||||
// // secure: false,
|
||||
// // changeOrigin: true,
|
||||
// // },
|
||||
// // "/ws": {
|
||||
// // target: "http://localhost:12080",
|
||||
// // // pathRewrite: { "^/ws": "" },
|
||||
// // // "logLevel": "debug",
|
||||
// // // "logger": "console",
|
||||
// // secure: false,
|
||||
// // ws: true,
|
||||
// // changeOrigin: true,
|
||||
// // },
|
||||
// },
|
||||
// "static": [
|
||||
// // "../../processedResources/js/main",
|
||||
// "D:\\Users\\Adam\\Projects\\games\\kafkatorio\\modules\\web-map\\build\\processedResources\\frontend\\main",
|
||||
// ],
|
||||
// };
|
||||
// required for single-page app
|
||||
config.devServer.historyApiFallback = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue