- tidy up player layer
 - no need for smaller web tiles, make the large ones render as pixelated
 - make tile server and websocket server URL not-hardcoded
 - tidy up dynamic tile refreshing
This commit is contained in:
Adam 2022-06-19 10:16:37 +02:00
parent e9a6f99fb8
commit f151027464
9 changed files with 312 additions and 135 deletions

View file

@ -1,10 +1,13 @@
import dev.adamko.kafkatorio.gradle.taskProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
plugins { plugins {
// dev.adamko.kafkatorio.lang.`kotlin-js` dev.adamko.kafkatorio.lang.`kotlin-js`
dev.adamko.kafkatorio.lang.`kotlin-multiplatform` // dev.adamko.kafkatorio.lang.`kotlin-multiplatform`
kotlin("plugin.serialization") kotlin("plugin.serialization")
id("io.kvision") id("io.kvision")
} }
@ -19,13 +22,42 @@ project.ext.set("io.kvision.plugin.enableBackendTasks", false)
kotlin { rootProject.extensions.configure<NodeJsRootExtension> {
js(IR) { // https://github.com/rjaros/kvision/issues/410
browser() versions.webpackCli.version = "4.10.0"
binaries.executable() versions.webpackDevServer.version = "4.9.2"
}
rootProject.extensions.configure<YarnRootExtension> {
resolution("http-proxy-middleware", "^2.0.6")
}
//rootProject.afterEvaluate {
// extensions.configure<NodeJsRootExtension> {
// // https://github.com/rjaros/kvision/issues/410
// versions.webpackCli.version = "4.10.0"
// }
//}
afterEvaluate {
rootProject.extensions.configure<NodeJsRootExtension> {
// https://github.com/rjaros/kvision/issues/410
versions.webpackCli.version = "4.10.0"
versions.webpackDevServer.version = "4.9.2"
} }
js("frontend", IR) { rootProject.extensions.configure<YarnRootExtension> {
resolution("http-proxy-middleware", "^2.0.6")
}
}
kotlin {
js(IR) {
// browser()
// binaries.executable()
// }
//
// js("frontend", IR) {
// nodejs() // nodejs()
browser { browser {
runTask { runTask {
@ -35,13 +67,20 @@ kotlin {
open = false, open = false,
port = 3000, port = 3000,
proxy = mutableMapOf( proxy = mutableMapOf(
"/kv/*" to "http://localhost:8080", "/tiles" to mapOf(
"/kvws/*" to mapOf( "target" to "http://localhost:12080",
"target" to "ws://localhost:8080", "secure" to false,
"changeOrigin" to true,
),
"/ws/foo" to mapOf(
"target" to "ws://localhost:12080",
// "secure" to false,
"ws" to true, "ws" to true,
) // "changeOrigin" to true,
),
), ),
static = mutableListOf("$buildDir/processedResources/frontend/main") // static = mutableListOf("$buildDir/processedResources/frontend/main")
static = mutableListOf("$buildDir/processedResources/js/main")
) )
} }
webpackTask { webpackTask {
@ -54,11 +93,14 @@ kotlin {
} }
} }
binaries.executable() binaries.executable()
// compilations["main"].packageJson {
// this.devDependencies["webpack-dev-server"] = "4.9.1"
// }
} }
jvm("backend") { // jvm("backend") {
//
} // }
sourceSets { sourceSets {
@ -69,7 +111,8 @@ kotlin {
} }
} }
val commonMain by getting { // val commonMain by getting {
main {
dependencies { dependencies {
implementation(dependencies.platform(libs.kotlinx.coroutines.bom)) implementation(dependencies.platform(libs.kotlinx.coroutines.bom))
implementation(dependencies.platform(libs.kotlin.jsWrappers.bom)) implementation(dependencies.platform(libs.kotlin.jsWrappers.bom))
@ -79,13 +122,13 @@ kotlin {
implementation(projects.modules.eventsSchema) implementation(projects.modules.eventsSchema)
implementation(libs.kotlinx.html) implementation(libs.kotlinx.html)
} // }
} // }
val jsMain by getting { // val jsMain by getting {
dependsOn(commonMain) // dependsOn(commonMain)
//
dependencies { // dependencies {
implementation(projects.modules.eventsSchema) implementation(projects.modules.eventsSchema)
@ -108,36 +151,52 @@ kotlin {
implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.core)
implementation(devNpm("http-proxy-middleware", "^2.0.6"))
implementation(dependencies.platform(devNpm("http-proxy-middleware", "^2.0.6")))
// implementation(dependencies.platform(npm("follow-redirects", "^1.14.8"))) // implementation(dependencies.platform(npm("follow-redirects", "^1.14.8")))
// implementation(dependencies.platform(npm("nanoid", "^3.1.31"))) // implementation(dependencies.platform(npm("nanoid", "^3.1.31")))
// implementation(dependencies.platform(npm("minimist", "^1.2.6"))) // implementation(dependencies.platform(npm("minimist", "^1.2.6")))
// implementation(dependencies.platform(npm("async", "^2.6.4"))) // implementation(dependencies.platform(npm("async", "^2.6.4")))
// implementation(dependencies.platform(npm("node-forge", "^1.3.0"))) // implementation(dependencies.platform(npm("node-forge", "^1.3.0")))
// implementation(dependencies.platform(npm("socket.io", "^4.5.1")))
// implementation(dependencies.platform(devNpm("http-proxy-middleware", "^3.0.0-beta.0")))
// implementation(dependencies.platform(devNpm("webpack-dev-server", "4.9.1")))
} }
// val webDir = file("src/main/web") // val webDir = file("src/main/web")
resources.srcDir("src/main/web") resources.srcDir("src/main/web")
resources.srcDir("src/main/resources")
kotlin.srcDir("src/main/kotlin")
}
val frontendMain by getting {
dependsOn(jsMain)
// resources.srcDir("src/main/web")
// resources.srcDir("src/main/resources") // resources.srcDir("src/main/resources")
// kotlin.srcDir("src/main/kotlin")
} }
val jsTest by getting { // val frontendMain by getting {
// dependsOn(jsMain)
//// resources.srcDir("src/main/web")
//// resources.srcDir("src/main/resources")
// }
//
// val jsTest by getting {
// dependencies {
// implementation(kotlin("test-js"))
//
// kvision("kvision-testutils")
//
//// implementation(npm("karma", "^6.3.16"))
// }
//
// kotlin.srcDir("src/test/kotlin")
// }
test {
dependencies { dependencies {
implementation(kotlin("test-js")) implementation(kotlin("test-js"))
kvision("kvision-testutils") kvision("kvision-testutils")
// implementation(npm("karma", "^6.3.16")) // implementation(npm("karma", "^6.3.16"))
} }
kotlin.srcDir("src/test/kotlin")
} }
} }
} }
@ -152,17 +211,42 @@ fun KotlinDependencyHandler.kvision(
implementation("io.kvision:$module:${version.get()}", configure) implementation("io.kvision:$module:${version.get()}", configure)
} }
// https://youtrack.jetbrains.com/issue/KT-42420 ////// https://youtrack.jetbrains.com/issue/KT-42420
//afterEvaluate { //afterEvaluate {
// yarn { // yarn {
// resolution("mocha", "9.2.2") //// resolution("mocha", "9.2.2")
// resolution("follow-redirects", "1.14.8") //// resolution("follow-redirects", "1.14.8")
// resolution("nanoid", "3.1.31") //// resolution("nanoid", "3.1.31")
// resolution("minimist", "1.2.6") //// resolution("minimist", "1.2.6")
// resolution("async", "2.6.4") //// resolution("async", "2.6.4")
// resolution("node-forge", "1.3.0") //// resolution("node-forge", "1.3.0")
//// resolution("socket.io", "^4.5.1")
//// resolution("http-proxy-middleware", "^3.0.0-beta.0")
// resolution("webpack-dev-server", "4.9.1")
// } // }
//} //}
evaluationDependsOn(rootProject.path)
evaluationDependsOn(projects.modules.eventsSchema.dependencyProject.path) //evaluationDependsOn(rootProject.path)
//evaluationDependsOn(projects.modules.eventsSchema.dependencyProject.path)
// stop warnings when building
tasks.configureEach {
when (name) {
"productionExecutableCompileSync" ->
dependsOn(taskProvider("compileProductionExecutableKotlinJs"))
"testTestDevelopmentExecutableCompileSync" ->
dependsOn(taskProvider("compileTestDevelopmentExecutableKotlinJs"))
// "jsTestTestDevelopmentExecutableCompileSync" ->
// dependsOn(taskProvider("compileTestDevelopmentExecutableKotlinFrontend"))
// "jsProductionExecutableCompileSync" ->
// dependsOn(taskProvider("compileProductionExecutableKotlinFrontend"))
"browserDevelopmentRun" ->
dependsOn(taskProvider("browserDevelopmentWebpack"))
"browserDevelopmentWebpack" ->
dependsOn(taskProvider("assemble"))
"browserProductionWebpack" ->
dependsOn(taskProvider("developmentExecutableCompileSync"))
}
}

View file

@ -38,8 +38,7 @@ class App(
wsService: WebsocketService, wsService: WebsocketService,
) : Application(), CoroutineScope { ) : Application(), CoroutineScope {
override val coroutineContext: CoroutineContext = override val coroutineContext: CoroutineContext = CoroutineName("WebMapApp")
CoroutineName("WebMapApp") + Job(rootJob)
private var appState: MutableMap<String, Any> = mutableMapOf() private var appState: MutableMap<String, Any> = mutableMapOf()
@ -62,7 +61,7 @@ class App(
override fun start(state: Map<String, Any>) { override fun start(state: Map<String, Any>) {
this.appState = state.toMutableMap() this.appState = state.toMutableMap()
val root = root("kvapp") { root("kvapp") {
div("Kafkatorio Web Map") div("Kafkatorio Web Map")
add(kvMaps) add(kvMaps)
} }
@ -74,18 +73,16 @@ class App(
it.redraw() it.redraw()
} }
}) })
// this.asDynamic()._fadeAnimated = false
} }
val doc = root.getElement()?.ownerDocument
val window = doc!!.defaultView!!
wsService.packetsFlow wsService.packetsFlow
.filterIsInstance<EventServerPacket.ChunkTileSaved>() .filterIsInstance<EventServerPacket.ChunkTileSaved>()
.onEach { .onEach {
println("[packetsFlow] triggering tile refresh ${it.filename.value}") println("[packetsFlow] triggering tile refresh ${it.filename.value}")
gameState.map.refreshUpdatedTilePng(doc, window, it.filename) gameState.map.refreshUpdatedTilePng(
// doc, window,
it.filename
)
}.launchIn(this) }.launchIn(this)
} }
@ -104,8 +101,8 @@ fun main() {
{ {
val reduxStore = createFactorioReduxStore() val reduxStore = createFactorioReduxStore()
val wsService = WebsocketService( val wsService = WebsocketService(
"ws://localhost:9073/ws", // "ws://localhost:9073/ws", // TODO load from config
reduxStore, reduxStore = reduxStore,
) )
App( App(
reduxStore = reduxStore, reduxStore = reduxStore,

View file

@ -0,0 +1,12 @@
package dev.adamko.kafkatorio.webmap
import kotlinx.browser.window
object Props {
@Suppress("HttpUrlsUsage")
val websocketServerUrl: String
get() = window.location.href
.replace("http://", "ws://")
.replace("https://", "wss://") +
"ws/foo"
}

View file

@ -0,0 +1,33 @@
package dev.adamko.kafkatorio.webmap.externals
import io.kvision.maps.externals.leaflet.DoneCallback
import io.kvision.maps.externals.leaflet.geo.LatLng
import io.kvision.maps.externals.leaflet.layer.tile.TileLayer
import io.kvision.maps.externals.leaflet.layer.vector.Polyline
import org.w3c.dom.HTMLElement
inline var TileLayer<TileLayer.TileLayerOptions>.tileOnLoad: TileOnLoadFn?
get() = asDynamic()._tileOnLoad as TileOnLoadFn
set(value) {
asDynamic()._tileOnLoad = value
}
typealias TileOnLoadFn = (done: DoneCallback, tile: HTMLElement) -> Unit
sealed interface PolylinePathPoints {
value class D1(val points: Array<LatLng>) : PolylinePathPoints
value class D2(val points: Array<Array<LatLng>>) : PolylinePathPoints
value class D3(val points: Array<Array<Array<LatLng>>>) : PolylinePathPoints
}
inline fun Polyline<*>.getLatLngs2(): PolylinePathPoints? {
return when (val points = this.getLatLngs()) {
is Array<LatLng> -> PolylinePathPoints.D1(points as Array<LatLng>)
is Array<Array<LatLng>> -> PolylinePathPoints.D2(points as Array<Array<LatLng>>)
is Array<Array<Array<LatLng>>> -> PolylinePathPoints.D3(points as Array<Array<Array<LatLng>>>)
else -> null
}
}

View file

@ -1,6 +1,8 @@
package dev.adamko.kafkatorio.webmap package dev.adamko.kafkatorio.webmap
import dev.adamko.kafkatorio.schema.common.TilePngFilename import dev.adamko.kafkatorio.schema.common.TilePngFilename
import dev.adamko.kafkatorio.webmap.externals.TileOnLoadFn
import dev.adamko.kafkatorio.webmap.externals.tileOnLoad
import io.kvision.maps.Maps import io.kvision.maps.Maps
import io.kvision.maps.Maps.Companion.L import io.kvision.maps.Maps.Companion.L
import io.kvision.maps.externals.leaflet.DoneCallback import io.kvision.maps.externals.leaflet.DoneCallback
@ -11,15 +13,15 @@ import io.kvision.maps.externals.leaflet.geo.CRS
import io.kvision.maps.externals.leaflet.geo.LatLng import io.kvision.maps.externals.leaflet.geo.LatLng
import io.kvision.maps.externals.leaflet.layer.LayerGroup import io.kvision.maps.externals.leaflet.layer.LayerGroup
import io.kvision.maps.externals.leaflet.layer.tile.TileLayer import io.kvision.maps.externals.leaflet.layer.tile.TileLayer
import io.kvision.utils.obj
import io.kvision.utils.px import io.kvision.utils.px
import kotlinx.browser.document
import kotlinx.browser.window
import kotlinx.coroutines.await import kotlinx.coroutines.await
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.w3c.dom.Document import kotlinx.js.jso
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
import org.w3c.dom.Image import org.w3c.dom.Image
import org.w3c.dom.Window
import org.w3c.dom.asList import org.w3c.dom.asList
import org.w3c.fetch.NO_CORS import org.w3c.fetch.NO_CORS
import org.w3c.fetch.RELOAD import org.w3c.fetch.RELOAD
@ -29,7 +31,7 @@ import org.w3c.fetch.RequestMode
class FactorioMap( class FactorioMap(
private val tileUrlTemplate: String = """http://localhost:9073/tiles/s1/z{z}/x{x}/y{y}.png""", private val tileUrlTemplate: String = """/tiles/s1/z{z}/x{x}/y{y}.png""",
) { ) {
val kvMap: Maps = Maps { val kvMap: Maps = Maps {
@ -38,21 +40,24 @@ class FactorioMap(
margin = 10.px margin = 10.px
} }
val factorioTerrainLayer: TileLayer<*> = buildFactorioTerrainLayer() private val factorioTerrainLayer: TileLayer<*> = buildFactorioTerrainLayer()
val playerIconsLayer: LayerGroup = LayerGroup() val playerIconsLayer: LayerGroup = LayerGroup()
init { init {
val baseLayers: Control.LayersObject = obj<Control.LayersObject> {}
baseLayers["Terrain"] = factorioTerrainLayer
val overlays: Control.LayersObject = obj<Control.LayersObject> {} val baseLayers: Control.LayersObject = jso {
overlays["Players"] = playerIconsLayer set("Terrain", factorioTerrainLayer)
}
val overlays: Control.LayersObject = jso {
set("Players", playerIconsLayer)
}
val layersControl = Layers( val layersControl = Layers(
baseLayers = baseLayers, baseLayers = baseLayers,
overlays = overlays, overlays = overlays,
options = obj<Layers.LayersOptions> { options = jso {
sortLayers = true sortLayers = true
} }
) )
@ -78,21 +83,19 @@ class FactorioMap(
suspend fun refreshUpdatedTilePng( suspend fun refreshUpdatedTilePng(
document: Document,
window: Window,
tilePngFilename: TilePngFilename, tilePngFilename: TilePngFilename,
): Unit = coroutineScope { ): Unit = coroutineScope {
launch { document
document .querySelectorAll("img.leaflet-tile-loaded")
.querySelectorAll("img.leaflet-tile-loaded") .asList()
.asList() .filterIsInstance<Image>()
.filterIsInstance<Image>() .filter { img ->
.filter { img -> tilePngFilename.value in img.src
tilePngFilename.value in img.src }
} .forEach { img ->
.forEach { img -> val imgSrc = img.src
val imgSrc = img.src //.substringBeforeLast('?')
launch {
window.fetch( window.fetch(
imgSrc, imgSrc,
RequestInit( RequestInit(
@ -100,24 +103,14 @@ class FactorioMap(
mode = RequestMode.NO_CORS, mode = RequestMode.NO_CORS,
) )
).then { ).then {
println("[refreshUpdatedTilePng] updating $imgSrc") window.requestAnimationFrame {
img.setAttribute(DYNAMIC_RELOAD_ATT, "true") println("[refreshUpdatedTilePng] updating $imgSrc")
img.src = imgSrc img.setAttribute(DYNAMIC_RELOAD_ATT, "true")
img.src = imgSrc
}
}.await() }.await()
} }
} }
//// println("fetching $imgSrc")
// val newImg = Image()
// newImg.onload = {
//// window.requestAnimationFrame {
//// println("image loaded ${newImg!!.src}")
// img.setAttribute(DYNAMIC_RELOAD_ATT, "true")
// img.src = newImg.src
// Unit
//// }
// }
// newImg.src = imgSrc //+ "?t=${currentTimeMillis()}"
} }
private fun buildFactorioTerrainLayer(): TileLayer<TileLayer.TileLayerOptions> { private fun buildFactorioTerrainLayer(): TileLayer<TileLayer.TileLayerOptions> {
@ -132,7 +125,7 @@ class FactorioMap(
minZoom = -2 minZoom = -2
maxZoom = 6 maxZoom = 6
maxNativeZoom = 3 maxNativeZoom = -1
minNativeZoom = -1 minNativeZoom = -1
noWrap = true noWrap = true
@ -140,13 +133,14 @@ class FactorioMap(
updateWhenZooming = true updateWhenZooming = true
} }
val currentTileOnLoad: (DoneCallback, HTMLElement) -> Unit = val currentTileOnLoad: TileOnLoadFn? = baseTileLayer.tileOnLoad
baseTileLayer.asDynamic()._tileOnLoad as (DoneCallback, HTMLElement) -> Unit
baseTileLayer.asDynamic()._tileOnLoad = { done: DoneCallback, tile: HTMLElement -> if (currentTileOnLoad != null) {
if (tile.hasAttribute(DYNAMIC_RELOAD_ATT)) { baseTileLayer.tileOnLoad = { done: DoneCallback, tile: HTMLElement ->
if (!tile.hasAttribute(DYNAMIC_RELOAD_ATT)) {
currentTileOnLoad(done, tile)
}
tile.removeAttribute(DYNAMIC_RELOAD_ATT) tile.removeAttribute(DYNAMIC_RELOAD_ATT)
} else {
currentTileOnLoad(done, tile)
} }
} }

View file

@ -10,9 +10,8 @@ import dev.adamko.kafkatorio.schema.packets.PlayerUpdate
import dev.adamko.kafkatorio.webmap.latLng import dev.adamko.kafkatorio.webmap.latLng
import io.kvision.maps.Maps import io.kvision.maps.Maps
import io.kvision.maps.externals.leaflet.geo.LatLng import io.kvision.maps.externals.leaflet.geo.LatLng
import io.kvision.maps.externals.leaflet.layer.overlay.Tooltip
import io.kvision.maps.externals.leaflet.layer.vector.CircleMarker import io.kvision.maps.externals.leaflet.layer.vector.CircleMarker
import io.kvision.utils.obj import kotlinx.js.jso
fun handlePlayerUpdate( fun handlePlayerUpdate(
@ -100,7 +99,7 @@ data class PlayerState(
className = "player-marker" className = "player-marker"
// interactive = false // interactive = false
}.also { circle -> }.also { circle ->
circle.bindTooltip("", obj<Tooltip.TooltipOptions> { circle.bindTooltip("", jso {
// interactive = false // interactive = false
}) })
} }

View file

@ -22,10 +22,11 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.w3c.dom.MessageEvent import org.w3c.dom.MessageEvent
import org.w3c.dom.WebSocket import org.w3c.dom.WebSocket
import org.w3c.dom.events.Event
class WebsocketService( class WebsocketService(
wsUrl: String, wsUrl: String = Props.websocketServerUrl,
private val reduxStore: ReduxStore<FactorioGameState, FactorioUpdate>, private val reduxStore: ReduxStore<FactorioGameState, FactorioUpdate>,
) : CoroutineScope { ) : CoroutineScope {
@ -33,6 +34,7 @@ class WebsocketService(
CoroutineName("WebsocketService") + Job(rootJob) CoroutineName("WebsocketService") + Job(rootJob)
private val ws = WebSocket(wsUrl) private val ws = WebSocket(wsUrl)
// private val ws = WebSocket("ws://localhost:12080/ws/foo")
private val _packetsFlow = MutableSharedFlow<EventServerPacket>() private val _packetsFlow = MutableSharedFlow<EventServerPacket>()
val packetsFlow: SharedFlow<EventServerPacket> val packetsFlow: SharedFlow<EventServerPacket>
@ -40,6 +42,9 @@ class WebsocketService(
init { init {
ws.onmessage = ::handleMessageEvent ws.onmessage = ::handleMessageEvent
ws.onerror = ::handleError
println("[WebsocketService] init ${ws.url}, ${ws.protocol}")
} }
private fun handleMessageEvent(msg: MessageEvent) { private fun handleMessageEvent(msg: MessageEvent) {
@ -52,35 +57,46 @@ class WebsocketService(
&& data.endsWith("}") && data.endsWith("}")
) { ) {
println(data.replace('\n', ' ')) println("[WebsocketService.handleMessageEvent] ${data.replace('\n', ' ')}")
val packet = jsonMapper.decodeFromString(EventServerPacket.serializer(), data) val packet: EventServerPacket? = runCatching {
jsonMapper.decodeFromString(EventServerPacket.serializer(), data)
launch { }.getOrElse {
_packetsFlow.emit(packet) null
} }
when (packet) { if (packet != null) {
is EventServerPacket.ChunkTileSaved -> {}
is EventServerPacket.Kafkatorio -> launch { _packetsFlow.emit(packet) }
when (val packetData = packet.packet.data) {
is PlayerUpdate -> reduxStore.dispatch( when (packet) {
FactorioUpdate.Player(packet.packet.tick, packetData) is EventServerPacket.ChunkTileSaved -> {}
)
is ConfigurationUpdate, is EventServerPacket.Kafkatorio ->
is ConsoleChatUpdate, when (val packetData = packet.packet.data) {
is ConsoleCommandUpdate, is PlayerUpdate -> reduxStore.dispatch(
is PrototypesUpdate, FactorioUpdate.Player(packet.packet.tick, packetData)
is SurfaceUpdate, )
is EntityUpdate, is ConfigurationUpdate,
is MapChunkUpdate -> { is ConsoleChatUpdate,
// to be continued... is ConsoleCommandUpdate,
is PrototypesUpdate,
is SurfaceUpdate,
is EntityUpdate,
is MapChunkUpdate -> {
// to be continued...
}
} }
} }
} else {
println("[WebsocketService.handleMessageEvent] unknown json message ${msg.data}")
} }
} else { } else {
println(data) println("[WebsocketService.handleMessageEvent] non-json message ${msg.data}")
} }
} }
private fun handleError(error: Event) {
println("ws error: ${JSON.stringify(error)}")
}
} }

View file

@ -1,8 +1,10 @@
/* https://github.com/Leaflet/Leaflet/issues/3575 */
.leaflet-tile { .leaflet-tile {
width: 257px !important; /* https://github.com/Leaflet/Leaflet/issues/3575 */
height: 257px !important; /*width: 257px !important;*/
box-shadow: 0 0 1px rgba(0, 0, 0, 0.05); /*height: 257px !important;*/
/*box-shadow: 0 0 1px rgba(0, 0, 0, 0.05);*/
image-rendering: pixelated;
} }
html { html {

View file

@ -1,15 +1,55 @@
config.resolve.modules.push("../../processedResources/js/main"); config.resolve.modules.push("../../processedResources/js/main");
if (config.devServer) { if (config.devServer) {
config.devServer.hot = true; config.devServer.hot = true;
config.devtool = 'eval-cheap-source-map'; config.devtool = 'eval-cheap-source-map';
config.devServer.host = "0.0.0.0"
} else { } else {
config.devtool = undefined; config.devtool = undefined;
} }
// disable bundle size warning // disable bundle size warning
config.performance = { config.performance = {
assetFilter: function (assetFilename) { assetFilter: function (assetFilename) {
return !assetFilename.endsWith('.js'); return !assetFilename.endsWith('.js');
}, },
}; };
// // 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",
// ],
// };