import io.ktor.request.*
import io.ktor.routing.*
import io.ktor.util.*
+import kotlinx.html.*
import net.starshipfights.data.Id
import net.starshipfights.game.ClientMode
+import net.starshipfights.game.toUrlSlug
import net.starshipfights.game.view
+import net.starshipfights.labs.lab
+import net.starshipfights.labs.labPost
fun Routing.installCampaign() {
- get("/test-cluster") {
- call.respondHtml(block = call.campaignTestPage())
+ lab("cluster", "Star Clusters") {
+ section {
+ h1 { +"Star Clusters" }
+ p { +"This is only a test and may not be indicative of the finished star-cluster feature for Starship Fights" }
+ form(action = "/labs/cluster", method = FormMethod.post) {
+ h2 { +"Generation Parameters" }
+ h3 { +"Background Color" }
+ for (color in StarClusterBackground.values()) {
+ val colorId = "color-${color.toUrlSlug()}"
+ label {
+ htmlFor = colorId
+ radioInput(name = "color") {
+ id = colorId
+ value = color.name
+ required = true
+ }
+ +Entities.nbsp
+ +color.displayName
+ br
+ }
+ }
+ h3 { +"Size" }
+ for (size in ClusterSize.values()) {
+ val sizeId = "size-${size.toUrlSlug()}"
+ label {
+ htmlFor = sizeId
+ radioInput(name = "size") {
+ id = sizeId
+ value = size.name
+ required = true
+ }
+ +Entities.nbsp
+ +size.displayName
+ br
+ }
+ }
+ h3 { +"Warp Lane Density" }
+ for (density in ClusterLaneDensity.values()) {
+ val densityId = "density-${density.toUrlSlug()}"
+ label {
+ htmlFor = densityId
+ radioInput(name = "density") {
+ id = densityId
+ value = density.name
+ required = true
+ }
+ +Entities.nbsp
+ +density.displayName
+ br
+ }
+ }
+ h3 { +"Planet Density" }
+ for (planets in ClusterPlanetDensity.values()) {
+ val planetsId = "planets-${planets.toUrlSlug()}"
+ label {
+ htmlFor = planetsId
+ radioInput(name = "planets") {
+ id = planetsId
+ value = planets.name
+ required = true
+ }
+ +Entities.nbsp
+ +planets.displayName
+ br
+ }
+ }
+ h3 { +"Eldritch Corruption" }
+ for (corruption in ClusterCorruption.values()) {
+ val corruptionId = "corruption-${corruption.toUrlSlug()}"
+ label {
+ htmlFor = corruptionId
+ radioInput(name = "corruption") {
+ id = corruptionId
+ value = corruption.name
+ required = true
+ }
+ +Entities.nbsp
+ +corruption.displayName
+ br
+ }
+ }
+ submitInput {
+ value = "Generate Star Cluster"
+ }
+ }
+ }
}
- post("/test-cluster") {
+ labPost("cluster") {
val parameters = call.receiveParameters()
val color = StarClusterBackground.valueOf(parameters.getOrFail("color"))
+++ /dev/null
-package net.starshipfights.campaign
-
-import io.ktor.application.*
-import kotlinx.html.*
-import net.starshipfights.game.toUrlSlug
-import net.starshipfights.info.page
-import net.starshipfights.info.standardNavBar
-
-suspend fun ApplicationCall.campaignTestPage(): HTML.() -> Unit {
- return page(
- "Star Cluster Test",
- standardNavBar(),
- null
- ) {
- section {
- h1 { +"Star Cluster Test" }
- p { +"This is only a test and may not be indicative of the finished star-cluster feature for Starship Fights" }
- form(action = "/test-cluster", method = FormMethod.post) {
- h2 { +"Generation Parameters" }
- h3 { +"Background Color" }
- for (color in StarClusterBackground.values()) {
- val colorId = "color-${color.toUrlSlug()}"
- label {
- htmlFor = colorId
- radioInput(name = "color") {
- id = colorId
- value = color.name
- required = true
- }
- +Entities.nbsp
- +color.displayName
- br
- }
- }
- h3 { +"Size" }
- for (size in ClusterSize.values()) {
- val sizeId = "size-${size.toUrlSlug()}"
- label {
- htmlFor = sizeId
- radioInput(name = "size") {
- id = sizeId
- value = size.name
- required = true
- }
- +Entities.nbsp
- +size.displayName
- br
- }
- }
- h3 { +"Warp Lane Density" }
- for (density in ClusterLaneDensity.values()) {
- val densityId = "density-${density.toUrlSlug()}"
- label {
- htmlFor = densityId
- radioInput(name = "density") {
- id = densityId
- value = density.name
- required = true
- }
- +Entities.nbsp
- +density.displayName
- br
- }
- }
- h3 { +"Planet Density" }
- for (planets in ClusterPlanetDensity.values()) {
- val planetsId = "planets-${planets.toUrlSlug()}"
- label {
- htmlFor = planetsId
- radioInput(name = "planets") {
- id = planetsId
- value = planets.name
- required = true
- }
- +Entities.nbsp
- +planets.displayName
- br
- }
- }
- h3 { +"Eldritch Corruption" }
- for (corruption in ClusterCorruption.values()) {
- val corruptionId = "corruption-${corruption.toUrlSlug()}"
- label {
- htmlFor = corruptionId
- radioInput(name = "corruption") {
- id = corruptionId
- value = corruption.name
- required = true
- }
- +Entities.nbsp
- +corruption.displayName
- br
- }
- }
- submitInput {
- value = "Generate Star Cluster"
- }
- }
- }
- }
-}
package net.starshipfights.info
import kotlinx.html.*
+import net.starshipfights.data.auth.User
+import net.starshipfights.data.auth.UserStatus
+import net.starshipfights.data.auth.getTrophies
+import net.starshipfights.data.auth.renderTrophy
import net.starshipfights.game.ShipType
import net.starshipfights.game.getDefiniteShortName
}
}
}
+
+data class UserProfileSidebar(val user: User, val isCurrentUser: Boolean, val hasOpenSessions: Boolean) : Sidebar() {
+ override fun TagConsumer<*>.display() {
+ if (user.showDiscordName) {
+ img(src = user.discordAvatarUrl) {
+ style = "border-radius:50%"
+ }
+ p {
+ style = "text-align:center"
+ +user.discordName
+ +"#"
+ +user.discordDiscriminator
+ }
+ } else {
+ img(src = user.anonymousAvatarUrl) {
+ style = "border-radius:50%"
+ }
+ }
+ for (trophy in user.getTrophies())
+ renderTrophy(trophy)
+
+ if (user.showUserStatus) {
+ p {
+ style = "text-align:center"
+ +when (user.status) {
+ UserStatus.IN_BATTLE -> "In Battle"
+ UserStatus.READY_FOR_BATTLE -> "In Battle"
+ UserStatus.IN_MATCHMAKING -> "In Matchmaking"
+ UserStatus.AVAILABLE -> if (hasOpenSessions) "Online" else "Offline"
+ }
+ }
+ p {
+ style = "text-align:center"
+ +"Registered at "
+ span(classes = "moment") {
+ style = "display:none"
+ +user.registeredAt.toEpochMilli().toString()
+ }
+ br
+ +"Last active at "
+ span(classes = "moment") {
+ style = "display:none"
+ +user.lastActivity.toEpochMilli().toString()
+ }
+ }
+ }
+ if (isCurrentUser) {
+ hr { style = "border-color:#036" }
+ div(classes = "list") {
+ div(classes = "item") {
+ a(href = "/admiral/new") { +"Create New Admiral" }
+ }
+ div(classes = "item") {
+ a(href = "/me/manage") { +"Edit Profile" }
+ }
+ }
+ }
+ }
+}
import net.starshipfights.auth.*
import net.starshipfights.data.Id
import net.starshipfights.data.admiralty.*
-import net.starshipfights.data.auth.*
+import net.starshipfights.data.auth.PreferredTheme
+import net.starshipfights.data.auth.User
+import net.starshipfights.data.auth.UserSession
import net.starshipfights.forbid
import net.starshipfights.game.*
import net.starshipfights.redirect
val admirals = Admiral.filter(Admiral::owningUser eq user.id).toList()
return page(
- user.profileName, standardNavBar(), CustomSidebar {
- if (user.showDiscordName) {
- img(src = user.discordAvatarUrl) {
- style = "border-radius:50%"
- }
- p {
- style = "text-align:center"
- +user.discordName
- +"#"
- +user.discordDiscriminator
- }
- } else {
- img(src = user.anonymousAvatarUrl) {
- style = "border-radius:50%"
- }
- }
- for (trophy in user.getTrophies())
- renderTrophy(trophy)
-
- if (user.showUserStatus) {
- p {
- style = "text-align:center"
- +when (user.status) {
- UserStatus.IN_BATTLE -> "In Battle"
- UserStatus.READY_FOR_BATTLE -> "In Battle"
- UserStatus.IN_MATCHMAKING -> "In Matchmaking"
- UserStatus.AVAILABLE -> if (hasOpenSessions) "Online" else "Offline"
- }
- }
- p {
- style = "text-align:center"
- +"Registered at "
- span(classes = "moment") {
- style = "display:none"
- +user.registeredAt.toEpochMilli().toString()
- }
- br
- +"Last active at "
- span(classes = "moment") {
- style = "display:none"
- +user.lastActivity.toEpochMilli().toString()
- }
- }
- }
- if (isCurrentUser) {
- hr { style = "border-color:#036" }
- div(classes = "list") {
- div(classes = "item") {
- a(href = "/admiral/new") { +"Create New Admiral" }
- }
- div(classes = "item") {
- a(href = "/me/manage") { +"Edit Profile" }
- }
- }
- } /*else if (currentUser != null) {
- hr { style = "border-color:#036" }
- div(classes = "list") {
- div(classes = "item") {
- a(href = "/user/${userId}/send") { +"Send Message" }
- }
- }
- }*/
- }
+ user.profileName,
+ standardNavBar(),
+ UserProfileSidebar(user, isCurrentUser, hasOpenSessions)
) {
section {
h1 { +user.profileName }
--- /dev/null
+package net.starshipfights.labs
+
+import io.ktor.application.*
+import io.ktor.html.*
+import io.ktor.routing.*
+import io.ktor.util.pipeline.*
+import kotlinx.html.*
+import net.starshipfights.info.*
+
+private val labs = mutableMapOf<String, String>()
+
+private val labsSidebar: Sidebar
+ get() = PageNavSidebar(
+ listOf(NavHead("Other Labs")) + labs.map { (slug, title) ->
+ NavLink("/labs/$slug", title)
+ }
+ )
+
+fun Routing.lab(slug: String, title: String, pageBody: SECTIONS.() -> Unit) {
+ labs[slug] = title
+
+ get("/labs/$slug") {
+ call.respondHtml(
+ block = call.page(
+ title,
+ call.standardNavBar(),
+ labsSidebar,
+ pageBody
+ )
+ )
+ }
+}
+
+fun Routing.labPost(slug: String, action: PipelineInterceptor<Unit, ApplicationCall>) {
+ post("/labs/$slug", action)
+}
+
+fun Routing.installLabs() {
+ get("/labs") {
+ call.respondHtml(
+ block = call.page(
+ "Experimental Features",
+ call.standardNavBar(),
+ null
+ ) {
+ section {
+ h1 { +"Experimental Features" }
+ p { +"Sometimes it is desirable that an in-progress feature be demonstrated to the playerbase before it is fully ready to be integrated into the game. In that case, the progress on the feature made so far will be accessible here." }
+ if (labs.isEmpty())
+ p { +"No labs are currently visible." }
+ else
+ ul {
+ for ((slug, title) in labs) {
+ li {
+ a(href = "/labs/$slug") { +title }
+ }
+ }
+ }
+ }
+ }
+ )
+ }
+}
import net.starshipfights.data.DataRoutines
import net.starshipfights.game.installGame
import net.starshipfights.info.*
+import net.starshipfights.labs.installLabs
import org.slf4j.event.Level
import java.io.InputStream
import java.util.concurrent.atomic.AtomicLong
routing {
installPages()
installGame()
- installAdmin()
installCampaign()
+ installAdmin()
+ installLabs()
static("/static") {
// I HAVE TO DO THIS MANUALLY