├── agent-ignore.txt
├── resources
├── public
│ ├── .gitignore
│ ├── images
│ │ └── favicon.ico
│ └── iconfont
│ │ ├── material-icons.woff
│ │ └── material-icons.woff2
├── .gitignore
├── skyreplays.properties
├── icon.ico
├── icon1024.png
├── icon128.png
├── icon16.png
├── icon256.png
├── icon32.png
├── icon48.png
├── icon512.png
├── icon64.png
├── FAsdfz.properties
├── 186669__fordps3__computer-boop.wav
├── skylobby-web.properties
├── skylobby-stream-fix.properties
└── skylobby.desktop
├── .clj-kondo
├── .gitignore
├── ci-config.edn
└── config.edn
├── cryogen
├── content
│ ├── css
│ │ ├── example.css
│ │ └── sassexample.scss
│ ├── img
│ │ ├── initial-ui.png
│ │ ├── battle-and-bots.png
│ │ ├── failed-dworld-minimap.png
│ │ └── battle-minimap-and-resources.png
│ ├── md
│ │ └── pages
│ │ │ └── index.md
│ └── config.edn
├── themes
│ ├── lotus
│ │ ├── config.edn
│ │ ├── html
│ │ │ ├── tags.html
│ │ │ ├── home.html
│ │ │ ├── tag.html
│ │ │ ├── archives.html
│ │ │ ├── author.html
│ │ │ ├── prev-next.html
│ │ │ ├── post-content.html
│ │ │ ├── page.html
│ │ │ ├── previews.html
│ │ │ ├── post.html
│ │ │ └── 404.html
│ │ ├── README.md
│ │ └── css
│ │ │ ├── _buttons.scss
│ │ │ ├── lotus-highlightjs.min.css
│ │ │ ├── _variables.scss
│ │ │ ├── _layout.scss
│ │ │ └── _menu.scss
│ ├── blue
│ │ ├── html
│ │ │ ├── tags.html
│ │ │ ├── tag.html
│ │ │ ├── author.html
│ │ │ ├── archives.html
│ │ │ ├── home.html
│ │ │ ├── post-content.html
│ │ │ ├── previews.html
│ │ │ ├── page.html
│ │ │ ├── 404.html
│ │ │ └── post.html
│ │ └── css
│ │ │ └── screen.css
│ ├── nucleus
│ │ ├── html
│ │ │ ├── tags.html
│ │ │ ├── tag.html
│ │ │ ├── archives.html
│ │ │ ├── author.html
│ │ │ ├── home.html
│ │ │ ├── post-content.html
│ │ │ ├── previews.html
│ │ │ ├── page.html
│ │ │ ├── 404.html
│ │ │ └── post.html
│ │ └── css
│ │ │ ├── buttons.css
│ │ │ ├── reset.css
│ │ │ ├── typography.css
│ │ │ └── menu.css
│ └── blue_centered
│ │ └── html
│ │ ├── tags.html
│ │ ├── tag.html
│ │ ├── author.html
│ │ ├── archives.html
│ │ ├── home.html
│ │ ├── post-content.html
│ │ ├── previews.html
│ │ ├── page.html
│ │ ├── 404.html
│ │ └── post.html
├── src
│ └── cryogen
│ │ ├── core.clj
│ │ └── server.clj
├── .gitignore
├── README.md
├── deps.edn
└── project.clj
├── native-res
├── linux
│ └── META-INF
│ │ └── native-image
│ │ └── skylobby
│ │ ├── java
│ │ ├── proxy-config.json
│ │ ├── predefined-classes-config.json
│ │ ├── serialization-config.json
│ │ └── resource-config.json
│ │ └── clj
│ │ └── .gitignore
└── windows
│ └── META-INF
│ └── native-image
│ └── skylobby
│ ├── java
│ ├── proxy-config.json
│ ├── .gitignore
│ ├── predefined-classes-config.json
│ ├── serialization-config.json
│ └── resource-config.json
│ └── clj
│ └── .gitignore
├── repo
├── io
│ └── github
│ │ └── memo33
│ │ └── jsquish
│ │ ├── 2.0.1
│ │ ├── jsquish-2.0.1.jar.sha1
│ │ ├── jsquish-2.0.1.pom.sha1
│ │ ├── jsquish-2.0.1.jar
│ │ └── jsquish-2.0.1.pom
│ │ └── maven-metadata-local.xml
└── gr
│ └── zdimensions
│ └── jsquish
│ ├── 1.0
│ ├── jsquish-1.0.jar
│ └── jsquish-1.0.pom
│ └── maven-metadata-local.xml
├── jpackage
├── linux
├── windows
├── mac
└── lobby
├── package
└── win
│ └── Elevate.exe
├── src
├── cljs
│ └── skylobby
│ │ ├── css.cljs
│ │ ├── view
│ │ ├── settings.cljs
│ │ ├── tasks.cljs
│ │ ├── side_nav.cljs
│ │ ├── server_nav.cljs
│ │ └── servers_nav.cljs
│ │ ├── web.cljs
│ │ └── util.cljs
└── clj
│ ├── skylobby
│ ├── fx
│ │ ├── text_ext.clj
│ │ ├── font_icon.clj
│ │ ├── flag_icon.clj
│ │ ├── tooltip_nofocus.clj
│ │ ├── virtualized_scroll_pane.clj
│ │ ├── color.clj
│ │ ├── server_tab.clj
│ │ ├── battles_window.clj
│ │ ├── channels.clj
│ │ ├── battle_chat.clj
│ │ └── event
│ │ │ └── direct.clj
│ ├── discord.clj
│ └── download
│ │ └── butler.clj
│ └── spring_lobby
│ ├── sound.clj
│ ├── spring
│ └── uikeys.clj
│ └── replays.clj
├── native-image-agent-filter.json
├── jvm-flags
├── .gitmodules
├── package.json
├── graal
├── clj
│ └── skylobby
│ │ ├── cli
│ │ └── util.clj
│ │ ├── replay.clj
│ │ ├── event
│ │ └── user.clj
│ │ ├── client
│ │ ├── stls.clj
│ │ ├── message.clj
│ │ └── gloss.clj
│ │ ├── chat.clj
│ │ ├── battle.clj
│ │ ├── lua.clj
│ │ ├── git.clj
│ │ ├── task.clj
│ │ └── config.clj
└── cljc
│ └── skylobby
│ ├── common
│ └── util.cljc
│ └── data.cljc
├── dist
├── arch
│ ├── skylobby.desktop
│ └── skylobby
└── linux
│ └── skylobby.desktop
├── tests.edn
├── test
└── clj
│ └── skylobby
│ ├── fx
│ ├── flag_icon_test.clj
│ ├── main_test.clj
│ ├── mods_test.clj
│ ├── server_tab_test.clj
│ ├── engines_test.clj
│ ├── map_sync_test.clj
│ ├── mod_sync_test.clj
│ ├── channels_test.clj
│ ├── minimap_test.clj
│ ├── chat_test.clj
│ ├── engine_sync_test.clj
│ ├── battle_chat_test.clj
│ ├── battles_window_test.clj
│ ├── battles_buttons_test.clj
│ ├── pick_spring_root_test.clj
│ ├── sync_test.clj
│ ├── user_test.clj
│ ├── root_test.clj
│ ├── host_battle_test.clj
│ ├── matchmaking_test.clj
│ ├── server_test.clj
│ ├── scenarios_test.clj
│ ├── reset_password_test.clj
│ ├── register_test.clj
│ ├── color_test.clj
│ ├── import_test.clj
│ ├── settings_test.clj
│ ├── tasks_test.clj
│ ├── rapid_test.clj
│ ├── spring_info_test.clj
│ ├── main_tabs_test.clj
│ ├── welcome_test.clj
│ ├── battles_table_test.clj
│ ├── console_test.clj
│ ├── bottom_bar_test.clj
│ ├── download_test.clj
│ ├── channel_test.clj
│ ├── spring_options_test.clj
│ ├── maps_test.clj
│ ├── players_table_test.clj
│ └── battle_test.clj
│ ├── task
│ └── handler_test.clj
│ ├── task_test.clj
│ ├── client
│ └── gloss_test.clj
│ ├── fx_test.clj
│ └── spads_test.clj
├── .gitignore
├── dev
└── clj
│ ├── test
│ └── tests.clj
│ ├── native
│ └── native_image.clj
│ ├── jar
│ └── uberjar.clj
│ ├── user
│ └── repl.clj
│ └── graal
│ └── repl.clj
├── shadow-cljs.edn
├── .github
└── workflows
│ ├── lint.yml
│ ├── changelog.yml
│ ├── pages.yml
│ └── test.yml
├── update-native-res.sh
├── update-native-res.ps1
├── LICENSE
└── README.md
/agent-ignore.txt:
--------------------------------------------------------------------------------
1 | io.netty
2 |
--------------------------------------------------------------------------------
/resources/public/.gitignore:
--------------------------------------------------------------------------------
1 | /js/
2 |
--------------------------------------------------------------------------------
/resources/.gitignore:
--------------------------------------------------------------------------------
1 | /skylobby.version
2 |
--------------------------------------------------------------------------------
/resources/skyreplays.properties:
--------------------------------------------------------------------------------
1 | arguments="skyreplays"
2 |
--------------------------------------------------------------------------------
/.clj-kondo/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 | !config.edn
4 | !ci-config.edn
5 |
--------------------------------------------------------------------------------
/cryogen/content/css/example.css:
--------------------------------------------------------------------------------
1 | a {
2 | text-decoration-style: dashed;
3 | }
--------------------------------------------------------------------------------
/native-res/linux/META-INF/native-image/skylobby/java/proxy-config.json:
--------------------------------------------------------------------------------
1 | [
2 | ]
3 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/java/proxy-config.json:
--------------------------------------------------------------------------------
1 | [
2 | ]
3 |
--------------------------------------------------------------------------------
/native-res/linux/META-INF/native-image/skylobby/clj/.gitignore:
--------------------------------------------------------------------------------
1 | /initialized-classes.txt
2 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/clj/.gitignore:
--------------------------------------------------------------------------------
1 | /initialized-classes.txt
2 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/java/.gitignore:
--------------------------------------------------------------------------------
1 | /.lock
2 | /agent-pid*
3 |
--------------------------------------------------------------------------------
/resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon.ico
--------------------------------------------------------------------------------
/repo/io/github/memo33/jsquish/2.0.1/jsquish-2.0.1.jar.sha1:
--------------------------------------------------------------------------------
1 | 7fda6fc496a1a368d3b3b4d6da37b84b8b8e392f
--------------------------------------------------------------------------------
/repo/io/github/memo33/jsquish/2.0.1/jsquish-2.0.1.pom.sha1:
--------------------------------------------------------------------------------
1 | 1e02650f05b4eb08d4e3a0893062a7145b1b0200
--------------------------------------------------------------------------------
/resources/icon1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon1024.png
--------------------------------------------------------------------------------
/resources/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon128.png
--------------------------------------------------------------------------------
/resources/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon16.png
--------------------------------------------------------------------------------
/resources/icon256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon256.png
--------------------------------------------------------------------------------
/resources/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon32.png
--------------------------------------------------------------------------------
/resources/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon48.png
--------------------------------------------------------------------------------
/resources/icon512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon512.png
--------------------------------------------------------------------------------
/resources/icon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/icon64.png
--------------------------------------------------------------------------------
/cryogen/themes/lotus/config.edn:
--------------------------------------------------------------------------------
1 | {:sass-src ["css"]
2 | :resources ["img"]}
3 |
--------------------------------------------------------------------------------
/jpackage/linux:
--------------------------------------------------------------------------------
1 | --linux-shortcut
2 | --icon "resources/icon128.png"
3 | --resource-dir "dist/linux"
4 |
--------------------------------------------------------------------------------
/package/win/Elevate.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/package/win/Elevate.exe
--------------------------------------------------------------------------------
/resources/FAsdfz.properties:
--------------------------------------------------------------------------------
1 | extension=sdfz
2 | mime-type=application/sdfz
3 | description=Spring Replay
4 |
--------------------------------------------------------------------------------
/cryogen/content/css/sassexample.scss:
--------------------------------------------------------------------------------
1 | body {
2 | a {
3 | text-decoration-style: dashed;
4 | }
5 | }
--------------------------------------------------------------------------------
/cryogen/content/img/initial-ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/cryogen/content/img/initial-ui.png
--------------------------------------------------------------------------------
/resources/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/public/images/favicon.ico
--------------------------------------------------------------------------------
/src/cljs/skylobby/css.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.css)
2 |
3 |
4 | (def header-class
5 | "f4 ba bw1 br3 no-underline pv2 ph3 dib")
6 |
--------------------------------------------------------------------------------
/cryogen/content/img/battle-and-bots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/cryogen/content/img/battle-and-bots.png
--------------------------------------------------------------------------------
/native-image-agent-filter.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": [
3 | {
4 | "excludeClasses": "io.netty.**"
5 | }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/resources/186669__fordps3__computer-boop.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/186669__fordps3__computer-boop.wav
--------------------------------------------------------------------------------
/cryogen/content/img/failed-dworld-minimap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/cryogen/content/img/failed-dworld-minimap.png
--------------------------------------------------------------------------------
/repo/gr/zdimensions/jsquish/1.0/jsquish-1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/repo/gr/zdimensions/jsquish/1.0/jsquish-1.0.jar
--------------------------------------------------------------------------------
/resources/public/iconfont/material-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/public/iconfont/material-icons.woff
--------------------------------------------------------------------------------
/resources/public/iconfont/material-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/resources/public/iconfont/material-icons.woff2
--------------------------------------------------------------------------------
/cryogen/content/img/battle-minimap-and-resources.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/cryogen/content/img/battle-minimap-and-resources.png
--------------------------------------------------------------------------------
/resources/skylobby-web.properties:
--------------------------------------------------------------------------------
1 | arguments="headless"
2 | java-options=-Xmx2g -XX:+ExitOnOutOfMemoryError -XX:+DoEscapeAnalysis -XX:+UseCompressedOops
3 |
--------------------------------------------------------------------------------
/repo/io/github/memo33/jsquish/2.0.1/jsquish-2.0.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skynet-gh/skylobby/HEAD/repo/io/github/memo33/jsquish/2.0.1/jsquish-2.0.1.jar
--------------------------------------------------------------------------------
/jpackage/windows:
--------------------------------------------------------------------------------
1 | --win-menu
2 | --type "msi"
3 | --icon "resources/icon.ico"
4 | --win-dir-chooser
5 | --java-options "-Dprism.allowhidpi=true -Dglass.win.minHiDPI=1"
6 |
--------------------------------------------------------------------------------
/native-res/linux/META-INF/native-image/skylobby/java/predefined-classes-config.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type":"agent-extracted",
4 | "classes":[
5 | ]
6 | }
7 | ]
8 |
9 |
--------------------------------------------------------------------------------
/native-res/linux/META-INF/native-image/skylobby/java/serialization-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "types":[
3 | ],
4 | "lambdaCapturingTypes":[
5 | ],
6 | "proxies":[
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/java/predefined-classes-config.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type":"agent-extracted",
4 | "classes":[
5 | ]
6 | }
7 | ]
8 |
9 |
--------------------------------------------------------------------------------
/jvm-flags:
--------------------------------------------------------------------------------
1 | -XX:+UseZGC -Xmx2g -XX:+ExitOnOutOfMemoryError -XX:+DoEscapeAnalysis -XX:+UseCompressedOops --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED
2 |
--------------------------------------------------------------------------------
/jpackage/mac:
--------------------------------------------------------------------------------
1 | --icon "resources/icon.ico"
2 | --java-options "-Xmx2g -XX:+ExitOnOutOfMemoryError -XX:+DoEscapeAnalysis -XX:+UseCompressedOops --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
3 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/lua-parser"]
2 | path = lib/lua-parser
3 | url = https://github.com/bkiers/lua-parser.git
4 | [submodule "lib/grammars-v4"]
5 | path = lib/grammars-v4
6 | url = https://github.com/antlr/grammars-v4.git
7 |
--------------------------------------------------------------------------------
/cryogen/content/md/pages/index.md:
--------------------------------------------------------------------------------
1 | {:title "Index"
2 | :layout :page
3 | :page-index 0
4 | :navbar? true
5 | :home? true}
6 |
7 | ## skylobby
8 |
9 | Yet another Spring lobby.
10 |
11 | [Development diary](/pages/development/)
12 |
--------------------------------------------------------------------------------
/resources/skylobby-stream-fix.properties:
--------------------------------------------------------------------------------
1 | java-options=-XX:+UseZGC -Xmx2g -Dprism.order=sw -XX:+ExitOnOutOfMemoryError -XX:+DoEscapeAnalysis -XX:+UseCompressedOops --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "dayjs": "^1.11.0",
4 | "material-icons": "^1.10.6",
5 | "react": "^18.0.0",
6 | "react-dom": "^18.0.0"
7 | },
8 | "devDependencies": {
9 | "shadow-cljs": "^2.20.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/cryogen/src/cryogen/core.clj:
--------------------------------------------------------------------------------
1 | (ns cryogen.core
2 | (:require [cryogen-core.compiler :refer [compile-assets-timed]]
3 | [cryogen-core.plugins :refer [load-plugins]]))
4 |
5 | (defn -main []
6 | (load-plugins)
7 | (compile-assets-timed)
8 | (System/exit 0))
9 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/cli/util.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.cli.util)
2 |
3 |
4 | (set! *warn-on-reflection* true)
5 |
6 |
7 | (defn print-and-exit [exit-code & messages]
8 | (doseq [message messages]
9 | (println message))
10 | (shutdown-agents)
11 | (System/exit exit-code))
12 |
--------------------------------------------------------------------------------
/cryogen/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | pom.xml.asc
3 | *jar
4 | /lib/
5 | /classes/
6 | /target/
7 | /checkouts/
8 | .lein-deps-sum
9 | .lein-repl-history
10 | .lein-plugins/
11 | .lein-failures
12 | /public/
13 | /themes/lotus/css/blog.css
14 | /themes/lotus/css/blog.css.map
15 | .cpcache/
16 |
--------------------------------------------------------------------------------
/dist/arch/skylobby.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=skylobby
4 | Exec=skylobby
5 | Icon=skylobby
6 | Comment=Spring RTS games lobby client
7 | Terminal=false
8 | Categories=Game;StrategyGame;
9 | Keywords=real-time;strategy;lobby;network;multiplayer;spring;game;
10 |
--------------------------------------------------------------------------------
/resources/skylobby.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=skylobby
4 | Exec=skylobby
5 | Icon=skylobby
6 | Comment=Spring RTS games lobby client
7 | Terminal=false
8 | Categories=Game;StrategyGame;
9 | Keywords=real-time;strategy;lobby;network;multiplayer;spring;game;
10 |
--------------------------------------------------------------------------------
/tests.edn:
--------------------------------------------------------------------------------
1 | #kaocha/v1
2 | {:kaocha/tests
3 | [{:kaocha.testable/type :kaocha.type/clojure.test
4 | :kaocha.testable/id :unit
5 | :kaocha/ns-patterns ["-test$"]
6 | :kaocha/source-paths ["src/clj" "graal/clj"]
7 | :kaocha/test-paths ["test/clj"]}]
8 | :kaocha.watch/type :hawk}
9 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/replay.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.replay)
2 |
3 |
4 | (set! *warn-on-reflection* true)
5 |
6 |
7 | (defprotocol ReplayIndex
8 | (all-replays [this])
9 | (replay-by-id [this replay-id])
10 | (replay-by-path [this path])
11 | (update-replay [this replay])
12 | (update-replays [this replays]))
13 |
--------------------------------------------------------------------------------
/dist/linux/skylobby.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Name=skylobby
4 | Exec=/opt/skylobby/bin/skylobby
5 | Icon=/opt/skylobby/lib/skylobby.png
6 | Comment=Spring RTS games lobby client
7 | Terminal=false
8 | Categories=Game;StrategyGame;
9 | Keywords=real-time;strategy;lobby;network;multiplayer;spring;game;
10 | MimeType=
11 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/view/settings.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.view.settings
2 | (:require
3 | [skylobby.view.side-nav :as side-nav]))
4 |
5 |
6 | (defn settings-page [_]
7 | [:div {:class "flex"}
8 | [side-nav/side-nav]
9 | [:div {:class "flex-auto justify-center"}
10 | [:div {:class "flex justify-center mb2 f2"}
11 | "Settings"]]])
12 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/flag_icon_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.flag-icon-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | [skylobby.fx.flag-icon :as fx.flag-icon]))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (deftest flag-icon
11 | (is (map?
12 | (fx.flag-icon/flag-icon
13 | {:country-code "US"}))))
14 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/main_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.main-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.main :as fx.main]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest main-window
12 | (is (map?
13 | (fx.main/main-window
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/mods_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.mods-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.mods :as fx.mods]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest mods-view
12 | (is (map?
13 | (fx.mods/mods-view-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/server_tab_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.server-tab-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.server-tab :as fx.server-tab]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest server-tab
12 | (is (map?
13 | (fx.server-tab/server-tab {:fx/context (fx/create-context nil)}))))
14 |
--------------------------------------------------------------------------------
/repo/gr/zdimensions/jsquish/maven-metadata-local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | gr.zdimensions
4 | jsquish
5 |
6 | 1.0
7 |
8 | 1.0
9 |
10 | 20201225204629
11 |
12 |
13 |
--------------------------------------------------------------------------------
/repo/io/github/memo33/jsquish/maven-metadata-local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.github.memo33
4 | jsquish
5 |
6 | 2.0.1
7 |
8 | 2.0.1
9 |
10 | 20220626092300
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/engines_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.engines-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.engines :as fx.engines]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest engines-view
12 | (is (map?
13 | (fx.engines/engines-view-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/map_sync_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.map-sync-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.map-sync :as fx.map-sync]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest map-sync
12 | (is (map?
13 | (fx.map-sync/map-sync-pane-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/mod_sync_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.mod-sync-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.mod-sync :as fx.mod-sync]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest mod-sync
12 | (is (map?
13 | (fx.mod-sync/mod-sync-pane-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/channels_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.channels-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.channels :as fx.channels]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest channels-table
12 | (is (map?
13 | (fx.channels/channels-table
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/minimap_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.minimap-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.minimap :as fx.minimap]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest minimap-pane-impl
12 | (is (map?
13 | (fx.minimap/minimap-pane-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.orig
2 | *.swp
3 | /*.bin
4 | /*.db
5 | /*.deb
6 | /*.dll
7 | /*.exe
8 | /*.jar
9 | /*.log*
10 | /*.rpm
11 | /.calva/
12 | /.classpath
13 | /.cpcache/
14 | /.lsp/
15 | /.nrepl-port
16 | /.project
17 | /.settings/
18 | /.shadow-cljs/
19 | /classes/
20 | /native-image-args
21 | /node_modules/
22 | /pom.xml
23 | /skylobby-*.msi
24 | /skylobby
25 | /target/
26 | /trace.edn
27 | /*.build_artifacts.txt
28 |
--------------------------------------------------------------------------------
/dist/arch/skylobby:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | exec /usr/lib/jvm/java-17-openjdk/bin/java \
3 | -Dglass.gtk.uiScale=1.1 \
4 | -XX:+UseZGC \
5 | -Xmx2g \
6 | -XX:+ExitOnOutOfMemoryError \
7 | -XX:+DoEscapeAnalysis \
8 | -XX:+UseCompressedOops \
9 | --add-opens=java.base/java.nio=ALL-UNNAMED \
10 | --add-opens=java.base/sun.nio.ch=ALL-UNNAMED \
11 | -jar '/usr/share/java/skylobby/skylobby.jar' \
12 | "$@"
13 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/chat_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.chat-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.chat :as fx.chat]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest chat-window-impl
12 | (is (map?
13 | (fx.chat/chat-window-impl
14 | {:fx/context (fx/create-context {:show-chat-window true})}))))
15 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/tags.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Tags{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {% for tag in tags %}
11 | - {{tag.name}}
12 | {% endfor %}
13 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/tags.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Tags{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {% for tag in tags %}
11 | - {{tag.name}}
12 | {% endfor %}
13 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/tags.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Tags{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {% for tag in tags %}
11 | - {{tag.name}}
12 | {% endfor %}
13 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/engine_sync_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.engine-sync-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.engine-sync :as fx.engine-sync]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest engine-sync
12 | (is (map?
13 | (fx.engine-sync/engine-sync-pane-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/tags.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Tags{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 |
10 | {% for tag in tags %}
11 | - {{tag.name}}
12 | {% endfor %}
13 |
14 |
15 | {% endblock %}
16 |
--------------------------------------------------------------------------------
/dev/clj/test/tests.clj:
--------------------------------------------------------------------------------
1 | (ns tests
2 | (:require
3 | [com.jakemccrary.test-refresh :refer [monitor-project]]
4 | hashp.core
5 | [pjstadig.humane-test-output]))
6 |
7 |
8 | (defn -main []
9 | (pjstadig.humane-test-output/activate!)
10 | (monitor-project
11 | ["test/clj"]
12 | {:nses-and-selectors [:ignore [[(constantly true)]]]
13 | :do-not-monitor-keystrokes true
14 | :with-repl false}))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/battle_chat_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battle-chat-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.battle-chat :as fx.battle-chat]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battle-chat-window-impl
12 | (is (map?
13 | (fx.battle-chat/battle-chat-window-impl
14 | {:fx/context (fx/create-context {})}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/battles_window_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battles-window-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.battles-window :as fx.battles-window]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battles-window
12 | (is (map?
13 | (fx.battles-window/battles-window-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/battles_buttons_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battles-buttons-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.battles-buttons :as fx.battles-buttons]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battles-buttons-view
12 | (is (map?
13 | (fx.battles-buttons/battles-buttons-view
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/text_ext.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.text-ext
2 | (:require
3 | [cljfx.composite :as composite]
4 | [cljfx.fx.text :as fx.text])
5 | (:import
6 | (org.fxmisc.richtext TextExt)))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (def props
13 | (merge
14 | fx.text/props
15 | (composite/props TextExt)))
16 |
17 | (def lifecycle
18 | (composite/describe TextExt
19 | :ctor []
20 | :props props))
21 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/pick_spring_root_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.pick-spring-root-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.pick-spring-root :as fx.pick-spring-root]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest pick-spring-root-view
12 | (is (map?
13 | (fx.pick-spring-root/pick-spring-root-view
14 | {:fx/context (fx/create-context nil)}))))
15 |
--------------------------------------------------------------------------------
/shadow-cljs.edn:
--------------------------------------------------------------------------------
1 | {:deps {:aliases [:cljs]}
2 | :builds
3 | {:frontend
4 | {:target :browser
5 | :output-dir "resources/public/js"
6 | :asset-path "/js"
7 | :modules {:main {:entries [skylobby.js]
8 | :init-fn skylobby.js/init}}}
9 | :main
10 | {:target :browser
11 | :output-dir "resources/public/js"
12 | :asset-path "/js"
13 | :modules {:main {:entries [skylobby.web]
14 | :init-fn skylobby.web/init}}}}}
15 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/home.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% include "/html/post-content.html" %}
5 | {% if disqus? %}
6 |
9 | {% endif %}
10 |
11 | {% with prev=post.prev next=post.next%}
12 | {% include "/html/prev-next.html" %}
13 | {% endwith %}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/font_icon.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.font-icon
2 | (:require
3 | [cljfx.composite :as composite]
4 | [cljfx.lifecycle :as lifecycle])
5 | (:import
6 | (org.kordamp.ikonli.javafx FontIcon)))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (def props
13 | (composite/props FontIcon
14 | :icon-literal [:setter lifecycle/scalar]))
15 |
16 | (def lifecycle
17 | (composite/describe FontIcon
18 | :ctor []
19 | :props props))
20 |
--------------------------------------------------------------------------------
/jpackage/lobby:
--------------------------------------------------------------------------------
1 | --verbose
2 | --input target
3 | --main-jar "skylobby.jar"
4 | --name "skylobby"
5 | --main-class "spring_lobby.main"
6 | --vendor "skynet"
7 | --java-options "-XX:+UseZGC -Xmx2g -XX:+ExitOnOutOfMemoryError -XX:+DoEscapeAnalysis -XX:+UseCompressedOops --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
8 | --file-associations "resources/FAsdfz.properties"
9 | --add-launcher skylobby-stream-fix="resources/skylobby-stream-fix.properties"
10 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/tag.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts Tagged "{{name}}"{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 | {% for post in posts %}
10 | -
11 | {{post.title}}
12 |
13 | {% endfor %}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/tag.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts Tagged "{{name}}"{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 | {% for post in posts %}
10 | -
11 | {{post.title}}
12 |
13 | {% endfor %}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/tag.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts Tagged "{{name}}"{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 | {% for post in posts %}
10 | -
11 | {{post.title}}
12 |
13 | {% endfor %}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/sync_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.sync-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.sync :as fx.sync]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest sync-pane
12 | (is (map?
13 | (fx.sync/sync-pane
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.sync/sync-pane
17 | {:fx/context (fx/create-context nil)
18 | :issues [{}]}))))
19 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/tag.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts Tagged "{{name}}"{% endblock %}
3 | {% block content %}
4 |
5 |
8 |
9 | {% for post in posts %}
10 | -
11 | {{post.title}}
12 |
13 | {% endfor %}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/cryogen/README.md:
--------------------------------------------------------------------------------
1 | # Repo docs on gh-pages using Cryogen
2 |
3 | [GitHub Pages for this repo](https://skynet-gh/skylobby/) using [Cryogen](https://github.com/cryogen-project/cryogen).
4 |
5 | ### Dev
6 |
7 | To run a local server, run
8 |
9 | ```
10 | lein serve
11 | ```
12 |
13 | A browser should be opened to http://localhost:3000/skylobby
14 |
15 | ### Build
16 |
17 | GitHub actions now publishes content to the `gh-pages` branch automatically. To build manually, run
18 |
19 | ```
20 | clj -M:build
21 | ```
22 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/README.md:
--------------------------------------------------------------------------------
1 | # About Lotus
2 | An elegant and responsive theme for Cryogen by [Matthew Davidson](https://github.com/KingMob). To see it live, visit my site, [modulolotus.net](https://modulolotus.net).
3 |
4 | # Install
5 |
6 | 1. Change the `:theme` key in `content/config.edn` to "lotus".
7 | 2. Replace the GitHub and LinkedIn links in `base.html` with links to your own profiles. (More social media icons can be found in `icons.svg`.)
8 | 3. Replace the white lotus logo with the logo of your choice in `base.html`.
9 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/user_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.user-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.user :as fx.user]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest users-view
12 | (is (map?
13 | (fx.user/users-view-impl
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 |
18 | (deftest users-table
19 | (is (map?
20 | (fx.user/users-table-impl
21 | {:fx/context (fx/create-context nil)}))))
22 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 | on:
3 | push:
4 | branches: [ master ]
5 | pull_request:
6 | branches: [ master ]
7 | workflow_dispatch:
8 | jobs:
9 | lint:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v4.1.1
13 | - uses: DeLaGuardo/clojure-lint-action@master
14 | with:
15 | clj-kondo-args: --config-paths ^:replace [] --config .clj-kondo\ci-config.edn --lint src/clj graal/clj src/cljs graal/cljc
16 | github_token: ${{ secrets.GITHUB_TOKEN }}
17 |
--------------------------------------------------------------------------------
/repo/gr/zdimensions/jsquish/1.0/jsquish-1.0.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | gr.zdimensions
6 | jsquish
7 | 1.0
8 | POM was created from install:install-file
9 |
10 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/root_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.root-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.root :as fx.root]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battle-window
12 | (is (map?
13 | (fx.root/battle-window
14 | {:fx/context (fx/create-context nil)
15 | :screen-bounds {}}))))
16 |
17 | (deftest root-view
18 | (is (map?
19 | (fx.root/root-view-impl {:fx/context (fx/create-context nil)}))))
20 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/author.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts by {{author}} {% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/host_battle_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.host-battle-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.host-battle :as fx.host-battle]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest host-battle-window
12 | (is (map?
13 | (fx.host-battle/host-battle-window-impl
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.host-battle/host-battle-window-impl
17 | {:fx/context (fx/create-context {:show-host-battle-window true})}))))
18 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/author.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts by {{author}} {% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/graal/cljc/skylobby/common/util.cljc:
--------------------------------------------------------------------------------
1 | (ns skylobby.common.util)
2 |
3 |
4 | (defn server-type
5 | "Returns a keyword representing the type of server given its key. Used for dispatching actions
6 | based on these broad server groups."
7 | [server-key]
8 | (cond
9 | (string? server-key) :spring-lobby
10 | (= :local server-key) :singleplayer
11 | (map? server-key)
12 | (if (:host server-key)
13 | :direct-host
14 | :direct-client)
15 | :else nil))
16 |
17 | (defn is-direct? [server-key]
18 | (#{:direct-host :direct-client} (server-type server-key)))
19 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/matchmaking_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.matchmaking-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.matchmaking :as fx.matchmaking]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest matchmaking-view
12 | (is (map?
13 | (fx.matchmaking/matchmaking-view
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest matchmaking-window
18 | (is (map?
19 | (fx.matchmaking/matchmaking-window-impl
20 | {:fx/context (fx/create-context nil)}))))
21 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/archives.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Archives{% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/archives.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Archives{% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/update-native-res.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | jar="target/skylobby.jar"
4 |
5 | if [[ ! -f "$jar" ]]
6 | then
7 | ./build-jar.sh
8 | fi
9 |
10 | wget -N https://github.com/skynet-gh/clojure-native-image-agent/releases/download/v0.2.0%2Bfix-noclass%2Bcustom-ignore/clojure-native-image-agent.jar
11 |
12 | config="native-res/linux/META-INF/native-image/skylobby"
13 |
14 | java \
15 | -javaagent:clojure-native-image-agent.jar=initialize-class=skylobby.main,output-dir=$config/clj,ignore-file=agent-ignore.txt \
16 | -agentlib:native-image-agent=config-merge-dir=$config/java \
17 | -jar $jar "$@"
18 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/archives.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Archives{% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/server_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.server-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.server :as fx.server]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest servers-window
12 | (is (map?
13 | (fx.server/servers-window-impl
14 | {:fx/context (fx/create-context nil)
15 | :screen-bounds {}})))
16 | (is (map?
17 | (fx.server/servers-window-impl
18 | {:fx/context (fx/create-context {:show-servers-window true})
19 | :screen-bounds {}}))))
20 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/archives.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Archives{% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/scenarios_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.scenarios-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.scenarios :as fx.scenarios]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest scenarios-root
12 | (is (map?
13 | (fx.scenarios/scenarios-root
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest scenarios-window
18 | (is (map?
19 | (fx.scenarios/scenarios-window-impl
20 | {:fx/context (fx/create-context nil)
21 | :screen-bounds {}}))))
22 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/reset_password_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.reset-password-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.reset-password :as fx.reset-password]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest reset-password-window
12 | (is (map?
13 | (fx.reset-password/reset-password-window-impl
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.reset-password/reset-password-window-impl
17 | {:fx/context (fx/create-context {:show-reset-password-window true})}))))
18 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/author.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts by {{author}} {% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/author.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: Posts by {{author}} {% endblock %}
3 | {% block content %}
4 |
5 |
8 | {% for group in groups %}
9 |
{{group.group}}
10 |
11 | {% for post in group.posts %}
12 | -
13 | {{post.date|date:"MMM dd"}} - {{post.title}}
14 |
15 | {% endfor %}
16 |
17 | {% endfor %}
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/register_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.register-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.register :as fx.register]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest register-window
12 | (is (map?
13 | (fx.register/register-window-impl
14 | {:fx/context (fx/create-context nil)
15 | :screen-bounds {}})))
16 | (is (map?
17 | (fx.register/register-window-impl
18 | {:fx/context (fx/create-context {:show-register-window true})
19 | :screen-bounds {}}))))
20 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/css/_buttons.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | .button {
4 | background: none;
5 | border: $default-border;
6 | position: relative;
7 | display: inline-block;
8 | padding: 7px 12px;
9 | margin: 0;
10 | width: auto;
11 | font-family: $wide-font-family;
12 | font-size: $button-font-size;
13 | text-transform: uppercase;
14 |
15 | cursor: pointer;
16 | text-align: left;
17 | text-decoration: none;
18 | letter-spacing: 2px;
19 |
20 | &:hover {
21 | background: $default-border-color;
22 | color: $white;
23 | }
24 |
25 | &:active {
26 | top: 1px;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/css/lotus-highlightjs.min.css:
--------------------------------------------------------------------------------
1 | .hljs{display:block;overflow-x:auto;padding:0.5em;background:#fbfbfb}.hljs,.hljs-subst{color:#000}.hljs-string,.hljs-meta,.hljs-symbol,.hljs-template-tag,.hljs-template-variable,.hljs-addition{color:#756bb1}.hljs-comment,.hljs-quote{color:#636363}.hljs-number,.hljs-regexp,.hljs-literal,.hljs-bullet,.hljs-link{color:#31a354}.hljs-deletion,.hljs-variable{color:#88f}.hljs-keyword,.hljs-selector-tag,.hljs-title,.hljs-section,.hljs-built_in,.hljs-doctag,.hljs-type,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-strong{color:#3182bd}.hljs-emphasis{font-style:italic}.hljs-attribute{color:#e6550d}
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/home.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% include "/html/post-content.html" %}
5 | {% if disqus? %}
6 |
9 | {% endif %}
10 |
11 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/prev-next.html:
--------------------------------------------------------------------------------
1 |
2 | {% if prev %}
3 |
{{prev.title}}
4 | {% else %}
5 |
6 | {% endif %}
7 | {% if next %}
8 |
{{next.title}}
9 | {% else %}
10 |
11 | {% endif %}
12 |
13 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/home.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% include "/html/post-content.html" %}
5 | {% if disqus? %}
6 |
9 | {% endif %}
10 |
11 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/post-content.html:
--------------------------------------------------------------------------------
1 |
10 |
11 | {% if post.toc %}{{post.toc|safe}}{% endif %}
12 | {{post.content|safe}}
13 |
14 | {% if post.tags|not-empty %}
15 |
16 |
Tags:
17 | {% for tag in post.tags %}
18 |
{{tag.name}}
19 | {% endfor %}
20 |
21 | {% endif %}
22 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/post-content.html:
--------------------------------------------------------------------------------
1 |
10 |
11 | {% if post.toc %}{{post.toc|safe}}{% endif %}
12 | {{post.content|safe}}
13 |
14 | {% if post.tags|not-empty %}
15 |
16 |
Tags:
17 | {% for tag in post.tags %}
18 |
{{tag.name}}
19 | {% endfor %}
20 |
21 | {% endif %}
22 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/home.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% include "/html/post-content.html" %}
5 | {% if disqus? %}
6 |
9 | {% endif %}
10 |
11 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/post-content.html:
--------------------------------------------------------------------------------
1 |
10 |
11 | {% if post.toc %}{{post.toc|safe}}{% endif %}
12 | {{post.content|safe}}
13 |
14 | {% if post.tags|not-empty %}
15 |
16 |
17 |
Tags:
18 | {% for tag in post.tags %}
19 |
{{tag.name}}
20 | {% endfor %}
21 |
22 | {% endif %}
23 |
24 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/color_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.color-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | [skylobby.fx.color :as fx.color])
5 | (:import
6 | (javafx.scene.paint Color)))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (deftest spring-color-to-javafx
13 | (is (= "0x000000ff"
14 | (str
15 | (fx.color/spring-color-to-javafx nil))))
16 | (is (= "0x393000ff"
17 | (str
18 | (fx.color/spring-color-to-javafx 12345)))))
19 |
20 | (deftest javafx-color-to-spring
21 | (is (= 0
22 | (fx.color/javafx-color-to-spring nil)))
23 | (is (= 12345
24 | (fx.color/javafx-color-to-spring (Color/web "0x393000ff")))))
25 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/import_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.import-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.import :as fx.import]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest importer-root
12 | (is (map?
13 | (fx.import/importer-root
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest import-window
18 | (is (map?
19 | (fx.import/import-window
20 | {:fx/context (fx/create-context nil)
21 | :screen-bounds {}})))
22 | (is (map?
23 | (fx.import/import-window
24 | {:fx/context (fx/create-context {:show-importer true})
25 | :screen-bounds {}}))))
26 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/settings_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.settings-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.settings :as fx.settings]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battle-settings
12 | (is (map?
13 | (fx.settings/battle-settings
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest settings-root
18 | (is (map?
19 | (fx.settings/settings-root
20 | {:fx/context (fx/create-context nil)}))))
21 |
22 |
23 | (deftest settings-window
24 | (is (map?
25 | (fx.settings/settings-window-impl
26 | {:fx/context (fx/create-context nil)
27 | :screen-bounds {}}))))
28 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/post-content.html:
--------------------------------------------------------------------------------
1 |
12 |
13 | {% if post.toc %}{{post.toc|safe}}{% endif %}
14 | {{post.content|safe}}
15 |
16 | {% if post.tags|not-empty %}
17 |
18 |
19 |
Tags:
20 | {% for tag in post.tags %}
21 |
{{tag.name}}
22 | {% endfor %}
23 |
24 | {% endif %}
25 |
26 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/tasks_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.tasks-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.tasks :as fx.tasks]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest tasks-root
12 | (is (map?
13 | (fx.tasks/tasks-root
14 | {:fx/context (fx/create-context nil)
15 | :screen-bounds {}})))
16 | )
17 |
18 | (deftest tasks-window
19 | (is (map?
20 | (fx.tasks/tasks-window
21 | {:fx/context (fx/create-context nil)
22 | :screen-bounds {}})))
23 | (is (map?
24 | (fx.tasks/tasks-window
25 | {:fx/context (fx/create-context {:show-tasks-window true})
26 | :screen-bounds {}}))))
27 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/rapid_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.rapid-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.rapid :as fx.rapid]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest rapid-download-root
12 | (is (map?
13 | (fx.rapid/rapid-download-root
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest rapid-download-window
18 | (is (map?
19 | (fx.rapid/rapid-download-window
20 | {:fx/context (fx/create-context nil)
21 | :screen-bounds {}})))
22 | (is (map?
23 | (fx.rapid/rapid-download-window
24 | {:fx/context (fx/create-context {:show-rapid-downloader true})
25 | :screen-bounds {}}))))
26 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/spring_info_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.spring-info-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.spring-info :as fx.spring-info]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest spring-info-root
12 | (is (map?
13 | (fx.spring-info/spring-info-root
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.spring-info/spring-info-root
17 | {:fx/context (fx/create-context {:spring-crash-archive-not-found {}})}))))
18 |
19 |
20 | (deftest spring-info-window
21 | (is (map?
22 | (fx.spring-info/spring-info-window
23 | {:fx/context (fx/create-context nil)
24 | :screen-bounds {}}))))
25 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/view/tasks.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.view.tasks
2 | (:require
3 | [re-frame.core :as rf]
4 | [skylobby.view.side-nav :as side-nav]))
5 |
6 |
7 | (defn listen [query-v]
8 | @(rf/subscribe query-v))
9 |
10 | (defn tasks-page [_]
11 | (let [{:keys [current-tasks tasks-by-kind]} (listen [:skylobby/tasks])]
12 | [:div {:class "flex"}
13 | [side-nav/side-nav]
14 | [:div {:class "flex-auto justify-center"}
15 | [:div {:class "flex justify-center mb2 f2"}
16 | "Tasks"]
17 | [:div
18 | "Current: "
19 | (str (count current-tasks))]
20 | [:div
21 | "Queued: "
22 | (str (count (mapcat second tasks-by-kind)))]
23 | [:div
24 | "Types: "
25 | (str (keys tasks-by-kind))]]]))
26 |
--------------------------------------------------------------------------------
/cryogen/deps.edn:
--------------------------------------------------------------------------------
1 | {:deps {org.clojure/clojure {:mvn/version "1.10.1"}
2 | ring-server/ring-server {:mvn/version "0.5.0"}
3 | ring/ring-devel {:mvn/version "1.8.2"}
4 | compojure/compojure {:mvn/version "1.6.2"}
5 | cryogen-flexmark/cryogen-flexmark {:mvn/version "0.1.4"}
6 | cryogen-core/cryogen-core {:mvn/version "0.4.0"}}
7 | :aliases {;; Run with `clojure -M:build`
8 | :build {:main-opts ["-m" "cryogen.core"]}
9 | ;; Start a server serving the blog: `clojure -X:serve`
10 | ;; (requires tools-deps 0.9.745+)
11 | :serve {:exec-fn cryogen.server/serve
12 | :exec-args {:port 3000}}
13 | :serve-fast {:exec-fn cryogen.server/serve
14 | :exec-args {:port 3000, :fast true}}}}
15 |
--------------------------------------------------------------------------------
/update-native-res.ps1:
--------------------------------------------------------------------------------
1 |
2 | $jar = ".\target\skylobby.jar"
3 |
4 | if (!(Test-Path -Path $jar))
5 | {
6 | .\build-jar.ps1
7 | }
8 |
9 | $agent = "clojure-native-image-agent"
10 | $agentjar = "$agent.jar"
11 |
12 | if (!(Test-Path -Path $agentjar))
13 | {
14 | $url = "https://github.com/skynet-gh/$agent/releases/download/v0.2.0%2Bfix-noclass%2Bcustom-ignore/$agentjar"
15 | Write-Host "Downloading from $url to $agentjar"
16 | Invoke-WebRequest $url -OutFile $agentjar
17 | }
18 |
19 | $config = "native-res\windows\META-INF\native-image\skylobby"
20 |
21 | & "$env:GRAALVM_HOME\bin\java" `
22 | -javaagent:clojure-native-image-agent.jar="initialize-class=skylobby.main,output-dir=$config\clj,ignore-file=agent-ignore.txt" `
23 | -agentlib:native-image-agent="config-merge-dir=$config\java" `
24 | -jar $jar $args
25 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/flag_icon.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.flag-icon
2 | (:require
3 | [taoensso.timbre :as log])
4 | (:import
5 | (griffon.javafx.support.flagicons FlagIcon)))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (defn flag-image [^String country-code]
12 | (try
13 | (FlagIcon. country-code)
14 | (catch Exception e
15 | (log/trace e "Error creating flag icon"))))
16 |
17 | (def flag-image-memoized
18 | (memoize flag-image))
19 |
20 |
21 | (defn flag-icon [{:keys [^String country-code no-text]}]
22 | (let [image (flag-image-memoized country-code)]
23 | (merge
24 | {:fx/type :label
25 | :text (if (and no-text image) "" (str country-code))}
26 | (when image
27 | {:graphic
28 | {:fx/type :image-view
29 | :image image}}))))
30 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/previews.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% for post in posts %}
5 |
14 | {{post.content|safe}}
15 |
Continue reading →
16 |
17 | {% endfor %}
18 |
19 |
20 | {% if prev-uri %}
21 |
« Prev
22 | {% endif %}
23 | {% if next-uri %}
24 |
Next »
25 | {% endif %}
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/main_tabs_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.main-tabs-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.main-tabs :as fx.main-tabs]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest my-channels-view-impl
12 | (is (map?
13 | (fx.main-tabs/my-channels-view-impl
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.main-tabs/my-channels-view-impl
17 | {:fx/context (fx/create-context {:by-server {"server" {:my-channels {"c1" {}}}}})
18 | :server "sever"}))))
19 |
20 |
21 | (deftest battle-details
22 | (is (map?
23 | (fx.main-tabs/battle-details
24 | {:fx/context (fx/create-context nil)}))))
25 |
26 |
27 | (deftest main-tab-view
28 | (is (map?
29 | (fx.main-tabs/main-tab-view
30 | {:fx/context (fx/create-context nil)}))))
31 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/previews.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% for post in posts %}
5 |
14 | {{post.content|safe}}
15 |
Continue reading →
16 |
17 | {% endfor %}
18 |
19 |
20 | {% if prev-uri %}
21 |
« Prev
22 | {% endif %}
23 | {% if next-uri %}
24 |
Next »
25 | {% endif %}
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/page.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block subtitle %}: {{page.title}}{% endblock %}
3 | {% block meta %}
4 | {% if page.description %}
5 |
6 | {% comment %} OpenGraph tags {% endcomment %}
7 |
8 | {% endif %}
9 |
10 |
11 |
12 | {% endblock %}
13 | {% block content %}
14 |
15 |
18 | {% if page.toc %}{{page.toc|safe}}{% endif %}
19 | {{page.content|safe}}
20 |
21 | {% with prev=page.prev next=page.next%}
22 | {% include "/html/prev-next.html" %}
23 | {% endwith %}
24 |
25 |
26 | {% endblock %}
27 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/previews.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% for post in posts %}
5 |
14 | {{post.content|safe}}
15 |
16 |
Continue reading →
17 |
18 | {% endfor %}
19 |
20 |
21 | {% if prev-uri %}
22 |
« Prev
23 | {% endif %}
24 | {% if next-uri %}
25 |
Next »
26 | {% endif %}
27 |
28 |
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/.github/workflows/changelog.yml:
--------------------------------------------------------------------------------
1 | name: Create Release When Changelog Changes
2 | on:
3 | push:
4 | branches: [ master ]
5 | paths:
6 | - 'CHANGELOG.md'
7 | workflow_dispatch:
8 | jobs:
9 | changelog:
10 | runs-on: ubuntu-22.04
11 | steps:
12 | - uses: actions/checkout@v4.1.1
13 | - name: Get last version from tag
14 | id: lasttag
15 | shell: bash
16 | run: echo ::set-output name=version::$(git describe --abbrev=0 --tags --match '[0-9]*\.[0-9]*\.[0-9]*')
17 | - uses: coditory/changelog-parser@v1.0.2
18 | id: changelog
19 | - if: ${{ steps.changelog.outputs.version != steps.lasttag.outputs.version }}
20 | uses: ncipollo/release-action@v1.13.0
21 | with:
22 | body: ${{ steps.changelog.outputs.description }}
23 | prerelease: true
24 | tag: ${{ steps.changelog.outputs.version }}
25 | token: ${{ secrets.CREATE_RELEASE }}
26 |
--------------------------------------------------------------------------------
/cryogen/project.clj:
--------------------------------------------------------------------------------
1 | (defproject cryogen "0.1.0"
2 | :description "Simple static site generator"
3 | :url "https://github.com/lacarmen/cryogen"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.10.1"]
7 | [ring/ring-devel "1.8.2"]
8 | [compojure "1.6.2"]
9 | [ring-server "0.5.0"]
10 | [cryogen-flexmark "0.1.4"]
11 | [cryogen-core "0.4.0"]]
12 | :plugins [[lein-ring "0.12.5"]]
13 | :main cryogen.core
14 | :ring {:init cryogen.server/init
15 | :handler cryogen.server/handler}
16 | :aliases {"serve" ["run" "-m" "cryogen.server"]
17 | "serve-fast" ["run" "-m" "cryogen.server" "fast"]})
18 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/previews.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {% block content %}
3 |
4 | {% for post in posts %}
5 |
14 | {{post.content|safe}}
15 |
16 |
Continue reading →
17 |
18 | {% endfor %}
19 |
20 |
21 | {% if prev-uri %}
22 |
« Prev
23 | {% endif %}
24 | {% if next-uri %}
25 |
Next »
26 | {% endif %}
27 |
28 |
29 | {% endblock %}
30 |
--------------------------------------------------------------------------------
/src/clj/spring_lobby/sound.clj:
--------------------------------------------------------------------------------
1 | (ns spring-lobby.sound
2 | (:require
3 | [clojure.java.io :as io]
4 | [skylobby.fs :as fs]
5 | [taoensso.timbre :as log])
6 | (:import
7 | (javafx.scene.media Media MediaPlayer)))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (def ring-resource-name
14 | "186669__fordps3__computer-boop.wav")
15 |
16 |
17 | (defn play-ring
18 | [{:keys [ring-sound-file ring-volume use-default-ring-sound]}]
19 | (future
20 | (try
21 | (let [ring-uri (if (or use-default-ring-sound (not ring-sound-file))
22 | (str (io/resource ring-resource-name))
23 | (some-> ring-sound-file fs/file .toURI str))
24 | media (Media. ring-uri)
25 | media-player (MediaPlayer. media)]
26 | (.setVolume media-player (or ring-volume 1.0))
27 | (.play media-player))
28 | (catch Exception e
29 | (log/error e "Error playing ring")))))
30 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/welcome_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.welcome-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.welcome :as fx.welcome]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest connect-button
12 | (is (map?
13 | (fx.welcome/connect-button {:fx/context (fx/create-context nil)}))))
14 |
15 | (deftest singleplayer-buttons
16 | (is (map?
17 | (fx.welcome/singleplayer-buttons {:fx/context (fx/create-context nil)}))))
18 |
19 | (deftest multiplayer-buttons
20 | (is (map?
21 | (fx.welcome/multiplayer-buttons {:fx/context (fx/create-context nil)}))))
22 |
23 | (deftest welcome-view
24 | (is (map?
25 | (fx.welcome/welcome-view {:fx/context (fx/create-context nil)})))
26 | (is (map?
27 | (fx.welcome/welcome-view
28 | {:fx/context
29 | (fx/create-context
30 | {:by-server {:local {:battle {:battle-id :singleplayer}}}})}))))
31 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/css/buttons.css:
--------------------------------------------------------------------------------
1 | .button {
2 | position: relative;
3 | display: inline-block;
4 | padding: 7px 12px;
5 | margin: 0;
6 | width: auto;
7 | font-family: "Montserrat";
8 | font-size: 16px;
9 | text-transform: uppercase;
10 | font-weight: 400;
11 | cursor: pointer;
12 | background: none;
13 | border: none;
14 | outline: none;
15 | text-align: left;
16 | letter-spacing: 2px;
17 | }
18 |
19 | .button.fullbutton {
20 | width: 100%;
21 | }
22 |
23 | .button.fullbutton span {
24 | float: right;
25 | }
26 |
27 | .button:after {
28 | content: '';
29 | position: absolute;
30 | z-index: -1;
31 | }
32 |
33 | /** Colours **/
34 |
35 | .button {
36 | background: none;
37 | border: 2px solid #A71E2E;
38 | color: #A71E2E !important;
39 | }
40 |
41 | .button:hover {
42 | background: #A71E2E;
43 | color: #FFF !important;
44 | }
45 |
46 | .button:active {
47 | top: 2px;
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/web.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.web
2 | (:require
3 | [com.fulcrologic.fulcro.application :as app]
4 | [com.fulcrologic.fulcro.components :refer [defsc] :as comp]
5 | [com.fulcrologic.fulcro.dom :as dom]))
6 |
7 |
8 | (defonce app
9 | (app/fulcro-app))
10 |
11 |
12 | (defsc Root [_this _props]
13 | (dom/div "TODO"))
14 |
15 |
16 | (defn ^:export init
17 | "Shadow-cljs sets this up to be our entry-point function. See shadow-cljs.edn `:init-fn` in the modules of the main build."
18 | []
19 | (app/mount! app Root "root")
20 | (js/console.log "Loaded"))
21 |
22 | (defn ^:export refresh
23 | "During development, shadow-cljs will call this on every hot reload of source. See shadow-cljs.edn"
24 | []
25 | ;; re-mounting will cause forced UI refresh, update internals, etc.
26 | (app/mount! app Root "app")
27 | ;; As of Fulcro 3.3.0, this addition will help with stale queries when using dynamic routing:
28 | (comp/refresh-dynamic-queries! app)
29 | (js/console.log "Hot reload"))
30 |
--------------------------------------------------------------------------------
/test/clj/skylobby/task/handler_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.task.handler-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | [skylobby.task.handler :as handler]))
5 |
6 |
7 | (deftest parse-rapid-progress
8 | (is (= {:current 332922
9 | :total 332922}
10 | (handler/parse-rapid-progress "[Progress] 100% [==============================] 332922/332922")))
11 | (is (= {:current 0
12 | :total 0}
13 | (handler/parse-rapid-progress "[Progress] 0% [ ] 0/0")))
14 | (is (= {:current 171880
15 | :total 1024954}
16 | (handler/parse-rapid-progress "[Progress] 17% [===== ] 171880/1024954"))))
17 |
18 | (deftest set-sdd-modinfo-version
19 | (is (= ""
20 | (handler/set-sdd-modinfo-version "" "$VERSION")))
21 | (is (= "version = '$VERSION'"
22 | (handler/set-sdd-modinfo-version "version = 'xxxx'" "$VERSION")))
23 | (is (= "version = 'git:xxxxxxx'"
24 | (handler/set-sdd-modinfo-version "version = '$VERSION'" "git:xxxxxxx"))))
25 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/battles_table_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battles-table-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.battles-table :as fx.battles-table]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest battles-table
12 | (is (map?
13 | (fx.battles-table/battles-table-impl
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.battles-table/battles-table-impl
17 | {:fx/context (fx/create-context {:by-server {"server" {:battles {"1" {:battle-title "b1"}}}}})
18 | :server-key "server"}))))
19 |
20 | (deftest battles-table-with-images
21 | (is (map?
22 | (fx.battles-table/battles-table-with-images-impl
23 | {:fx/context (fx/create-context nil)})))
24 | (is (map?
25 | (fx.battles-table/battles-table-with-images-impl
26 | {:fx/context (fx/create-context {:by-server {"server" {:battles {"1" {:battle-title "b1"}}}}})
27 | :server-key "server"}))))
28 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/event/user.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.event.user
2 | (:require
3 | [skylobby.util :as u]
4 | [taoensso.timbre :as log]))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (defn update-user-state
11 | [state-atom server-key {:keys [username] :as id} user-state]
12 | ; TODO bots
13 | (log/info "Updating user state for" id "with" user-state)
14 | (case (u/server-type server-key)
15 | :direct-host
16 | (let [state (swap! state-atom update-in [:by-server server-key :users username] u/deep-merge user-state)]
17 | (if-let [broadcast-fn (get-in state [:by-server server-key :server :broadcast-fn])]
18 | (let [users (get-in state [:by-server server-key :users])]
19 | (broadcast-fn [:skylobby.direct/users users]))
20 | (log/warn "No broadcast-fn" server-key)))
21 | :direct-client
22 | (if-let [send-fn (get-in @state-atom [:by-server server-key :client :send-fn])]
23 | (send-fn [:skylobby.direct.client/user-state user-state])
24 | (log/warn "No send-fn" server-key))))
25 |
--------------------------------------------------------------------------------
/.github/workflows/pages.yml:
--------------------------------------------------------------------------------
1 | name: Build GitHub Pages Cryogen
2 | on:
3 | push:
4 | branches: [ master ]
5 | paths:
6 | - 'cryogen'
7 | workflow_dispatch:
8 | jobs:
9 | pages:
10 | runs-on: ubuntu-20.04
11 | steps:
12 | - uses: actions/checkout@v4.1.1
13 | - uses: actions/setup-java@v4.0.0
14 | with:
15 | java-version: '21'
16 | distribution: 'adopt'
17 | - uses: DeLaGuardo/setup-clojure@12.1
18 | with:
19 | cli: latest
20 | github-token: ${{ secrets.GITHUB_TOKEN }}
21 | - uses: actions/cache@v3.3.2
22 | with:
23 | path: ~/.m2/repository
24 | key: ${{ runner.os }}-maven-${{ hashFiles('cryogen/project.clj') }}
25 | restore-keys: |
26 | ${{ runner.os }}-maven-
27 | - run: clojure -M:build
28 | working-directory: ./cryogen
29 | - uses: peaceiris/actions-gh-pages@v3.9.3
30 | with:
31 | github_token: ${{ secrets.GITHUB_TOKEN }}
32 | publish_dir: ./cryogen/public/skylobby
33 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/java/serialization-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "types":[
3 | {
4 | "name":"byte[]"
5 | },
6 | {
7 | "name":"java.io.IOException"
8 | },
9 | {
10 | "name":"java.lang.Boolean"
11 | },
12 | {
13 | "name":"java.lang.Exception"
14 | },
15 | {
16 | "name":"java.lang.Integer"
17 | },
18 | {
19 | "name":"java.lang.Long"
20 | },
21 | {
22 | "name":"java.lang.Number"
23 | },
24 | {
25 | "name":"java.lang.Object[]"
26 | },
27 | {
28 | "name":"java.lang.String"
29 | },
30 | {
31 | "name":"java.lang.Throwable"
32 | },
33 | {
34 | "name":"java.net.SocketException"
35 | },
36 | {
37 | "name":"java.util.ArrayList"
38 | },
39 | {
40 | "name":"java.util.HashSet"
41 | },
42 | {
43 | "name":"java.util.TreeMap"
44 | },
45 | {
46 | "name":"long[]"
47 | }
48 | ],
49 | "lambdaCapturingTypes":[
50 | ],
51 | "proxies":[
52 | ]
53 | }
54 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/tooltip_nofocus.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.tooltip-nofocus
2 | (:require
3 | [cljfx.composite :as composite]
4 | [cljfx.fx.tooltip :as fx.tooltip])
5 | (:import
6 | (javafx.scene.control Tooltip)))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | ; https://stackoverflow.com/a/45468459/984393
13 |
14 | (defn create []
15 | (proxy [Tooltip] []
16 | (show
17 | ([^javafx.stage.Window owner]
18 | (when (.isFocused owner)
19 | (let [^Tooltip this this]
20 | (proxy-super show owner))))
21 | ([owner ^double x ^double y]
22 | (let [^Tooltip this this]
23 | (if (instance? javafx.scene.Node owner)
24 | (let [^javafx.scene.Node owner owner]
25 | (when (.isFocused owner)
26 | (proxy-super show owner x y)))
27 | (let [^javafx.stage.Window owner owner]
28 | (when (.isFocused owner)
29 | (proxy-super show owner x y)))))))))
30 |
31 | (def lifecycle
32 | (composite/lifecycle
33 | {:props fx.tooltip/props
34 | :args []
35 | :ctor create}))
36 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/console_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.console-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.console :as fx.console]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest console-document
12 | (is (some?
13 | (fx.console/console-document
14 | [{:message-type "PING"
15 | :message "PING"
16 | :source :client
17 | :timestamp 0}]))))
18 |
19 |
20 | (deftest console-view
21 | (is (map?
22 | (fx.console/console-view
23 | {:fx/context (fx/create-context {:selected-tab-main {"server-key" "console"}
24 | :by-server {"server-key" {:console-log [{:message-type "PING"
25 | :message "PING"
26 | :source :client
27 | :timestamp 0}]}}})
28 | :server-key "server-key"}))))
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 skynet
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/page.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{page.title}}{% endblock %}
3 | {% block meta %}
4 | {% if page.description %}
5 |
6 | {% comment %} OpenGraph tags {% endcomment %}
7 |
8 | {% endif %}
9 |
10 |
11 |
12 | {% endblock %}
13 | {% block content %}
14 |
15 |
18 | {% if page.toc %}{{page.toc|safe}}{% endif %}
19 | {{page.content|safe}}
20 |
21 |
29 |
30 | {% endblock %}
31 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/virtualized_scroll_pane.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.virtualized-scroll-pane
2 | (:require
3 | [cljfx.coerce :as coerce]
4 | [cljfx.composite :as composite]
5 | [cljfx.fx.region :as fx.region]
6 | [cljfx.lifecycle :as lifecycle]
7 | [cljfx.mutator :as mutator])
8 | (:import
9 | (javafx.scene.control ScrollPane$ScrollBarPolicy)
10 | (org.fxmisc.flowless VirtualizedScrollPane)))
11 |
12 |
13 | (set! *warn-on-reflection* true)
14 |
15 | (def props
16 | (merge
17 | fx.region/props
18 | (composite/props VirtualizedScrollPane
19 | :content [mutator/forbidden lifecycle/dynamic]
20 | :hbar-policy [:setter lifecycle/scalar
21 | :coerce (coerce/enum ScrollPane$ScrollBarPolicy)
22 | :default :as-needed]
23 | :vbar-policy [:setter lifecycle/scalar
24 | :coerce (coerce/enum ScrollPane$ScrollBarPolicy)
25 | :default :as-needed])))
26 |
27 | (def lifecycle
28 | (composite/lifecycle
29 | {:props props
30 | :args [:content]
31 | :ctor (fn [content]
32 | (VirtualizedScrollPane. content))}))
33 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/bottom_bar_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.bottom-bar-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fs :as fs]
6 | [skylobby.fx.bottom-bar :as fx.bottom-bar]))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (deftest app-update-button
13 | (is (map?
14 | (fx.bottom-bar/app-update-button
15 | {:fx/context (fx/create-context nil)})))
16 | (is (map?
17 | (fx.bottom-bar/app-update-button
18 | {:fx/context (fx/create-context {:app-update-available true})}))))
19 |
20 |
21 | (deftest bottom-bar-impl
22 | (is (map?
23 | (fx.bottom-bar/bottom-bar-impl
24 | {:fx/context (fx/create-context nil)})))
25 | (is (map?
26 | (fx.bottom-bar/bottom-bar-impl
27 | {:fx/context (fx/create-context {:music-dir "."})})))
28 | (is (map?
29 | (fx.bottom-bar/bottom-bar-impl
30 | {:fx/context (fx/create-context {:music-dir "."
31 | :music-now-playing (fs/file ".")
32 | :music-queue [:song1 :song2]})}))))
33 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/color.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.color
2 | (:require
3 | [com.evocomputing.colors :as colors]
4 | [skylobby.util :as u])
5 | (:import
6 | (javafx.scene.paint Color)))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (defn spring-color-to-javafx
13 | "Returns the rgb int color represention for the given Spring bgr int color."
14 | [spring-color]
15 | (let [spring-color-int (or (u/to-number spring-color) 0)
16 | [r g b _a] (:rgba (colors/create-color spring-color-int))
17 | reversed (colors/create-color
18 | {:r b
19 | :g g
20 | :b r})]
21 | (Color/web (format "#%06x" (colors/rgb-int reversed)))))
22 |
23 | (defn javafx-color-to-spring
24 | "Returns the spring bgr int color format from a javafx color."
25 | [^Color color]
26 | (if color
27 | (colors/rgba-int
28 | (colors/create-color
29 | {:r (Math/round (* 255 (.getBlue color))) ; switch blue to red
30 | :g (Math/round (* 255 (.getGreen color)))
31 | :b (Math/round (* 255 (.getRed color))) ; switch red to blue
32 | :a 0}))
33 | 0))
34 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/download_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.download-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.download :as fx.download]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest downloader-root
12 | (is (map?
13 | (fx.download/downloader-root
14 | {:fx/context (fx/create-context nil)})))
15 | (is (map?
16 | (fx.download/downloader-root
17 | {:fx/context (fx/create-context {:downloadables-by-url {"url" {:download-source-name "d"
18 | :resource-filename "f1"}}
19 | :download-source-name "d"
20 | :download-filter "f"})}))))
21 |
22 |
23 | (deftest download-window
24 | (is (map?
25 | (fx.download/download-window
26 | {:fx/context (fx/create-context nil)
27 | :screen-bounds {}})))
28 | (is (map?
29 | (fx.download/download-window
30 | {:fx/context (fx/create-context {:show-downloader true})
31 | :screen-bounds {}}))))
32 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/view/side_nav.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.view.side-nav
2 | (:require
3 | [re-frame.core :as rf]
4 | [skylobby.util :as u]))
5 |
6 |
7 | (defn listen [query-v]
8 | @(rf/subscribe query-v))
9 |
10 |
11 | (def navs
12 | [{:route :skylobby/servers
13 | :icon "web"}
14 | {:route :skylobby/replays
15 | :icon "movie"}
16 | {:route :skylobby/settings
17 | :icon "settings"}
18 | {:route :skylobby/tasks
19 | :icon "memory"}
20 | {:route :skylobby/quit
21 | :icon "logout"}])
22 |
23 | (defn side-nav [_]
24 | (let [current-route (listen [:skylobby/current-route])]
25 | [:div {:class "flex-column"}
26 | (for [{:keys [icon route]} navs]
27 | (let [color (if (= route (get-in current-route [:data :name]))
28 | "red"
29 | "gray")]
30 | ^{:key route}
31 | [:div.ma2
32 | [:div
33 | {:class (str "ba bw1 br2 ma2 b--" color " ")}
34 | [:a
35 | {
36 | :class color
37 | :href (u/href route)}
38 | [:span.material-icons
39 | {:style {:font-size 48}}
40 | icon]]]]))]))
41 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/page.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{page.title}}{% endblock %}
3 | {% block meta %}
4 | {% if page.description %}
5 |
6 | {% comment %} OpenGraph tags {% endcomment %}
7 |
8 | {% endif %}
9 |
10 |
11 |
12 | {% endblock %}
13 | {% block content %}
14 |
15 |
18 | {% if page.toc %}{{page.toc|safe}}{% endif %}
19 | {{page.content|safe}}
20 |
21 |
32 |
33 | {% endblock %}
34 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/page.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{page.title}}{% endblock %}
3 | {% block meta %}
4 | {% if page.description %}
5 |
6 | {% comment %} OpenGraph tags {% endcomment %}
7 |
8 | {% endif %}
9 |
10 |
11 |
12 | {% endblock %}
13 | {% block content %}
14 |
15 |
18 | {% if page.toc %}{{page.toc|safe}}{% endif %}
19 | {{page.content|safe}}
20 |
21 |
32 |
33 | {% endblock %}
34 |
--------------------------------------------------------------------------------
/.clj-kondo/ci-config.edn:
--------------------------------------------------------------------------------
1 | {:lint-as {com.fulcrologic.fulcro.components/defsc clojure.core/defn}
2 | :linters
3 | {:unresolved-symbol
4 | {:exclude [(diehard.core/defratelimiter)
5 | (taoensso.nippy/extend-freeze)
6 | (taoensso.nippy/extend-thaw)]}
7 | :unresolved-var
8 | {:exclude [gloss.core/compile-frame
9 | gloss.io/to-byte-buffer]}
10 | :warn-on-reflection
11 | {:level :warn
12 | :warn-only-on-interop false}
13 | :aliased-namespace-symbol {:level :off}
14 | :docstring-no-summary {:level :off}
15 | :docstring-leading-trailing-whitespace {:level :off}
16 | :dynamic-var-not-earmuffed {:level :off}
17 | :reduce-without-init {:level :warn}
18 | :keyword-binding {:level :warn}
19 | :main-without-gen-class {:level :off}
20 | :missing-docstring {:level :off}
21 | :namespace-name-mismatch {:level :error}
22 | :redundant-fn-wrapper {:level :off}
23 | :refer {:level :off}
24 | :single-key-in {:level :warn}
25 | :shadowed-var {:level :off}
26 | :used-underscored-binding {:level :warn}
27 | :unused-value {:level :warn}
28 | :unsorted-required-namespaces {:level :warn}}
29 | :output
30 | {
31 | :exclude-files ["event_stub.clj"]}}
32 |
--------------------------------------------------------------------------------
/.clj-kondo/config.edn:
--------------------------------------------------------------------------------
1 | {:lint-as {com.fulcrologic.fulcro.components/defsc clojure.core/defn}
2 | :linters
3 | {:unresolved-symbol
4 | {:exclude [(diehard.core/defratelimiter)
5 | (taoensso.nippy/extend-freeze)
6 | (taoensso.nippy/extend-thaw)]}
7 | :unresolved-var
8 | {:exclude [gloss.core/compile-frame
9 | gloss.io/to-byte-buffer]}
10 | :warn-on-reflection
11 | {:level :warn
12 | :warn-only-on-interop false}
13 | :aliased-namespace-symbol {:level :info}
14 | :docstring-no-summary {:level :info}
15 | :docstring-leading-trailing-whitespace {:level :info}
16 | :dynamic-var-not-earmuffed {:level :info}
17 | :reduce-without-init {:level :warn}
18 | :keyword-binding {:level :warn}
19 | :main-without-gen-class {:level :info}
20 | :missing-docstring {:level :info}
21 | :namespace-name-mismatch {:level :error}
22 | :redundant-fn-wrapper {:level :info}
23 | :refer {:level :info}
24 | :single-key-in {:level :warn}
25 | :shadowed-var {:level :info}
26 | :used-underscored-binding {:level :warn}
27 | :unused-value {:level :warn}
28 | :unsorted-required-namespaces {:level :warn}}
29 | :output
30 | {
31 | :exclude-files ["event_stub.clj"]}}
32 |
--------------------------------------------------------------------------------
/repo/io/github/memo33/jsquish/2.0.1/jsquish-2.0.1.pom:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.github.memo33
5 | jsquish
6 | jar
7 | jsquish
8 | 2.0.1
9 |
10 |
11 | BSD 3-Clause
12 | https://opensource.org/licenses/BSD-3-Clause
13 | repo
14 |
15 |
16 | jsquish
17 |
18 | com.github.memo33
19 |
20 |
21 |
22 | bintraymemo33maven
23 | bintray-memo33-maven
24 | https://dl.bintray.com/memo33/maven/
25 | default
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/clj/skylobby/task_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.task-test
2 | (:require
3 | [clojure.test :refer [deftest is testing]]
4 | [skylobby.task :as task]))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (deftest add-task!
11 | (testing "kind and dedupe in queue"
12 | (let [state (atom {})]
13 | (task/add-task! state {:spring-lobby/task-type :spring-lobby/fake-task})
14 | (task/add-task! state {:spring-lobby/task-type :spring-lobby/fake-task})
15 | (task/add-task! state {:spring-lobby/task-type :spring-lobby/refresh-engines})
16 | (task/add-task! state {:spring-lobby/task-type :spring-lobby/download-and-extract})
17 | (task/add-task! state {:spring-lobby/task-type :spring-lobby/update-rapid})
18 | (is (= {:tasks-by-kind
19 | {:spring-lobby/other-task
20 | #{{:spring-lobby/task-type :spring-lobby/fake-task}}
21 | :spring-lobby/index-task
22 | #{{:spring-lobby/task-type :spring-lobby/refresh-engines}}
23 | :spring-lobby/download-task
24 | #{{:spring-lobby/task-type :spring-lobby/download-and-extract}}
25 | :spring-lobby/rapid-task
26 | #{{:spring-lobby/task-type :spring-lobby/update-rapid}}}}
27 | @state)))))
28 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/client/stls.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.client.stls
2 | (:require
3 | [taoensso.timbre :as log])
4 | (:import
5 | (io.netty.channel ChannelPipeline)
6 | (io.netty.handler.ssl SslContextBuilder SslHandler)
7 | (io.netty.handler.ssl.util InsecureTrustManagerFactory)))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (defn upgrade-pipeline [^ChannelPipeline pipeline]
14 | (if pipeline
15 | (let [; https://github.com/clj-commons/aleph/blob/master/src/aleph/netty.clj#L721-L724
16 | ssl-context-builder (SslContextBuilder/forClient)
17 | _ (.trustManager ssl-context-builder InsecureTrustManagerFactory/INSTANCE)
18 | _ (.startTls ssl-context-builder true)
19 | ssl-context (.build ssl-context-builder)
20 | ch (.channel pipeline)
21 | engine (.newEngine ssl-context (.alloc ch))
22 | handler (SslHandler. engine false)
23 | handshake-future (.handshakeFuture handler)]
24 | (.addFirst pipeline "ssl" handler)
25 | (log/info "Added SslHandler to TCP pipeline")
26 | (log/info "Waiting for SSL handshake")
27 | (let [handshake @handshake-future]
28 | (log/info "SSL handshake finished" handshake)
29 | true))
30 | (log/warn "No TCP pipeline to upgrade to TLS!")))
31 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/channel_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.channel-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.channel :as fx.channel]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest channel-document
12 | (is (some?
13 | (fx.channel/channel-document
14 | [{:message-type :ex
15 | :text "message"
16 | :timestamp 0
17 | :username "me"}])))
18 | (is (some?
19 | (fx.channel/channel-document
20 | [{:message-type nil
21 | :text "message 2"
22 | :timestamp 1
23 | :username "me"}]))))
24 |
25 |
26 | (deftest channel-view-history-impl
27 | (is (map?
28 | (fx.channel/channel-view-history-impl
29 | {:fx/context (fx/create-context nil)}))))
30 |
31 |
32 | (deftest channel-view-input
33 | (is (map?
34 | (fx.channel/channel-view-input
35 | {:fx/context (fx/create-context nil)}))))
36 |
37 |
38 | (deftest channel-view-users
39 | (is (map?
40 | (fx.channel/channel-view-users
41 | {:fx/context (fx/create-context nil)}))))
42 |
43 |
44 | (deftest channel-view
45 | (is (map?
46 | (fx.channel/channel-view
47 | {:fx/context (fx/create-context nil)}))))
48 |
--------------------------------------------------------------------------------
/cryogen/content/config.edn:
--------------------------------------------------------------------------------
1 | {:site-title "skylobby"
2 | :author "skynet-gh"
3 | :description "Docs and blog for skylobby project"
4 | :site-url "https://skynet-gh.github.io/skylobby/"
5 | :post-root "posts"
6 | :page-root "pages"
7 | :public-dest "public"
8 | :blog-prefix "/skylobby"
9 | :rss-name "feed.xml"
10 | :rss-filters ["cryogen"]
11 | :recent-posts 3
12 | :post-date-format "yyyy-MM-dd"
13 | :archive-group-format "yyyy MMMM"
14 | :sass-src []
15 | :sass-path "sass.bat"
16 | :theme "blue"
17 | :resources ["img"]
18 | :keep-files [".git"]
19 | :disqus? false
20 | :disqus-shortname ""
21 | :ignored-files [#"\.#.*" #".*\.swp$"]
22 | :previews? false
23 | :posts-per-page 5
24 | :blocks-per-preview 2
25 | :clean-urls :trailing-slash
26 | :collapse-subdirs? false
27 | :hide-future-posts? true
28 | :klipse {}
29 | :description-include-elements #{:p :h1 :h2 :h3 :h4 :h5 :h6}
30 | :debug? false}
31 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/spring_options_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.spring-options-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.spring-options :as fx.spring-options]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest split-by
12 | (is (= []
13 | (fx.spring-options/split-by (constantly false) [])))
14 | (is (= [[:x :y :y :y]
15 | [:x :y :y]
16 | [:x :y]
17 | [:x :y :y]]
18 | (fx.spring-options/split-by #{:x} [:x :y :y :y :x :y :y :x :y :x :y :y]))))
19 |
20 | (deftest modoptions-table
21 | (is (map?
22 | (fx.spring-options/modoptions-table {:fx/context (fx/create-context nil)})))
23 | (is (map?
24 | (fx.spring-options/modoptions-table
25 | {:fx/context
26 | (fx/create-context
27 | {:modoptions
28 | [[:1 {:type "section"}]
29 | [:2 {:type "number"}]
30 | [:2 {:type "list"}]]})}))))
31 |
32 | (deftest modoptions-view
33 | (is (map?
34 | (fx.spring-options/modoptions-view {:fx/context (fx/create-context nil)})))
35 | (is (map?
36 | (fx.spring-options/modoptions-view
37 | {:fx/context
38 | (fx/create-context
39 | {:modoptions
40 | [[:1 {:type "section"}]
41 | [:2 {:type "number"}]
42 | [:2 {:type "list"}]]})}))))
43 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/client/message.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.client.message
2 | (:refer-clojure :exclude [send])
3 | (:require
4 | [clojure.string :as string]
5 | [manifold.stream :as s]
6 | [skylobby.util :as u]
7 | [taoensso.timbre :as log]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (defn send
14 | ([state-atom client-data message]
15 | (send state-atom client-data message nil))
16 | ([state-atom client-data message {:keys [log-message] :or {log-message message}}]
17 | (if-let [client (:client client-data)]
18 | (let [server-key (u/server-key client-data)]
19 | (log/info (str "[" server-key "] > '" log-message "'"))
20 | @(s/put! client (str message "\n"))
21 | (let [k (-> message
22 | (string/split #"\s")
23 | first)]
24 | (swap! state-atom
25 | (fn [state]
26 | (cond-> ((u/append-console-log-fn server-key :client log-message) state)
27 | (= "PING" k)
28 | (assoc-in [:by-server server-key :last-ping] (u/curr-millis))
29 | (= "MYBATTLESTATUS" k)
30 | (assoc-in
31 | [:by-server server-key :expecting-responses k]
32 | {:sent-message message
33 | :sent-millis (u/curr-millis)}))))))
34 | (log/error (ex-info "No client to send message" {:message log-message})))))
35 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/chat.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.chat
2 | (:require
3 | [clojure.string :as string]))
4 |
5 |
6 | (set! *warn-on-reflection* true)
7 |
8 |
9 | (defn ignore-users-set [ignore-users]
10 | (->> ignore-users
11 | (filter second)
12 | (map first)
13 | set))
14 |
15 | (defn hide-spads-set [hide-spads-messages]
16 | (->> hide-spads-messages
17 | (filter second)
18 | (map first)
19 | set))
20 |
21 | (defn visible-message?
22 | [{:keys [
23 | hide-barmanager-messages
24 | hide-joinas-spec
25 | hide-spads-set
26 | hide-vote-messages
27 | ignore-users-set]}
28 | {:keys [message-type relay spads text username vote]}]
29 | (not
30 | (or (and
31 | username
32 | (contains? ignore-users-set username))
33 | (and (= "Coordinator" username)
34 | (string/starts-with? text "skylobby"))
35 | (and
36 | (:on-behalf-of relay)
37 | (contains? ignore-users-set (:on-behalf-of relay)))
38 | (contains? hide-spads-set (:spads-message-type spads))
39 | (and hide-vote-messages
40 | (:vote vote))
41 | (and hide-joinas-spec
42 | (= "joinas spec"
43 | (:command vote)))
44 | (and hide-barmanager-messages
45 | (and (= :ex message-type)
46 | text
47 | (string/starts-with? text "* BarManager|"))))))
48 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
28 |
29 |
30 |
31 |
32 |
33 |
404
34 | Error ! Page Not Found
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
28 |
29 |
30 |
31 |
32 |
33 |
404
34 | Error ! Page Not Found
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
28 |
29 |
30 |
31 |
32 |
33 |
404
34 | Error ! Page Not Found
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/css/_variables.scss:
--------------------------------------------------------------------------------
1 | // Colors
2 |
3 | $black: #000;
4 | $red: #A71E2E;
5 | $green: #00D400;
6 | $purple: #522158;
7 | $very-dark-grey: #111;
8 | $dark-grey: #444;
9 | $grey: #808080;
10 | $light-grey: #ccc;
11 | $very-light-grey: #fbfbfb;
12 | $white: #fff;
13 |
14 | $base-color: $purple;
15 | $base-font-color: $very-dark-grey;
16 | $body-bgcolor: $very-light-grey;
17 |
18 | // Fonts
19 | $font-weight-light: 300;
20 | $font-weight-normal: 400;
21 | $font-weight-heavy: 600;
22 | $font-weight-header: 700;
23 | $default-font-weight: $font-weight-normal;
24 |
25 | $default-font-size: 16px;
26 | $default-line-height: 1.25;
27 | $button-font-size: 14px;
28 |
29 |
30 |
31 | $default-font-family: Oxygen, Tahoma, Verdana, Helvetica, Arial, sans-serif;
32 | $wide-font-family: Montserrat, sans-serif;
33 | $mono-font-family: Inconsolata, Consolas, "Deja Vu Sans Mono", "Bitstream Vera Sans Mono", "Droid Sans Mono", "Andale Mono", Anonymous, "Monaco", monospaced;
34 |
35 | // Borders
36 | $default-border-color: $base-color;
37 | $default-border-width: 2px;
38 | $default-border-style: solid;
39 | $default-border: $default-border-width $default-border-style $default-border-color;
40 | $default-border-radius: 2px;
41 |
42 | // Spacing
43 | $default-gutter: 20px;
44 | $sidebar-width: 220px;
45 |
46 | // Media
47 | // $tablet-breakpoint: 768px;
48 | // $mobile-breakpoint: 480px;
49 | $tablet-breakpoint: 900px;
50 | $mobile-breakpoint: 700px;
51 |
52 | // Effects
53 | $default-opacity: 0.85;
54 |
--------------------------------------------------------------------------------
/dev/clj/native/native_image.clj:
--------------------------------------------------------------------------------
1 | (ns native-image
2 | (:require
3 | [clojure.java.io :as io]
4 | [clojure.pprint :refer [pprint]]
5 | [clojure.tools.namespace.repl :refer [disable-unload! disable-reload!]]
6 | clj.native-image
7 | [clojure.tools.namespace.find :refer [find-namespaces-in-dir]]))
8 |
9 |
10 | (disable-unload!)
11 | (disable-reload!)
12 |
13 |
14 | ; adapted from https://github.com/taylorwood/clj.native-image/blob/master/src/clj/native_image.clj
15 | ; mostly just to put classpath in a file since it's too big for a command on Windows
16 |
17 |
18 | (defn build [main-ns opts]
19 | (let [nat-image-path (clj.native-image/native-image-bin-path)
20 | deps-map (clj.native-image/merged-deps)
21 | namespaces (mapcat (comp find-namespaces-in-dir io/file) (:paths deps-map))]
22 | (clj.native-image/prep-compile-path)
23 | (doseq [ns (distinct (cons main-ns namespaces))]
24 | (println "Compiling" ns)
25 | (compile (symbol ns)))
26 | (let [cp (clj.native-image/native-image-classpath)]
27 | (spit "native-image-args" (str "-cp " cp)))
28 | (let [args (concat
29 | ["@native-image-args"]
30 | opts)]
31 | (println "Running native-image with options" (with-out-str (pprint args)))
32 | (System/exit
33 | (clj.native-image/exec-native-image
34 | nat-image-path
35 | args
36 | nil
37 | main-ns)))))
38 |
39 | (defn -main [main-ns & args]
40 | (try
41 | (build main-ns args)
42 | (finally
43 | (shutdown-agents))))
44 |
--------------------------------------------------------------------------------
/test/clj/skylobby/client/gloss_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.client.gloss-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | [skylobby.client.gloss :as cu]))
5 |
6 |
7 | (deftest decode-client-status
8 | (is (= {:bot false,
9 | :access false,
10 | :rank 0,
11 | :away false,
12 | :ingame false}
13 | (cu/decode-client-status "0")))
14 | (is (= {:bot false,
15 | :access false,
16 | :rank 0,
17 | :away false,
18 | :ingame true}
19 | (cu/decode-client-status "1")))
20 | (is (= {:bot false,
21 | :access false,
22 | :rank 2,
23 | :away false,
24 | :ingame false}
25 | (cu/decode-client-status "8")))
26 | (is (= {:bot true,
27 | :access false,
28 | :rank 0,
29 | :away false,
30 | :ingame false}
31 | (cu/decode-client-status "64"))))
32 |
33 |
34 |
35 | (deftest decode-battle-status
36 | (is (= {:ready false,
37 | :ally 0,
38 | :handicap 0,
39 | :mode true,
40 | :sync 2,
41 | :id 0,
42 | :side 0}
43 | (cu/decode-battle-status "8389632"))))
44 |
45 | (deftest encode-battle-status
46 | (let [encoded (cu/encode-battle-status
47 | {:ready false,
48 | :ally 0,
49 | :handicap 0,
50 | :mode true,
51 | :sync 2,
52 | :id 0,
53 | :side 0})]
54 | (is (= "8389632"
55 | encoded))))
56 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/post.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{post.title}}{% endblock %}
3 | {% block meta %}
4 |
5 | {% if post.description %}
6 |
7 | {% comment %} OpenGraph tags {% endcomment %}
8 |
9 | {% endif %}
10 |
11 |
12 |
13 | {% endblock %}
14 | {% block content %}
15 |
16 | {% include "/html/post-content.html" %}
17 |
18 | {% with prev=post.prev next=post.next%}
19 | {% include "/html/prev-next.html" %}
20 | {% endwith %}
21 |
22 | {% if disqus-shortname %}
23 |
24 |
35 | {% endif %}
36 |
37 |
38 |
39 | {% endblock %}
40 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/battle.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.battle
2 | "Utilities for processing battle data.")
3 |
4 |
5 | (set! *warn-on-reflection* true)
6 |
7 |
8 | (defn battle-players-and-bots-users
9 | "Returns the sequence of all players and bots for a battle."
10 | [{:keys [battle users]}]
11 | (concat
12 | (mapv
13 | (fn [[k v]] (assoc v :username k :user (get users k)))
14 | (:users battle))
15 | (mapv
16 | (fn [[k v]]
17 | (assoc v
18 | :bot-name k
19 | :user {:client-status {:bot true}}))
20 | (:bots battle))))
21 |
22 | (defn battle-players-and-bots
23 | "Returns the sequence of all players and bots for a battle."
24 | [battle]
25 | (when battle
26 | (->> (mapcat battle [:users :bots])
27 | (mapv second))))
28 |
29 |
30 | (defn- first-avail [n-set]
31 | (loop [i 0]
32 | (if (or (contains? n-set i)
33 | (contains? n-set (str i)))
34 | (recur (inc i))
35 | i)))
36 |
37 | (defn available-team-id [battle]
38 | (let [ids (->> battle
39 | battle-players-and-bots
40 | (filter (comp :mode :battle-status)) ; remove spectators
41 | (map (comp :id :battle-status))
42 | set)]
43 | (first-avail ids)))
44 |
45 | (defn available-ally [battle]
46 | (let [allies (->> battle
47 | battle-players-and-bots
48 | (filter (comp :mode :battle-status)) ; remove spectators
49 | (map (comp :ally :battle-status))
50 | set)]
51 | (first-avail allies)))
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # skylobby [](https://github.com/skynet-gh/skylobby/actions/workflows/test.yml) [](LICENSE)
2 |
3 | A [Spring RTS](https://springrts.com/) lobby for [uberserver](https://github.com/spring/uberserver).
4 |
5 | ## Usage
6 |
7 | Install instructions and basic usage can be found in the [User Guide](https://github.com/skynet-gh/skylobby/wiki/User-Guide).
8 |
9 | Feel free to open an [issue](https://github.com/skynet-gh/skylobby/issues) if you find a bug or have a feature request.
10 |
11 | ## Dev
12 |
13 | Below are instructions on how to build and contribute to skylobby.
14 |
15 | You will need [Java 11 or higher](https://adoptium.net/) and the [Clojure CLI tools](https://clojure.org/guides/getting_started#_clojure_installer_and_cli_tools).
16 |
17 | ### REPL
18 |
19 | Runs an interactive compiler as well as the UI. If you make a change to something in `src/clj` it will trigger a recompile and re-render the UI from the running state.
20 |
21 | You will also need to install `rlwrap`. Run:
22 |
23 | ```bash
24 | clj -M:nrepl
25 | ```
26 |
27 | Logs are written to `repl.log`.
28 |
29 | ### Jar
30 |
31 | To build an executable jar file:
32 |
33 | ```bash
34 | clojure -M:uberjar
35 | ```
36 |
37 | And then run it with:
38 |
39 | ```bash
40 | java -jar target/skylobby.jar
41 | ```
42 |
43 | To build an installer, then run `jpackage` for your platform, for example on Windows
44 |
45 | ```bash
46 | jpackage @jpackage/common @jpackage/windows
47 | ```
48 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/maps_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.maps-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fs :as fs]
6 | [skylobby.fx.maps :as fx.maps]))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (deftest maps-view
13 | (is (map?
14 | (fx.maps/maps-view-impl
15 | {:fx/context (fx/create-context nil)}))))
16 |
17 |
18 | (deftest maps-window
19 | (is (map?
20 | (fx.maps/maps-window
21 | {:fx/context (fx/create-context nil)
22 | :screen-bounds {}})))
23 | (let [f (fs/file ".")]
24 | (is (map?
25 | (fx.maps/maps-window
26 | {:fx/context (fx/create-context {:show-maps true
27 | :spring-isolation-dir f
28 | :by-spring-root {(fs/canonical-path f) {:maps [{:map-name "map1"}
29 | {:map-name "map2"}]}}})
30 | :screen-bounds {}})))
31 | (is (map?
32 | (fx.maps/maps-window
33 | {:fx/context (fx/create-context {:show-maps true
34 | :spring-isolation-dir f
35 | :filter-maps-name "map1"
36 | :by-spring-root {(fs/canonical-path f) {:maps [{:map-name "map1"}
37 | {:map-name "map2"}]}}})
38 | :screen-bounds {}})))))
39 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/html/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
47 |
48 |
49 |
50 |
51 |
52 | Emptiness - 404
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/clj/skylobby/discord.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.discord
2 | (:require
3 | [cheshire.core :as json]
4 | [clj-http.client :as http]
5 | [clojure.string :as string]
6 | [skylobby.util :as u]
7 | [taoensso.timbre :as log]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (def base-url "https://discord.com/api/webhooks/")
14 |
15 | (def cooldown 180000) ; 3 minutes
16 |
17 | (def tokens
18 | {"898249621527220235" "czlXYXJqSlpEY1VINU1UenpjMVpFNGJ1cGVBV1N5XzBXbXpPR2Z2M3pwQmJKOWdzbTdNbHFGYlJoMXJ6b296Y0x0Q0Y="})
19 |
20 |
21 | (defn channel-to-promote [{:keys [mod-name]}]
22 | (when (and mod-name
23 | (or
24 | (string/starts-with? mod-name "Balanced Annihilation")
25 | (string/starts-with? mod-name "Metal Factions")
26 | (string/starts-with? mod-name "Tech Annihilation")))
27 | "898249621527220235"))
28 |
29 | (defn promote-battle [channel-id {:keys [battle-title map-name mod-name team-counts]}]
30 | (let [
31 | url (str base-url channel-id "/" (u/base64-decode (get tokens channel-id)))
32 | total-players (reduce (fnil + 0 0) 0 (flatten team-counts))
33 | body {:content (str "**" total-players " players** in " battle-title "\n"
34 | "**" mod-name "** on **" map-name "**")
35 | :username "skylobby"}
36 | _ (log/info "Posting Discord promotion to" url ":" body)
37 | response
38 | (http/post url
39 | {:body (json/generate-string body)
40 | :content-type :json
41 | :accept :json
42 | :as :json})]
43 | (log/info "Response from Discord:" (:body response))))
44 |
--------------------------------------------------------------------------------
/src/clj/spring_lobby/spring/uikeys.clj:
--------------------------------------------------------------------------------
1 | (ns spring-lobby.spring.uikeys
2 | (:require
3 | [clojail.core :as clojail]
4 | [clojure.java.io :as io]
5 | [clojure.string :as string]
6 | [instaparse.core :as instaparse]
7 | [taoensso.timbre :as log]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (def uikeys-grammar
14 | (instaparse/parser
15 | "uikeys = line*
16 | = (bind | notbind | #'\\s*')
17 | bind = <'bind'> <#'\\s+'> #'[^\\s]+' <#'\\s+'> #'[^/\\r\\n]+' comment?
18 | notbind = !'bind' #'\\w+' #'\\s+' #'.*'
19 | comment = <'//'> #'.*'"
20 | :auto-whitespace :standard))
21 |
22 | (defn postprocess [parsed-uikeys]
23 | (->> parsed-uikeys
24 | (filter coll?)
25 | (filter (comp #{:bind} first))
26 | (map
27 | (fn [[_kind key-combo action [_comment comment-str]]]
28 | {:bind-key key-combo
29 | :bind-action (string/trim action)
30 | :bind-comment comment-str}))
31 | (filter some?)))
32 |
33 |
34 | (defn parse-uikeys
35 | ([]
36 | (parse-uikeys (slurp (io/resource "uikeys.tmp"))))
37 | ([uikeys-raw]
38 | (clojail/thunk-timeout
39 | #(let [parsed (instaparse/parse uikeys-grammar uikeys-raw)]
40 | (if (instaparse/failure? parsed)
41 | (do
42 | (log/debug parsed)
43 | (throw (ex-info "Failed to parse" {:uikeys-pr-str (pr-str uikeys-raw)})))
44 | (postprocess parsed)))
45 | 2000)))
46 |
47 | (defn parse-bind-keys [bind-keys-str]
48 | (let [combos (string/split bind-keys-str #"(? parameters :path :server-url)
24 | username (-> parameters :query :username)
25 | server-key (u/get-server-key server-url username)
26 | battle (listen [:skylobby/battle server-key])
27 | route-names (concat
28 | (when battle
29 | [:skylobby/room])
30 | [:skylobby/battles :skylobby/channels :skylobby/console])
31 | battle-title (str "Battle: " (listen [:skylobby/battle-title server-key]))]
32 | [:div {:class "flex justify-center"}
33 | (for [route-name route-names]
34 | ^{:key route-name}
35 | [:div {:class "pa3"}
36 | [:a
37 | {:class (str css/header-class " "
38 | (if (or (= route-name (-> current-route :data :name))
39 | (and (= :skylobby/chat route-name)
40 | (= :skylobby/channels (-> current-route :data :name))))
41 | "gold"
42 | "gray"))
43 | :href (u/href route-name {:server-url server-url} {:username username})}
44 | (or (get server-route-names route-name)
45 | battle-title)]])]))
46 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Unit test
2 | on:
3 | push:
4 | branches: [ master ]
5 | pull_request:
6 | branches: [ master ]
7 | workflow_dispatch:
8 | jobs:
9 | test:
10 | strategy:
11 | matrix:
12 | os: [ubuntu-latest, macos-latest, windows-latest]
13 | java: ['17', '21']
14 | fail-fast: false
15 | runs-on: ${{ matrix.os }}
16 | steps:
17 | - uses: actions/checkout@v4.1.1
18 | - uses: actions/setup-java@v4.0.0
19 | with:
20 | java-version: ${{ matrix.java }}
21 | distribution: 'adopt'
22 | - uses: DeLaGuardo/setup-clojure@12.1
23 | with:
24 | cli: latest
25 | github-token: ${{ secrets.GITHUB_TOKEN }}
26 | - uses: actions/cache@v3.3.2
27 | with:
28 | path: ~/.m2/repository
29 | key: ${{ runner.os }}-maven-${{ hashFiles('deps.edn') }}
30 | restore-keys: |
31 | ${{ runner.os }}-maven-
32 | - if: ${{ matrix.os != 'windows-latest' }}
33 | run: clojure -M:test:headless:runner
34 | shell: bash
35 | - if: ${{ matrix.os == 'windows-latest' }}
36 | run: clojure -M:test:headless:runner
37 | shell: powershell
38 | coverage:
39 | if: ${{ false }} # disable for now
40 | runs-on: ubuntu-22.04
41 | steps:
42 | - uses: actions/checkout@v4.1.1
43 | - uses: actions/setup-java@v4.0.0
44 | with:
45 | java-version: '21'
46 | distribution: 'adopt'
47 | - uses: DeLaGuardo/setup-clojure@12.1
48 | with:
49 | cli: latest
50 | github-token: ${{ secrets.GITHUB_TOKEN }}
51 | - run: clojure -M:coverage:headless
52 | - run: bash <(curl -s https://codecov.io/bash) -f target/coverage/codecov.json
53 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/html/post.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{post.title}}{% endblock %}
3 | {% block meta %}
4 |
5 | {% if post.description %}
6 |
7 | {% comment %} OpenGraph tags {% endcomment %}
8 |
9 | {% endif %}
10 |
11 |
12 |
13 | {% endblock %}
14 | {% block content %}
15 |
16 | {% include "/html/post-content.html" %}
17 |
25 |
26 | {% if disqus-shortname %}
27 |
28 |
39 | {% endif %}
40 |
41 |
42 |
43 | {% endblock %}
44 |
--------------------------------------------------------------------------------
/cryogen/themes/blue_centered/html/post.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{post.title}}{% endblock %}
3 | {% block meta %}
4 |
5 | {% if post.description %}
6 |
7 | {% comment %} OpenGraph tags {% endcomment %}
8 |
9 | {% endif %}
10 |
11 |
12 |
13 | {% endblock %}
14 | {% block content %}
15 |
16 | {% include "/html/post-content.html" %}
17 |
25 |
26 | {% if disqus-shortname %}
27 |
28 |
39 | {% endif %}
40 |
41 |
42 |
43 | {% endblock %}
44 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/html/post.html:
--------------------------------------------------------------------------------
1 | {% extends "/html/base.html" %}
2 | {%block subtitle %}: {{post.title}}{% endblock %}
3 | {% block meta %}
4 |
5 | {% if post.description %}
6 |
7 | {% comment %} OpenGraph tags {% endcomment %}
8 |
9 | {% endif %}
10 |
11 |
12 |
13 | {% endblock %}
14 | {% block content %}
15 |
16 | {% include "/html/post-content.html" %}
17 |
25 |
26 | {% if disqus-shortname %}
27 |
28 |
39 | {% endif %}
40 |
41 |
42 |
43 | {% endblock %}
44 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/lua.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.lua
2 | (:import
3 | (org.luaj.vm2 LuaValue)
4 | (org.luaj.vm2.lib.jse JsePlatform)))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (def mocks
11 | "VFS = {}
12 |
13 | function VFS.DirList(dir, fileType)
14 | return {}
15 | end
16 |
17 | function getfenv()
18 | local t = {}
19 | t[\"mapinfo\"] = {}
20 | return t
21 | end
22 |
23 | Spring = {}
24 |
25 | function Spring.Log(x, level, message)
26 | return {}
27 | end
28 |
29 | ")
30 |
31 |
32 | (defn table-to-map
33 | "Returns a map from the given lua table, with keys converted to keywowrds and inner table values
34 | converted to maps as well."
35 | [^LuaValue lv]
36 | (let [table (.checktable lv)]
37 | (loop [m {}
38 | prevk LuaValue/NIL]
39 | (let [kv (.next table prevk)
40 | k (.arg1 kv)
41 | v (.arg kv 2)]
42 | (if (.isnil k)
43 | m
44 | (recur
45 | (let [kk (keyword (.toString k))
46 | vs (cond
47 | (.istable v) (table-to-map v)
48 | :else
49 | (.toString v))]
50 | (assoc m kk vs))
51 | k))))))
52 |
53 | (defn read-mapinfo
54 | "Returns a map repsenting mapinfo from the given string representation of mapinfo.lua."
55 | [s]
56 | (let [globals (JsePlatform/standardGlobals)
57 | lua-chunk (.load globals (str mocks s))
58 | res (.call lua-chunk)]
59 | (table-to-map res)))
60 |
61 | (defn read-modinfo
62 | "Returns a map repsenting modinfo from the given string representation of modinfo.lua."
63 | [s]
64 | (let [globals (JsePlatform/standardGlobals)
65 | lua-chunk (.load globals (str mocks s))
66 | res (.call lua-chunk)]
67 | (table-to-map res)))
68 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/view/servers_nav.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.view.servers-nav
2 | (:require
3 | [re-frame.core :as rf]
4 | [skylobby.common.util :as cu]
5 | [skylobby.css :as css]
6 | [skylobby.util :as u]))
7 |
8 |
9 | (defn listen [query-v]
10 | @(rf/subscribe query-v))
11 |
12 | (defn servers-nav []
13 | (let [current-route (listen [:skylobby/current-route])
14 | {:keys [parameters]} current-route
15 | server-key (u/params-server-key parameters)]
16 | [:div
17 | [:div {:class "flex justify-center"}
18 | (let [route-name :skylobby/servers]
19 | ^{:key route-name}
20 | [:div
21 | {:class "pa3"}
22 | [:a
23 | {:class (str css/header-class " "
24 | (if (= route-name (-> current-route :data :name))
25 | "purple"
26 | "gray"))
27 | :href (u/href route-name)}
28 | "Servers"]])
29 | (for [{:keys [server-id server-url username]} (filter :server-id (listen [:skylobby/active-servers]))]
30 | (let [is-direct (cu/is-direct? server-id)]
31 | ^{:key (str server-id)}
32 | [:div
33 | {:class "pa3"}
34 | [:a
35 | {
36 | :class (str css/header-class " "
37 | (if (= server-id server-key)
38 | "purple"
39 | "gray"))
40 | :href (if is-direct
41 | (u/href :skylobby/direct-battle {:server-key server-id})
42 | (u/href :skylobby/battles {:server-url server-url} {:username username}))}
43 | (if is-direct
44 | (let [{:keys [server-type username hostname port]} server-id]
45 | (str (name server-type) " " username "@" hostname ":" port))
46 | server-id)]]))]]))
47 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | skylobby.fx))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (def screen-bounds
11 | {:min-x -2560.0
12 | :min-y 0.0
13 | :max-x 2560.0
14 | :max-y 1440.0
15 | :width 5120.0
16 | :height 1440.0})
17 |
18 |
19 | (deftest fitx
20 | (is (= 0
21 | (with-redefs [skylobby.fx/get-screen-bounds (constantly nil)]
22 | (skylobby.fx/fitx nil))))
23 | (is (= -128.0
24 | (with-redefs [skylobby.fx/get-screen-bounds (constantly screen-bounds)]
25 | (skylobby.fx/fitx nil))))
26 | (is (= -128.0
27 | (skylobby.fx/fitx screen-bounds))))
28 | (deftest fity
29 | (is (= 0
30 | (with-redefs [skylobby.fx/get-screen-bounds (constantly nil)]
31 | (skylobby.fx/fity nil))))
32 | (is (= 592.0
33 | (with-redefs [skylobby.fx/get-screen-bounds (constantly screen-bounds)]
34 | (skylobby.fx/fity nil))))
35 | (is (= 592.0
36 | (skylobby.fx/fity screen-bounds))))
37 | (deftest fitwidth
38 | (is (= 256
39 | (with-redefs [skylobby.fx/get-screen-bounds (constantly nil)]
40 | (skylobby.fx/fitwidth nil -10000))))
41 | (is (= 256
42 | (with-redefs [skylobby.fx/get-screen-bounds (constantly screen-bounds)]
43 | (skylobby.fx/fitwidth nil -10000))))
44 | (is (= 256
45 | (skylobby.fx/fitwidth screen-bounds -10000))))
46 | (deftest fitheight
47 | (is (= 256
48 | (with-redefs [skylobby.fx/get-screen-bounds (constantly nil)]
49 | (skylobby.fx/fitheight nil -10000))))
50 | (is (= 256
51 | (with-redefs [skylobby.fx/get-screen-bounds (constantly screen-bounds)]
52 | (skylobby.fx/fitheight nil -10000))))
53 | (is (= 256
54 | (skylobby.fx/fitheight screen-bounds -10000))))
55 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/css/_layout.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | body {
4 | display: flex;
5 | flex-flow: row nowrap;
6 | align-items: stretch;
7 | justify-content: space-between;
8 |
9 | @media (max-width: $mobile-breakpoint) {
10 | flex-flow: column nowrap;
11 | }
12 | }
13 |
14 | #sidebar {
15 | @media (min-width: $mobile-breakpoint) {
16 | flex: 0 0 auto;
17 | height: 100vh;
18 | }
19 | @media (max-width: $mobile-breakpoint) {
20 | flex: 1 0 auto;
21 | width: 100vw;
22 | }
23 | }
24 |
25 | #sidebar-links {
26 | display: flex;
27 | flex-flow: column nowrap;
28 | justify-content: space-between;
29 | align-items: stretch;
30 |
31 | @media (max-width: $mobile-breakpoint) {
32 | flex-flow: row nowrap;
33 | }
34 | }
35 |
36 | .post-header {
37 | h1 {
38 | margin-top: 0;
39 | }
40 |
41 | .byline {
42 | display: flex;
43 | justify-content: space-between;
44 | margin-bottom: 1.375rem;
45 |
46 | @media (max-width: $tablet-breakpoint) {
47 | margin-bottom: 1.375rem;
48 | }
49 |
50 | @media (max-width: $mobile-breakpoint) {
51 | margin-bottom: 1.25rem;
52 | }
53 | }
54 | }
55 |
56 | #main {
57 | flex: 1 1 0;
58 |
59 | @media (min-width: $mobile-breakpoint) {
60 | height: 100vh;
61 | overflow-y: scroll;
62 | }
63 | }
64 |
65 | #prev-next {
66 | display: flex;
67 | align-items: center;
68 | flex-flow: row nowrap;
69 | justify-content: space-between;
70 |
71 | .prev, .next {
72 | display: flex;
73 | align-items: center;
74 | flex-flow: row nowrap;
75 |
76 | flex: 1 1 50%;
77 | fill: currentColor;
78 | text-decoration: none;
79 |
80 | .icon {
81 | flex: 0 0 1em;
82 | height: 1em;
83 | width: 1em;
84 | }
85 |
86 | .nav-text {
87 | flex: 1 1 0;
88 | margin-left: 1em;
89 | margin-right: 1em;
90 | text-align: center;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/css/reset.css:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 License: none (public domain)
2 | Removed code from first reset list since it conflics with highlight.js.
3 | */
4 |
5 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
6 | a, abbr, acronym, address, big, cite, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend,
7 | table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | font-size: 100%;
12 | font: inherit;
13 | vertical-align: baseline;
14 | }
15 |
16 | /* HTML5 display-role reset for older browsers */
17 |
18 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
19 | display: block;
20 | }
21 |
22 | body {
23 | line-height: 1;
24 | }
25 |
26 | ol, ul {
27 | list-style: none;
28 | }
29 |
30 | blockquote, q {
31 | quotes: none;
32 | }
33 |
34 | blockquote:before, blockquote:after, q:before, q:after {
35 | content: '';
36 | content: none;
37 | }
38 |
39 | table {
40 | border-collapse: collapse;
41 | border-spacing: 0;
42 | }
43 |
44 | /* Clear Fix Styles */
45 |
46 | .clearfix:after {
47 | visibility: hidden;
48 | display: block;
49 | font-size: 0;
50 | content: " ";
51 | clear: both;
52 | height: 0;
53 | }
54 |
55 | .clearfix {
56 | display: inline-block;
57 | }
58 |
59 | /* start commented backslash hack \*/
60 | * html .clearfix {
61 | height: 1%;
62 | }
63 |
64 | .clearfix {
65 | display: block;
66 | }
67 |
68 | /* close commented backslash hack */
69 | {
70 | height: 1%
71 | ;
72 | }
73 |
74 | .clearfix {
75 | display: block;
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/dev/clj/jar/uberjar.clj:
--------------------------------------------------------------------------------
1 | (ns uberjar
2 | (:require
3 | [clojure.java.io :as io]
4 | [clojure.tools.build.api :as b]
5 | [skylobby.git :as git]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (def lib 'skylobby/skylobby)
12 | (def here (io/file "."))
13 | (def latest-git-id (git/latest-id here))
14 | (def git-tag (git/tag-or-latest-id here))
15 | (def version
16 | (if (= latest-git-id git-tag)
17 | (str "git:" (git/short-git-commit latest-git-id))
18 | git-tag))
19 | (def src-dirs ["src/clj" "graal/clj" "graal/cljc" "resources"])
20 | (def class-dir "target/classes")
21 | (def basis (b/create-basis {:project "deps.edn"
22 | :aliases [:headless]}))
23 | (def app-name (name lib))
24 | (def uber-file (format "target/%s.jar" app-name))
25 |
26 |
27 |
28 | (defn spit-version-resource []
29 | (println "Spitting version resource file")
30 | (spit (io/file "resources" (str app-name ".version")) version))
31 |
32 |
33 | (defn -main [& _args]
34 | (println "\nDeleting target\n")
35 | (b/delete {:path "target"})
36 | (spit-version-resource)
37 | (b/copy-dir {:src-dirs src-dirs
38 | :target-dir class-dir})
39 | (println "\nCompiling clj\n")
40 | (b/compile-clj {:basis basis
41 | :src-dirs src-dirs
42 | :class-dir class-dir
43 | :java-opts [
44 | "-Dtestfx.robot=glass"
45 | "-Dglass.platform=Monocle"
46 | "-Dmonocle.platform=Headless"
47 | "-Dprism.order=sw"]})
48 | (println "\nBuilding uberjar\n")
49 | (b/uber {:class-dir class-dir
50 | :uber-file uber-file
51 | :basis basis
52 | :main 'spring-lobby.main
53 | :manifest {"Build-Number" version}})
54 | (println "\nDeleting classes dir\n")
55 | (b/delete {:path "target/classes"})
56 | (println "\nExiting\n")
57 | (System/exit 0))
58 |
--------------------------------------------------------------------------------
/graal/cljc/skylobby/data.cljc:
--------------------------------------------------------------------------------
1 | (ns skylobby.data
2 | (:require
3 | [clojure.string :as string]))
4 |
5 |
6 | (defn filter-battles
7 | [battles {:keys [filter-battles
8 | hide-empty-battles
9 | hide-locked-battles
10 | hide-passworded-battles
11 | hide-running-battles
12 | users]}]
13 | (let [
14 | filter-battles (when (string? filter-battles)
15 | filter-battles)
16 | filter-lc (when-not (string/blank? filter-battles)
17 | (string/lower-case filter-battles))]
18 | (->> battles
19 | vals
20 | (filter :battle-title)
21 | (filter
22 | (fn [{:keys [battle-map battle-modname battle-title]}]
23 | (if filter-lc
24 | (or (and battle-map (string/includes? (string/lower-case battle-map) filter-lc))
25 | (and battle-modname (string/includes? (string/lower-case battle-modname) filter-lc))
26 | (string/includes? (string/lower-case battle-title) filter-lc))
27 | true)))
28 | (remove
29 | (fn [{:keys [battle-passworded]}]
30 | (if hide-passworded-battles
31 | (= "1" battle-passworded)
32 | false)))
33 | (remove
34 | (fn [{:keys [battle-locked]}]
35 | (if hide-locked-battles
36 | (= "1" battle-locked)
37 | false)))
38 | (remove
39 | (fn [{:keys [users]}]
40 | (if hide-empty-battles
41 | (boolean (<= (count users) 1)) ; TODO bot vs human hosts
42 | false)))
43 | (remove
44 | (fn [{:keys [host-username]}]
45 | (if hide-running-battles
46 | (boolean (get-in users [host-username :client-status :ingame]))
47 | false)))
48 | (sort-by (juxt (comp count :users) :battle-spectators))
49 | reverse
50 | doall)))
51 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/players_table_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.players-table-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.players-table :as fx.players-table]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest ai-options-window
12 | (is (map?
13 | (fx.players-table/ai-options-window
14 | {:fx/context (fx/create-context {})}))))
15 |
16 | (deftest player-context-menu
17 | (is (map?
18 | (fx.players-table/player-context-menu
19 | {:fx/context (fx/create-context {})}))))
20 |
21 | (deftest player-status-tooltip-label
22 | (is (map?
23 | (fx.players-table/player-status-tooltip-label
24 | {:fx/context (fx/create-context {})}))))
25 |
26 | (deftest player-status
27 | (is (map?
28 | (fx.players-table/player-status
29 | {:fx/context (fx/create-context {})}))))
30 |
31 | (deftest player-name-tooltip
32 | (is (map?
33 | (fx.players-table/player-name-tooltip
34 | {:fx/context (fx/create-context {})}))))
35 |
36 |
37 | (def fake-players
38 | [{}
39 | {:battle-status {:mode true
40 | :ally 0
41 | :id 0}}])
42 |
43 | (deftest players-table
44 | (is (map?
45 | (fx.players-table/players-table-impl
46 | {:fx/context
47 | (fx/create-context
48 | {
49 | :players-table-columns {:skill true
50 | :ally true
51 | :team true
52 | :color true
53 | :status true
54 | :spectator true
55 | :faction true
56 | :country true
57 | :bonus true}})
58 | :players fake-players}))))
59 |
60 |
61 | (deftest players-not-a-table
62 | (is (map?
63 | (fx.players-table/players-not-a-table
64 | {:fx/context
65 | (fx/create-context {})
66 | :players fake-players}))))
67 |
--------------------------------------------------------------------------------
/src/cljs/skylobby/util.cljs:
--------------------------------------------------------------------------------
1 | (ns skylobby.util
2 | (:require
3 | ["dayjs" :as dayjs]
4 | ["dayjs/plugin/utc" :as utc]
5 | [clojure.edn :as edn]
6 | [clojure.string :as string]
7 | [reitit.frontend.easy :as rfe]))
8 |
9 |
10 | (.extend dayjs utc)
11 |
12 |
13 | (defn get-server-key [server-url username]
14 | (str username "@" server-url))
15 |
16 | (defn params-server-key [parameters]
17 | (if-let [s (get-in parameters [:path :server-key])]
18 | (edn/read-string s)
19 | (let [
20 | server-url (-> parameters :path :server-url)
21 | username (-> parameters :query :username)]
22 | (get-server-key server-url username))))
23 |
24 |
25 | (defn href
26 | "Return relative url for given route. Url can be used in HTML links."
27 | ([k]
28 | (href k nil nil))
29 | ([k params]
30 | (href k params nil))
31 | ([k params query]
32 | (rfe/href k params query)))
33 |
34 |
35 | (defn time-diff
36 | ([start]
37 | (time-diff start (dayjs)))
38 | ([start end]
39 | (dayjs/utc
40 | (.diff
41 | (dayjs end)
42 | (dayjs start)
43 | "milliseconds"))))
44 |
45 | (defn format-hours
46 | [timestamp]
47 | (.format (dayjs timestamp) "HH:mm:ss"))
48 |
49 |
50 | (defn spring-color-to-web [spring-color]
51 | (let [i (cond
52 | (string? spring-color)
53 | (js/parseInt spring-color)
54 | (number? spring-color)
55 | (int spring-color)
56 | :else 0)
57 | ; https://stackoverflow.com/a/11866980
58 | b (bit-and i 0xFF)
59 | g (unsigned-bit-shift-right (bit-and i 0xFF00) 8)
60 | r (unsigned-bit-shift-right (bit-and i 0xFF0000) 16)]
61 | ; string colors reverse r and b
62 | (str "#" (.padStart (.toString b 16) 2 "0")
63 | (.padStart (.toString g 16) 2 "0")
64 | (.padStart (.toString r 16) 2 "0"))))
65 |
66 |
67 | (defn battle-channel-name [{:keys [battle-id channel-name]}]
68 | (or channel-name
69 | (str "__battle__" battle-id)))
70 |
71 | (defn battle-channel-name? [channel-name]
72 | (and channel-name
73 | (string/starts-with? channel-name "__battle__")))
74 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/git.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.git
2 | "Utils for working with git resources."
3 | (:require
4 | [clj-jgit.porcelain :as git]
5 | [clojure.string :as string])
6 | (:import
7 | (java.io File)
8 | (org.eclipse.jgit.api Git)
9 | (org.eclipse.jgit.lib ObjectId Ref Repository)
10 | (org.eclipse.jgit.revwalk RevCommit)))
11 |
12 |
13 | (set! *warn-on-reflection* true)
14 |
15 |
16 | (def ba-repo-url
17 | "https://github.com/Balanced-Annihilation/Balanced-Annihilation.git")
18 | (def bar-repo-url
19 | "https://github.com/beyond-all-reason/Beyond-All-Reason.git")
20 | (def known-mod-repos
21 | [ba-repo-url
22 | bar-repo-url])
23 |
24 | (defn- repo-latest-id [repo]
25 | (when-let [^RevCommit first-log (first (git/git-log repo))]
26 | (ObjectId/toString (:id first-log))))
27 |
28 | (defn latest-id [^File f]
29 | (with-open [repo (git/load-repo f)]
30 | (repo-latest-id repo)))
31 |
32 | (defn fetch [^File f]
33 | (with-open [repo (git/load-repo f)]
34 | (git/git-fetch repo)))
35 |
36 | (defn reset-hard [^File f commit-id]
37 | (with-open [repo (git/load-repo f)]
38 | (git/git-reset repo :ref commit-id :mode :hard)))
39 |
40 | (defn- repo-tag-list [^Git repo]
41 | (for [^Ref tag (.call (.tagList repo))]
42 | (let [tag-name (.getName tag)]
43 | {:tag-name tag-name
44 | :short-tag-name (when tag-name (Repository/shortenRefName tag-name))
45 | :object-id (ObjectId/toString (.getObjectId tag))})))
46 |
47 | (defn tag-list [^File f]
48 | (with-open [repo (git/load-repo f)]
49 | (repo-tag-list repo)))
50 |
51 | ; https://stackoverflow.com/a/14933815/984393
52 | (defn tag-or-latest-id
53 | "Returns the current tag, if any. If there is no tag, returns the commit id string."
54 | [^File f]
55 | (with-open [repo (git/load-repo f)]
56 | (when-let [latest-id (repo-latest-id repo)]
57 | (let [tag-names-by-id (->> repo
58 | repo-tag-list
59 | (map (juxt :object-id :short-tag-name))
60 | (into {}))]
61 | (or (get tag-names-by-id latest-id)
62 | latest-id)))))
63 |
64 | (defn short-git-commit [git-commit-id]
65 | (when-not (string/blank? git-commit-id)
66 | (subs git-commit-id 0 (min 7 (count git-commit-id)))))
67 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/server_tab.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.server-tab
2 | (:require
3 | [cljfx.api :as fx]
4 | skylobby.fx
5 | [skylobby.fx.battle :as fx.battle]
6 | [skylobby.fx.main-tabs :as fx.main-tabs]
7 | [taoensso.tufte :as tufte]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (defn- server-tab-impl
14 | [{:fx/keys [context]
15 | :keys [server-key]}]
16 | (let [battle-as-tab (fx/sub-val context :battle-as-tab)
17 | pop-out-battle (fx/sub-val context :pop-out-battle)
18 | battle (fx/sub-val context get-in [:by-server server-key :battle])
19 | in-battle (and (seq battle)
20 | (or (not (:battle-id battle))
21 | (not pop-out-battle)))
22 | show-battle-pane (and in-battle (not battle-as-tab))
23 | divider-positions (fx/sub-val context :divider-positions)
24 | divider-key :server-tab
25 | tabs {:fx/type fx.main-tabs/main-tab-view
26 | :v-box/vgrow :always
27 | :server-key server-key}]
28 | {:fx/type :v-box
29 | :style {:-fx-font-size 14}
30 | :alignment :top-left
31 | :children
32 | [
33 | (if show-battle-pane
34 | {:fx/type fx/ext-on-instance-lifecycle
35 | :v-box/vgrow :always
36 | :on-created (fn [^javafx.scene.control.SplitPane node]
37 | (skylobby.fx/add-divider-listener node divider-key))
38 | :desc
39 | {:fx/type :split-pane
40 | :orientation :vertical
41 | :divider-positions [(or (get divider-positions divider-key)
42 | 0.20)]
43 | :items
44 | [tabs
45 | (if (:battle-id battle)
46 | {:fx/type fx.battle/battle-view
47 | :server-key server-key}
48 | {:fx/type :h-box
49 | :alignment :top-left
50 | :children
51 | [{:fx/type :v-box
52 | :h-box/hgrow :always
53 | :children
54 | [{:fx/type :label
55 | :style {:-fx-font-size 20}
56 | :text "Waiting for battle details from server..."}]}]})]}}
57 | tabs)]}))
58 |
59 | (defn server-tab [state]
60 | (tufte/profile {:dynamic? true
61 | :id :skylobby/ui}
62 | (tufte/p :server-tab
63 | (server-tab-impl state))))
64 |
--------------------------------------------------------------------------------
/test/clj/skylobby/fx/battle_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battle-test
2 | (:require
3 | [cljfx.api :as fx]
4 | [clojure.test :refer [deftest is]]
5 | [skylobby.fx.battle :as fx.battle]))
6 |
7 |
8 | (set! *warn-on-reflection* true)
9 |
10 |
11 | (deftest sync-button
12 | (is (map?
13 | (fx.battle/sync-button
14 | {:fx/context (fx/create-context nil)}))))
15 |
16 |
17 | (deftest spring-debug-window
18 | (is (map?
19 | (fx.battle/spring-debug-window
20 | {:fx/context (fx/create-context nil)
21 | :screen-bounds {}}))))
22 |
23 |
24 | (deftest battle-buttons
25 | (is (map?
26 | (fx.battle/battle-buttons
27 | {:fx/context (fx/create-context nil)})))
28 | (is (map?
29 | (fx.battle/battle-buttons
30 | {:fx/context (fx/create-context nil)
31 | :server-key :local}))))
32 |
33 |
34 | (deftest battle-tabs
35 | (is (map?
36 | (fx.battle/battle-tabs
37 | {:fx/context (fx/create-context nil)}))))
38 |
39 |
40 | (deftest battle-votes-impl
41 | (is (map?
42 | (fx.battle/battle-votes-impl
43 | {:fx/context (fx/create-context nil)})))
44 | (is (map?
45 | (fx.battle/battle-votes-impl
46 | {:fx/context (fx/create-context {:show-vote-log true})})))
47 | (is (map?
48 | (fx.battle/battle-votes-impl
49 | {:fx/context (fx/create-context {:show-vote-log true
50 | :by-server {"server" {:battle {:battle-id "1"}
51 | :battles {"1" {:channel-name "channel"
52 | :host-username "host"}}
53 | :channels {"channel" {:messages [{:username "host"
54 | :message-type :ex
55 | :spads {:spads-message-type :called-vote
56 | :spads-parsed ["" "user" "vote"]}}]}}}}})
57 | :server-key "server"}))))
58 |
59 |
60 | (deftest battle-view
61 | (is (map?
62 | (fx.battle/battle-view
63 | {:fx/context (fx/create-context nil)}))))
64 |
--------------------------------------------------------------------------------
/dev/clj/user/repl.clj:
--------------------------------------------------------------------------------
1 | (ns repl
2 | (:require
3 | [cider.nrepl]
4 | [clojure.string :as string]
5 | [clojure.tools.cli :as cli]
6 | hashp.core
7 | [io.aviso.repl]
8 | [nrepl.cmdline]
9 | [reply.main]
10 | [taoensso.timbre :as timbre]
11 | [taoensso.timbre.appenders.community.rotor :as rotor]
12 | user))
13 |
14 |
15 | (set! *warn-on-reflection* true)
16 |
17 |
18 | (def ^:private dev-log-path "repl.log")
19 |
20 |
21 | (defn log-to-file []
22 | (println "Setting up log to" dev-log-path)
23 | (timbre/merge-config!
24 | {:min-level :info
25 | :appenders
26 | {:rotor (rotor/rotor-appender
27 | {:path dev-log-path
28 | :max-size 10000000
29 | :backlog 5})}}))
30 |
31 | (defn disable-print-log []
32 | (timbre/merge-config!
33 | {:appenders
34 | {:println {:enabled? false}}}))
35 |
36 |
37 | (def middleware
38 | [;'cider.nrepl/cider-middleware
39 | 'cider.nrepl/wrap-clojuredocs
40 | 'cider.nrepl/wrap-classpath
41 | 'cider.nrepl/wrap-complete
42 | 'cider.nrepl/wrap-debug
43 | 'cider.nrepl/wrap-format
44 | 'cider.nrepl/wrap-info
45 | 'cider.nrepl/wrap-inspect
46 | 'cider.nrepl/wrap-macroexpand
47 | 'cider.nrepl/wrap-ns
48 | 'cider.nrepl/wrap-spec
49 | 'cider.nrepl/wrap-profile
50 | 'cider.nrepl/wrap-resource
51 | ;'cider.nrepl/wrap-refresh TODO re-render
52 | 'cider.nrepl/wrap-stacktrace
53 | 'cider.nrepl/wrap-test
54 | 'cider.nrepl/wrap-trace
55 | 'cider.nrepl/wrap-out
56 | 'cider.nrepl/wrap-undef
57 | 'cider.nrepl/wrap-version])
58 |
59 | (def cli-options [])
60 |
61 | (defn -main [& args]
62 | (let [parsed (cli/parse-opts args cli-options)]
63 | (log-to-file)
64 | (disable-print-log)
65 | (future
66 | (nrepl.cmdline/-main
67 | "--middleware"
68 | (str "[" (string/join "," middleware) "]")
69 | ;"--interactive"
70 | "--color"))
71 | (user/init parsed)
72 | (loop []
73 | (when
74 | (try
75 | (println "Trying to start REPLy")
76 | (reply.main/launch-nrepl
77 | {:attach (slurp ".nrepl-port")
78 | :caught io.aviso.repl/pretty-pst
79 | :color true})
80 | false
81 | (catch Exception _e
82 | (println "Error connecting REPLy, sleeping")
83 | (Thread/sleep 500)
84 | true))
85 | (recur)))
86 | (System/exit 0)))
87 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/battles_window.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battles-window
2 | (:require
3 | [cljfx.api :as fx]
4 | skylobby.fx
5 | [skylobby.fx.battles-table :as fx.battles-table]
6 | [skylobby.util :as u]
7 | [taoensso.tufte :as tufte]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (def window-key :battles)
14 |
15 | (def battles-window-width 1600)
16 | (def battles-window-height 1000)
17 |
18 |
19 | (defn battles-window-impl
20 | [{:fx/keys [context]
21 | :keys [screen-bounds]}]
22 | (let [
23 | window-states (fx/sub-val context :window-states)
24 | show-battles-window (fx/sub-val context :show-battles-window)
25 | server-key (fx/sub-ctx context skylobby.fx/selected-tab-server-key-sub)
26 | client-data (fx/sub-val context get-in [:by-server server-key :client-data])
27 | show (and show-battles-window client-data)]
28 | {:fx/type :stage
29 | :showing show
30 | :title (str u/app-name " Battles " server-key)
31 | :icons skylobby.fx/icons
32 | :on-close-request {:event/type :spring-lobby/dissoc
33 | :key :show-battles-window}
34 | :x (skylobby.fx/fitx screen-bounds (get-in window-states [window-key :x]))
35 | :y (skylobby.fx/fity screen-bounds (get-in window-states [window-key :y]))
36 | :width (skylobby.fx/fitwidth screen-bounds (get-in window-states [window-key :width]) battles-window-width)
37 | :height (skylobby.fx/fitheight screen-bounds (get-in window-states [window-key :height]) battles-window-height)
38 | :on-width-changed (partial skylobby.fx/window-changed window-key :width)
39 | :on-height-changed (partial skylobby.fx/window-changed window-key :height)
40 | :on-x-changed (partial skylobby.fx/window-changed window-key :x)
41 | :on-y-changed (partial skylobby.fx/window-changed window-key :y)
42 | :scene
43 | {:fx/type :scene
44 | :stylesheets (fx/sub-ctx context skylobby.fx/stylesheet-urls-sub)
45 | :root
46 | (if show
47 | {:fx/type fx.battles-table/battles-table
48 | :v-box/vgrow :always
49 | :server-key (u/server-key client-data)}
50 | {:fx/type :pane
51 | :pref-width battles-window-width
52 | :pref-height battles-window-height})}}))
53 |
54 | (defn battles-window-view [state]
55 | (tufte/profile {:dynamic? true
56 | :id :skylobby/ui}
57 | (tufte/p :battles-window
58 | (battles-window-impl state))))
59 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/task.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.task
2 | (:require
3 | [taoensso.timbre :as log]))
4 |
5 |
6 | (set! *warn-on-reflection* true)
7 |
8 |
9 | (def index-tasks
10 | #{:spring-lobby/refresh-engines
11 | :spring-lobby/refresh-mods
12 | :spring-lobby/refresh-maps})
13 |
14 | (def resource-tasks
15 | #{
16 | :spring-lobby/map-details
17 | :spring-lobby/mod-details
18 | :spring-lobby/update-cached-minimaps})
19 |
20 | (def download-tasks
21 | #{
22 | :spring-lobby/download-and-extract
23 | :spring-lobby/download-springfiles
24 | :spring-lobby/extract-7z
25 | :spring-lobby/import
26 | :spring-lobby/http-downloadable})
27 |
28 | (def rapid-tasks
29 | #{
30 | :spring-lobby/rapid-download
31 | :spring-lobby/update-rapid
32 | :spring-lobby/update-rapid-packages
33 | :spring-lobby/delete-corrupt-rapid})
34 |
35 | (def task-kinds
36 | [:spring-lobby/index-task
37 | :spring-lobby/resource-task
38 | :spring-lobby/download-task
39 | :spring-lobby/rapid-task
40 | :spring-lobby/other-task])
41 |
42 | (defn task-kind [{:spring-lobby/keys [task-type]}]
43 | (cond
44 | (contains? index-tasks task-type) :spring-lobby/index-task
45 | (contains? resource-tasks task-type) :spring-lobby/resource-task
46 | (contains? download-tasks task-type) :spring-lobby/download-task
47 | (contains? rapid-tasks task-type) :spring-lobby/rapid-task
48 | :else :spring-lobby/other-task))
49 |
50 | (defn add-task-state [state task]
51 | (if task
52 | (let [task-kind (task-kind task)]
53 | (log/info "Adding task" (pr-str task) "to" task-kind)
54 | (update-in state [:tasks-by-kind task-kind]
55 | (fn [tasks]
56 | (set (conj tasks task)))))
57 | (do
58 | (log/warn "Attempt to add nil task" task)
59 | state)))
60 |
61 | (defn add-task! [state-atom task]
62 | (swap! state-atom add-task-state task))
63 |
64 | (defn add-multiple-tasks [tasks-by-kind new-tasks]
65 | (reduce-kv
66 | (fn [m k new-tasks]
67 | (update m k (fn [existing]
68 | (set (concat new-tasks existing)))))
69 | tasks-by-kind
70 | (group-by task-kind new-tasks)))
71 |
72 | (defn add-tasks! [state-atom new-tasks]
73 | (log/info "Adding tasks" (pr-str new-tasks))
74 | (swap! state-atom update :tasks-by-kind add-multiple-tasks new-tasks))
75 |
76 |
77 | (defn all-tasks [{:keys [current-tasks tasks-by-kind]}]
78 | (->> tasks-by-kind
79 | (mapcat second)
80 | (concat (vals current-tasks))
81 | (filter some?)
82 | doall))
83 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/channels.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.channels
2 | (:require
3 | [cljfx.api :as fx]
4 | skylobby.fx
5 | [skylobby.util :as u]
6 | [taoensso.tufte :as tufte]))
7 |
8 |
9 | (set! *warn-on-reflection* true)
10 |
11 |
12 | (defn sorted-channels-sub [context server-key]
13 | (let [
14 | channels (fx/sub-val context get-in [:by-server server-key :channels])]
15 | (->> (vals channels)
16 | u/non-battle-channels
17 | (sort-by :channel-name String/CASE_INSENSITIVE_ORDER)
18 | doall)))
19 |
20 | (defn- channels-table-impl
21 | [{:fx/keys [context]
22 | :keys [server-key]}]
23 | (let [
24 | my-channels (fx/sub-val context get-in [:by-server server-key :my-channels])
25 | sorted-channels (fx/sub-ctx context sorted-channels-sub server-key)]
26 | {:fx/type :table-view
27 | :style {:-fx-min-width "240"}
28 | :column-resize-policy :constrained
29 | :items sorted-channels
30 | :columns
31 | [{:fx/type :table-column
32 | :text "Channel"
33 | :pref-width 100
34 | :cell-value-factory identity
35 | :cell-factory
36 | {:fx/cell-type :table-cell
37 | :describe (fn [i] {:text (str (:channel-name i))})}}
38 | {:fx/type :table-column
39 | :text "Users"
40 | :resizable false
41 | :pref-width 60
42 | :cell-value-factory identity
43 | :cell-factory
44 | {:fx/cell-type :table-cell
45 | :describe (fn [i] {:text (str (:user-count i))})}}
46 | {:fx/type :table-column
47 | :text "Actions"
48 | :resizable false
49 | :pref-width 80
50 | :cell-value-factory identity
51 | :cell-factory
52 | {:fx/cell-type :table-cell
53 | :describe
54 | (fn [{:keys [channel-name]}]
55 | {:text ""
56 | :graphic
57 | (merge
58 | {:fx/type :button}
59 | (if (contains? my-channels channel-name)
60 | {:text "Leave"
61 | :on-action {:event/type :spring-lobby/leave-channel
62 | :channel-name channel-name
63 | :server-key server-key}}
64 | {:text "Join"
65 | :on-action {:event/type :spring-lobby/join-channel
66 | :channel-name channel-name
67 | :server-key server-key}}))})}}]}))
68 |
69 | (defn channels-table [state]
70 | (tufte/profile {:dynamic? true
71 | :id :skylobby/ui}
72 | (tufte/p :channels-table
73 | (channels-table-impl state))))
74 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/battle_chat.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.battle-chat
2 | (:require
3 | [cljfx.api :as fx]
4 | skylobby.fx
5 | [skylobby.fx.channel :as fx.channel]
6 | [skylobby.util :as u]
7 | [taoensso.tufte :as tufte]))
8 |
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 |
13 | (def window-key :battle-chat)
14 |
15 | (def battle-chat-window-width 1600)
16 | (def battle-chat-window-height 1000)
17 |
18 |
19 | (defn battle-chat-window-impl
20 | [{:fx/keys [context]
21 | :keys [screen-bounds]}]
22 | (let [pop-out-chat (fx/sub-val context :pop-out-chat)
23 | window-states (fx/sub-val context :window-states)
24 | server-key (fx/sub-ctx context skylobby.fx/selected-tab-server-key-sub)
25 | battle-id (fx/sub-val context get-in [:by-server server-key :battle :battle-id])
26 | show-battle-chat-window (boolean (and pop-out-chat battle-id))]
27 | {:fx/type :stage
28 | :showing show-battle-chat-window
29 | :title (str u/app-name " Battle Chat")
30 | :icons skylobby.fx/icons
31 | :on-close-request {:event/type :spring-lobby/dissoc
32 | :key :pop-out-chat}
33 | :x (skylobby.fx/fitx screen-bounds (get-in window-states [window-key :x] 0))
34 | :y (skylobby.fx/fity screen-bounds (get-in window-states [window-key :y] 0))
35 | :width (skylobby.fx/fitwidth screen-bounds (get-in window-states [window-key :width]) battle-chat-window-width)
36 | :height (skylobby.fx/fitheight screen-bounds (get-in window-states [window-key :height]) battle-chat-window-height)
37 | :on-width-changed (partial skylobby.fx/window-changed window-key :width)
38 | :on-height-changed (partial skylobby.fx/window-changed window-key :height)
39 | :on-x-changed (partial skylobby.fx/window-changed window-key :x)
40 | :on-y-changed (partial skylobby.fx/window-changed window-key :y)
41 | :scene
42 | {:fx/type :scene
43 | :stylesheets (fx/sub-ctx context skylobby.fx/stylesheet-urls-sub)
44 | :root
45 | (if show-battle-chat-window
46 | {:fx/type fx.channel/channel-view
47 | :h-box/hgrow :always
48 | :channel-name (fx/sub-ctx context skylobby.fx/battle-channel-sub server-key)
49 | :hide-users true
50 | :server-key server-key}
51 | {:fx/type :pane
52 | :pref-width battle-chat-window-width
53 | :pref-height battle-chat-window-height})}}))
54 |
55 | (defn battle-chat-window [state]
56 | (tufte/profile {:dynamic? true
57 | :id :skylobby/ui}
58 | (tufte/p :battle-chat-window
59 | (battle-chat-window-impl state))))
60 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/css/typography.css:
--------------------------------------------------------------------------------
1 | .textleft {
2 | text-align: left;
3 | }
4 |
5 | .textcentre {
6 | text-align: center;
7 | }
8 |
9 | .textright {
10 | text-align: right;
11 | }
12 |
13 | p {
14 | margin: 0 0 20px 0;
15 | }
16 |
17 | strong, b {
18 | font-weight: 600;
19 | }
20 |
21 | em, i {
22 | font-style: italic;
23 | }
24 |
25 | h1 {
26 | margin: 0 0 10px 0;
27 | font-weight: 700;
28 | font-family: "Montserrat";
29 | text-transform: uppercase;
30 | font-size: 46px;
31 | line-height: 42px;
32 | letter-spacing: -1px;
33 | color: #111;
34 | }
35 |
36 | h2 {
37 | margin: 30px 0 15px 0;
38 | font-weight: 350;
39 | font-family: "Montserrat";
40 | text-transform: uppercase;
41 | font-size: 23px;
42 | line-height: 21px;
43 | letter-spacing: -0.5px;
44 | color: #111;
45 | }
46 |
47 | h3 {
48 | margin: 26px 0 13px 0;
49 | font-weight: 200;
50 | font-family: "Montserrat";
51 | font-size: 16px;
52 | line-height: 16px;
53 | letter-spacing: -0.4px;
54 | color: #111;
55 | }
56 |
57 | h4, h5, h6 {
58 | margin: 20px 0 10px 0;
59 | font-weight: 100;
60 | font-family: "Montserrat";
61 | font-size: 12px;
62 | line-height: 12px;
63 | color: #111;
64 | }
65 |
66 | ul {
67 | margin: 0 0 20px 35px;
68 | list-style-type: square;
69 | }
70 |
71 | ul li {
72 | padding: 0 0 0 2px;
73 | }
74 |
75 | ul ul {
76 | margin: 0 0 0 25px;
77 | }
78 |
79 | ol {
80 | margin: 0 0 20px 35px;
81 | list-style-type: decimal;
82 | }
83 |
84 | ol li {
85 | padding: 0 0 0 2px;
86 | }
87 |
88 | ol ol {
89 | margin: 0 0 0 25px;
90 | }
91 |
92 | hr {
93 | clear: both;
94 | float: left;
95 | width: 100%;
96 | padding: 0;
97 | margin: 30px 0 40px 0;
98 | border: none;
99 | border-top: 4px solid #A71E2E;
100 | text-align: center;
101 | }
102 |
103 | blockquote {
104 | background: #EEE;
105 | margin: 0 0 5px 0 !important;
106 | color: #555;
107 | border-left: 5px solid #A71E2E;
108 | padding: 15px;
109 | font-style: italic;
110 | }
111 |
112 | blockquote p {
113 | margin: 0;
114 | }
115 |
116 | blockquote p.author {
117 | text-align: right;
118 | font-size: 14px;
119 | letter-spacing: 2px;
120 | color: #999;
121 | }
122 |
123 | @media screen and (max-width: 768px) {
124 |
125 | .textcentre {
126 | text-align: left;
127 | }
128 |
129 | .textright {
130 | text-align: left;
131 | }
132 |
133 | }
134 |
135 |
136 |
--------------------------------------------------------------------------------
/native-res/linux/META-INF/native-image/skylobby/java/resource-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "resources":{
3 | "includes":[{
4 | "pattern":"\\QLinux-amd64/lib7-Zip-JBinding.so\\E"
5 | }, {
6 | "pattern":"\\QLinux-amd64/sevenzipjbinding-lib.properties\\E"
7 | }, {
8 | "pattern":"\\QMETA-INF/services/java.net.spi.InetAddressResolverProvider\\E"
9 | }, {
10 | "pattern":"\\QMETA-INF/services/java.sql.Driver\\E"
11 | }, {
12 | "pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
13 | }, {
14 | "pattern":"\\QMETA-INF/services/javax.xml.datatype.DatatypeFactory\\E"
15 | }, {
16 | "pattern":"\\Qmozilla/public-suffix-list.txt\\E"
17 | }, {
18 | "pattern":"\\Qnet/jpountz/util/linux/amd64/liblz4-java.so\\E"
19 | }, {
20 | "pattern":"\\Qorg/apache/http/client/version.properties\\E"
21 | }, {
22 | "pattern":"\\Qorg/h2/util/data.zip\\E"
23 | }, {
24 | "pattern":"\\Qorg/jsoup/nodes/entities-base.properties\\E"
25 | }, {
26 | "pattern":"\\Qorg/jsoup/nodes/entities-full.properties\\E"
27 | }, {
28 | "pattern":"\\Qpublic/css/tachyons.min.css\\E"
29 | }, {
30 | "pattern":"\\Qpublic/iconfont/material-icons.css\\E"
31 | }, {
32 | "pattern":"\\Qpublic/iconfont/material-icons.woff2\\E"
33 | }, {
34 | "pattern":"\\Qpublic/images/favicon.ico\\E"
35 | }, {
36 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.async.impl.channels.js.map\\E"
37 | }, {
38 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.async.impl.dispatch.js.map\\E"
39 | }, {
40 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.async.impl.ioc_helpers.js.map\\E"
41 | }, {
42 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.js.map\\E"
43 | }, {
44 | "pattern":"\\Qpublic/js/cljs-runtime/goog.async.nexttick.js.map\\E"
45 | }, {
46 | "pattern":"\\Qpublic/js/cljs-runtime/module$node_modules$react_dom$cjs$react_dom_development.js.map\\E"
47 | }, {
48 | "pattern":"\\Qpublic/js/cljs-runtime/skylobby.js.js.map\\E"
49 | }, {
50 | "pattern":"\\Qpublic/js/cljs-runtime/taoensso.sente.js.map\\E"
51 | }, {
52 | "pattern":"\\Qpublic/js/cljs-runtime/taoensso.timbre.appenders.core.js.map\\E"
53 | }, {
54 | "pattern":"\\Qpublic/js/cljs-runtime/taoensso.timbre.js.map\\E"
55 | }, {
56 | "pattern":"\\Qpublic/js/main.js\\E"
57 | }, {
58 | "pattern":"\\Qsevenzipjbinding-platforms.properties\\E"
59 | }, {
60 | "pattern":"\\Qskylobby.version\\E"
61 | }, {
62 | "pattern":"\\Qskylobby/util.clj\\E"
63 | }, {
64 | "pattern":"\\Qskylobby/util__init.class\\E"
65 | }, {
66 | "pattern":"java.base:\\Qsun/net/www/content-types.properties\\E"
67 | }]},
68 | "bundles":[]
69 | }
70 |
--------------------------------------------------------------------------------
/src/clj/spring_lobby/replays.clj:
--------------------------------------------------------------------------------
1 | (ns spring-lobby.replays
2 | (:require
3 | [cljfx.api :as fx]
4 | [skylobby.fs :as fs]
5 | skylobby.fx
6 | [skylobby.fx.replay :as fx.replay]
7 | [skylobby.fx.settings :as fx.settings]
8 | [skylobby.util :as u]
9 | spring-lobby
10 | [taoensso.timbre :as log])
11 | (:import
12 | (javafx.application Platform)
13 | (javafx.event Event))
14 | (:gen-class))
15 |
16 |
17 | (set! *warn-on-reflection* true)
18 |
19 |
20 | (def screen-bounds (skylobby.fx/get-screen-bounds))
21 |
22 |
23 | (defn replays-on-close-request
24 | [^Event e]
25 | (log/debug "Replays window close request" e)
26 | (System/exit 0)
27 | (.consume e))
28 |
29 | (defn root-view
30 | [_]
31 | {:fx/type fx/ext-many
32 | :desc
33 | [
34 | {:fx/type fx.replay/replays-window
35 | :on-close-request replays-on-close-request
36 | :screen-bounds screen-bounds
37 | :settings-button true
38 | :show true
39 | :title (str "skyreplays " u/app-version)}
40 | {:fx/type fx.settings/settings-window
41 | :screen-bounds screen-bounds}]})
42 |
43 |
44 | (defn create-renderer []
45 | (log/info "Creating renderer")
46 | (let [r (fx/create-renderer
47 | :middleware (comp
48 | fx/wrap-context-desc
49 | (fx/wrap-map-desc (fn [_] {:fx/type root-view})))
50 | :opts {:fx.opt/map-event-handler spring-lobby/event-handler
51 | :fx.opt/type->lifecycle #(or (fx/keyword->lifecycle %)
52 | (fx/fn->lifecycle-with-context %))})]
53 | (log/info "Mounting renderer")
54 | (fx/mount-renderer spring-lobby/*ui-state r)))
55 |
56 | (defn -main [& _args]
57 | (u/log-to-file (fs/canonical-path (fs/config-file (str u/app-name ".log"))))
58 | (let [before (u/curr-millis)]
59 | (log/info "Main start")
60 | (Platform/setImplicitExit true)
61 | (log/info "Set JavaFX implicit exit")
62 | (future
63 | (log/info "Start 7Zip init, async")
64 | (fs/init-7z!)
65 | (log/info "Finished 7Zip init"))
66 | (let [before-state (u/curr-millis)
67 | _ (log/info "Loading initial state")
68 | state (assoc (spring-lobby/initial-state) :show-replays true :standalone true)]
69 | (log/info "Loaded initial state in" (- (u/curr-millis) before-state) "ms")
70 | (reset! spring-lobby/*state state)
71 | (spring-lobby/add-ui-state-watcher spring-lobby/*state spring-lobby/*ui-state)
72 | (create-renderer))
73 | (spring-lobby/init-async spring-lobby/*state)
74 | (log/info "Main finished in" (- (u/curr-millis) before) "ms")))
75 |
--------------------------------------------------------------------------------
/cryogen/themes/nucleus/css/menu.css:
--------------------------------------------------------------------------------
1 | /** Menu Styles **/
2 |
3 | #menucont ul.menu {
4 | margin: 0;
5 | }
6 |
7 | #menucont ul.menu li {
8 | position: relative;
9 | float: left;
10 | width: 100%;
11 | list-style-type: none;
12 | padding: 0;
13 | }
14 |
15 | #menucont ul.menu li a {
16 | float: left;
17 | color: #FFF;
18 | width: 100%;
19 | padding: 10px 20px;
20 | margin: 0;
21 | font-weight: 300;
22 | text-transform: uppercase;
23 | line-height: 22px;
24 | text-decoration: none;
25 | letter-spacing: 2px;
26 | }
27 |
28 | #menucont ul.menu li a:hover {
29 | background: rgba(0, 0, 0, 0.2);
30 | }
31 |
32 | #menucont ul.menu li.active a,
33 | #menucont ul.menu li.active a:hover {
34 | background: rgba(0, 0, 0, 0.2);
35 | font-weight: 600;
36 | }
37 |
38 | #menucont .menutitle {
39 | display: none;
40 | }
41 |
42 | @media screen and (max-width: 480px) {
43 |
44 | #menucont .menu {
45 | display: none;
46 | margin: 0;
47 | }
48 |
49 | #menucont .menu.open {
50 | display: block;
51 | }
52 |
53 | #menucont ul.menu li {
54 | position: relative;
55 | float: none;
56 | }
57 |
58 | #menucont ul.menu li, #menucont ul.menu ul li {
59 | display: block;
60 | }
61 |
62 | #menucont ul.menu li a {
63 | width: 100%;
64 | display: inline-block;
65 | margin: 0;
66 | padding: 5px 0;
67 | text-indent: 0;
68 | line-height: 23px;
69 | color: rgba(255, 255, 255, 0.6);
70 | background: none;
71 | font-weight: 300;
72 | text-transform: uppercase;
73 | }
74 |
75 | #menucont ul.menu li.active a,
76 | #menucont ul.menu li.active a:hover {
77 | font-weight: 600;
78 | color: #FFF;
79 | background: none;
80 | }
81 |
82 | #menucont ul.menu li a:hover {
83 | color: #FFF;
84 | background: none;
85 | }
86 |
87 | #menucont ul.menu > li:last-child a {
88 | margin: 0 0 20px 0;
89 | }
90 |
91 | #menucont .menutitle {
92 | display: block;
93 | width: 100%;
94 | padding: 12px 42px 12px 0;
95 | display: block;
96 | cursor: pointer;
97 | text-align: left;
98 | color: #FFF;
99 | text-transform: uppercase;
100 | }
101 |
102 | #menucont .menutitle p {
103 | margin-bottom: 0;
104 | }
105 |
106 | #menucont .menutitle p strong {
107 | margin: 0 0 0 15px;
108 | font-size: 18px;
109 | font-weight: 300;
110 | letter-spacing: 2px;
111 | }
112 |
113 | #menucont .menutitle span {
114 | margin: 0;
115 | font-size: 20px;
116 | }
117 |
118 | }
119 |
120 |
--------------------------------------------------------------------------------
/native-res/windows/META-INF/native-image/skylobby/java/resource-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "resources":{
3 | "includes":[{
4 | "pattern":"\\QMETA-INF/services/java.net.spi.InetAddressResolverProvider\\E"
5 | }, {
6 | "pattern":"\\QMETA-INF/services/java.net.spi.URLStreamHandlerProvider\\E"
7 | }, {
8 | "pattern":"\\QMETA-INF/services/java.sql.Driver\\E"
9 | }, {
10 | "pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
11 | }, {
12 | "pattern":"\\QMETA-INF/services/javax.xml.datatype.DatatypeFactory\\E"
13 | }, {
14 | "pattern":"\\QWindows-amd64/lib7-Zip-JBinding.dll\\E"
15 | }, {
16 | "pattern":"\\QWindows-amd64/sevenzipjbinding-lib.properties\\E"
17 | }, {
18 | "pattern":"\\Qmozilla/public-suffix-list.txt\\E"
19 | }, {
20 | "pattern":"\\Qnet/jpountz/util/win32/amd64/liblz4-java.so\\E"
21 | }, {
22 | "pattern":"\\Qorg/apache/http/client/version.properties\\E"
23 | }, {
24 | "pattern":"\\Qorg/h2/util/data.zip\\E"
25 | }, {
26 | "pattern":"\\Qpublic/css/tachyons.min.css\\E"
27 | }, {
28 | "pattern":"\\Qpublic/iconfont/material-icons.css\\E"
29 | }, {
30 | "pattern":"\\Qpublic/iconfont/material-icons.woff2\\E"
31 | }, {
32 | "pattern":"\\Qpublic/images/favicon.ico\\E"
33 | }, {
34 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.async.impl.dispatch.js.map\\E"
35 | }, {
36 | "pattern":"\\Qpublic/js/cljs-runtime/cljs.core.js.map\\E"
37 | }, {
38 | "pattern":"\\Qpublic/js/cljs-runtime/goog.async.nexttick.js.map\\E"
39 | }, {
40 | "pattern":"\\Qpublic/js/cljs-runtime/module$node_modules$react$cjs$react_development.js.map\\E"
41 | }, {
42 | "pattern":"\\Qpublic/js/cljs-runtime/module$node_modules$react_dom$cjs$react_dom_development.js.map\\E"
43 | }, {
44 | "pattern":"\\Qpublic/js/cljs-runtime/re_frame.events.js.map\\E"
45 | }, {
46 | "pattern":"\\Qpublic/js/cljs-runtime/re_frame.fx.js.map\\E"
47 | }, {
48 | "pattern":"\\Qpublic/js/cljs-runtime/re_frame.interceptor.js.map\\E"
49 | }, {
50 | "pattern":"\\Qpublic/js/cljs-runtime/re_frame.router.js.map\\E"
51 | }, {
52 | "pattern":"\\Qpublic/js/cljs-runtime/reagent.impl.batching.js.map\\E"
53 | }, {
54 | "pattern":"\\Qpublic/js/cljs-runtime/reagent.ratom.js.map\\E"
55 | }, {
56 | "pattern":"\\Qpublic/js/cljs-runtime/shadow.cljs.devtools.client.shared.js.map\\E"
57 | }, {
58 | "pattern":"\\Qpublic/js/cljs-runtime/skylobby.js.js.map\\E"
59 | }, {
60 | "pattern":"\\Qpublic/js/cljs-runtime/taoensso.sente.js.map\\E"
61 | }, {
62 | "pattern":"\\Qpublic/js/cljs-runtime/taoensso.timbre.appenders.core.js.map\\E"
63 | }, {
64 | "pattern":"\\Qpublic/js/main.js\\E"
65 | }, {
66 | "pattern":"\\Qsevenzipjbinding-platforms.properties\\E"
67 | }, {
68 | "pattern":"\\Qskylobby.version\\E"
69 | }, {
70 | "pattern":"java.base:\\Qsun/net/www/content-types.properties\\E"
71 | }]},
72 | "bundles":[]
73 | }
74 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/client/gloss.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.client.gloss
2 | (:require
3 | [gloss.core :as gloss]
4 | [gloss.io :as gio]
5 | [manifold.stream :as s]
6 | [skylobby.util :as u])
7 | (:import
8 | (java.nio ByteBuffer)))
9 |
10 |
11 | (set! *warn-on-reflection* true)
12 |
13 |
14 | ; https://springrts.com/dl/LobbyProtocol/ProtocolDescription.html
15 | (defn protocol [encoding]
16 | (gloss/compile-frame
17 | (gloss/delimited-frame
18 | ["\n"]
19 | (gloss/string (or encoding u/default-client-encoding)))))
20 |
21 | (def client-status-protocol
22 | (gloss/compile-frame
23 | (gloss/bit-map
24 | :prefix 1
25 | :bot 1
26 | :access 1
27 | :rank 3
28 | :away 1
29 | :ingame 1)))
30 |
31 |
32 | (defn wrap-duplex-stream
33 | [protocol s]
34 | (let [out (s/stream)]
35 | (s/connect
36 | (s/map #(gio/encode protocol %) out)
37 | s)
38 | (s/splice
39 | out
40 | (gio/decode-stream s protocol))))
41 |
42 | ; https://springrts.com/dl/LobbyProtocol/ProtocolDescription.html#MYBATTLESTATUS:client
43 | (def default-battle-status
44 | {:ready true
45 | :ally 0
46 | :handicap 0
47 | :mode false
48 | :sync 2 ; unsynced
49 | :id 0
50 | :side 0})
51 |
52 | (def default-client-status-str "0")
53 |
54 |
55 | (def battle-status-protocol
56 | (gloss/compile-frame
57 | (gloss/bit-map
58 | :prefix 5
59 | :side 3
60 | :sync 2
61 | :pad 4
62 | :handicap 7
63 | :mode 1
64 | :ally 4
65 | :id 4
66 | :ready 1
67 | :suffix 1)))
68 |
69 |
70 | (defn decode-client-status [status-str]
71 | (dissoc
72 | (gio/decode client-status-protocol
73 | (ByteBuffer/wrap
74 | (.array
75 | (.put
76 | (ByteBuffer/allocate 1)
77 | (Byte/parseByte status-str)))))
78 | :prefix))
79 |
80 |
81 | (def default-client-status
82 | (decode-client-status default-client-status-str))
83 |
84 |
85 | (defn encode-client-status [client-status]
86 | (str
87 | (.get
88 | ^ByteBuffer
89 | (gio/to-byte-buffer
90 | (gio/encode client-status-protocol
91 | (assoc
92 | (merge default-client-status client-status)
93 | :prefix false)))
94 | 0)))
95 |
96 | (defn decode-battle-status [status-str]
97 | (dissoc
98 | (gio/decode battle-status-protocol
99 | (ByteBuffer/wrap
100 | (.array
101 | (.putInt
102 | (ByteBuffer/allocate (quot Integer/SIZE Byte/SIZE))
103 | (Integer/parseInt status-str)))))
104 | :prefix :pad :suffix))
105 |
106 | (defn encode-battle-status [battle-status]
107 | (str
108 | (.getInt
109 | ^ByteBuffer
110 | (gio/to-byte-buffer
111 | (gio/encode battle-status-protocol
112 | (assoc
113 | (merge default-battle-status battle-status)
114 | :prefix 0
115 | :pad 0
116 | :suffix 0))))))
117 |
--------------------------------------------------------------------------------
/src/clj/skylobby/fx/event/direct.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.fx.event.direct
2 | (:require
3 | [clojure.set :refer [rename-keys]]
4 | [skylobby.direct :as direct]
5 | [skylobby.direct.client :as direct.client]
6 | [taoensso.sente :as sente]
7 | [taoensso.timbre :as log]))
8 |
9 |
10 | (set! *warn-on-reflection* false)
11 |
12 |
13 | (defn add-methods
14 | [multifn state-atom] ; TODO need to move event handler out of spring-lobby ns
15 | (defmethod multifn ::host
16 | [params]
17 | (swap! state-atom assoc-in [:login-error :direct-host] nil)
18 | (future
19 | (try
20 | (direct/host-direct-connect state-atom (rename-keys params {:direct-connect-password :password
21 | :direct-connect-port :port
22 | :direct-connect-username :username}))
23 | (catch Exception e
24 | (log/error e "Error starting direct connect server")))))
25 | (defmethod multifn ::join
26 | [{:keys [direct-connect-ip direct-connect-port direct-connect-protocol direct-connect-username]}]
27 | (swap! state-atom assoc-in [:login-error :direct-client] nil)
28 | (future
29 | (try
30 | (let [server-key {:server-type :direct
31 | :protocol :skylobby
32 | :host false
33 | :hostname direct-connect-ip
34 | :port direct-connect-port
35 | :username direct-connect-username}
36 | ;; Serializtion format, must use same val for client + server:
37 | packer :edn
38 | {:keys [ch-recv] :as client}
39 | (sente/make-channel-socket-client!
40 | "/chsk"
41 | nil ; ?csrf-token
42 | {
43 | :host direct-connect-ip
44 | :port direct-connect-port
45 | :protcol (or direct-connect-protocol :http)
46 | :type :ws
47 | :packer packer
48 | :wrap-recv-evs? false})
49 | msg-handler (direct.client/event-msg-handler state-atom server-key)
50 | client-close-fn (sente/start-client-chsk-router! ch-recv msg-handler)
51 | client-close-fn (fn []
52 | ;(send-fn [::direct.client/close])
53 | (client-close-fn))
54 | data {:battle {:battle-id :direct
55 | :users {}}
56 | :battles {:direct {}}
57 | :client client
58 | :client-close-fn client-close-fn
59 | :username direct-connect-username}]
60 | (swap! state-atom
61 | (fn [state]
62 | (-> state
63 | (assoc-in [:by-server server-key] data)
64 | (assoc :selected-server-tab (str server-key))))))
65 | (catch Exception e
66 | (log/error e "Error joining direct connect"))))))
67 |
--------------------------------------------------------------------------------
/cryogen/themes/lotus/css/_menu.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | #menucont {
4 | #menu-checkbox {
5 | display: none;
6 | }
7 |
8 | .menutitle {
9 | display: none;
10 | }
11 |
12 | .menu {
13 | margin: 0;
14 | padding: 0;
15 |
16 | li {
17 | width: 100%;
18 | list-style-type: none;
19 | padding: 0;
20 |
21 | a {
22 | color: #FFF;
23 | width: 100%;
24 | margin: 0;
25 | font-weight: 300;
26 | text-transform: uppercase;
27 | line-height: 22px;
28 | text-decoration: none;
29 | letter-spacing: 2px;
30 | }
31 |
32 | &:hover {
33 | background: rgba(0, 0, 0, 0.2);
34 | }
35 |
36 | &.active {
37 | background: rgba(0, 0, 0, 0.2);
38 |
39 | a {
40 | font-weight: 600;
41 | }
42 | }
43 |
44 | .menu-item-text {
45 | padding: $default-gutter/2 $default-gutter;
46 | width: 100%;
47 | }
48 | }
49 | }
50 | }
51 |
52 | // From the awesome animate.css
53 | @keyframes fadeIn {
54 | from {
55 | opacity: 0;
56 | }
57 |
58 | to {
59 | opacity: 1;
60 | }
61 | }
62 |
63 | @media screen and (max-width: $mobile-breakpoint) {
64 |
65 | #menucont {
66 | #menu-checkbox {
67 | &:checked ~ .menu {
68 | display: block;
69 | margin-bottom: .5em;
70 | }
71 | }
72 |
73 | .menutitle {
74 | display: flex;
75 | align-items: center;
76 |
77 | padding: $default-gutter/2 $default-gutter;
78 | cursor: pointer;
79 | text-transform: uppercase;
80 | opacity: $default-opacity;
81 |
82 | .icon-menu {
83 | // color: currentColor;
84 | fill: currentColor;
85 |
86 | // margin: 0 0 0 2px;
87 | // font-size: $default-font-size * 1.2;
88 | height: $default-font-size;
89 | width: $default-font-size;
90 | }
91 |
92 | .menu-text {
93 | margin: 0 0 0 .8em;
94 | font-size: $default-font-size;
95 | font-weight: $font-weight-heavy;
96 | letter-spacing: 2px;
97 | line-height: 1;
98 | }
99 | }
100 |
101 | .menu {
102 | animation-name: fadeIn;
103 | animation-duration: 1s;
104 | animation-fill-mode: both;
105 |
106 | display: none;
107 |
108 | li {
109 | &.active {
110 | background: transparent;
111 |
112 | a, a:hover {
113 | font-weight: 600;
114 | color: #FFF;
115 | }
116 | }
117 |
118 | a {
119 | width: 100%;
120 | display: inline-block;
121 | margin: 0;
122 | line-height: 23px;
123 | color: rgba(255, 255, 255, 0.6);
124 | font-weight: 300;
125 | text-transform: uppercase;
126 | }
127 |
128 | .menu-item-text {
129 | padding: $default-gutter/4 $default-gutter;
130 | }
131 | }
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/test/clj/skylobby/spads_test.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.spads-test
2 | (:require
3 | [clojure.test :refer [deftest is]]
4 | [skylobby.spads :as spads]))
5 |
6 |
7 | (set! *warn-on-reflection* true)
8 |
9 |
10 | (deftest parse-spads-message
11 | (is (= nil
12 | (spads/parse-spads-message "")))
13 | (is (= {:spads-message-type :vote-progress,
14 | :spads-parsed ["Vote in progress: \"start\" [y:6/7, n:0/6] (29s remaining)"
15 | "start"
16 | "6"
17 | "7"
18 | "0"
19 | "6"
20 | ""
21 | "29s"],
22 | :text "* Vote in progress: \"start\" [y:6/7, n:0/6] (29s remaining)"}
23 | (spads/parse-spads-message "* Vote in progress: \"start\" [y:6/7, n:0/6] (29s remaining)")))
24 | (is (= {:spads-message-type :vote-progress,
25 | :spads-parsed ["Vote in progress: \"rehost\" [y:4/6(9), n:1/6(9), votes:5/9] (9s remaining)"
26 | "rehost"
27 | "4"
28 | "6(9)"
29 | "1"
30 | "6(9)"
31 | ", votes:5/9"
32 | "9s"],
33 | :text "* Vote in progress: \"rehost\" [y:4/6(9), n:1/6(9), votes:5/9] (9s remaining)"}
34 | (spads/parse-spads-message "* Vote in progress: \"rehost\" [y:4/6(9), n:1/6(9), votes:5/9] (9s remaining)")))
35 | (is (= {:spads-message-type :vote-progress,
36 | :spads-parsed ["Vote in progress: \"set map Altored Divide Bar Remake 1.55\" [y:4/5, n:2/4(5)] (25s remaining)"
37 | "set map Altored Divide Bar Remake 1.55"
38 | "4"
39 | "5"
40 | "2"
41 | "4(5)"
42 | ""
43 | "25s"],
44 | :text "* Vote in progress: \"set map Altored Divide Bar Remake 1.55\" [y:4/5, n:2/4(5)] (25s remaining)"}
45 | (spads/parse-spads-message "* Vote in progress: \"set map Altored Divide Bar Remake 1.55\" [y:4/5, n:2/4(5)] (25s remaining)")))
46 | (is (= {:spads-message-type :cancelling-vote
47 | :spads-parsed ["* Cancelling \"set autobalance on\" vote (command executed directly by user)"
48 | "set autobalance on"
49 | "command executed directly by user"]
50 | :text "* [teh]cluster1[06] * Cancelling \"set autobalance on\" vote (command executed directly by user)"}
51 | (spads/parse-spads-message "* [teh]cluster1[06] * Cancelling \"set autobalance on\" vote (command executed directly by user)"))))
52 |
53 |
54 | (deftest parse-command-message
55 | (is (= {:command "y"
56 | :vote :y}
57 | (spads/parse-command-message "!y")))
58 | (is (= {:command "vote y"
59 | :vote :y}
60 | (spads/parse-command-message "!vote y"))))
61 |
62 |
63 | (deftest parse-relay-message
64 | (is (= {:on-behalf-of "skynet"}
65 | (spads/parse-relay-message " test"))))
66 |
--------------------------------------------------------------------------------
/cryogen/src/cryogen/server.clj:
--------------------------------------------------------------------------------
1 | (ns cryogen.server
2 | (:require
3 | [clojure.string :as string]
4 | [compojure.core :refer [GET defroutes]]
5 | [compojure.route :as route]
6 | [ring.util.response :refer [redirect file-response]]
7 | [ring.util.codec :refer [url-decode]]
8 | [ring.server.standalone :as ring-server]
9 | [cryogen-core.watcher :refer [start-watcher! start-watcher-for-changes!]]
10 | [cryogen-core.plugins :refer [load-plugins]]
11 | [cryogen-core.compiler :refer [compile-assets-timed]]
12 | [cryogen-core.config :refer [resolve-config]]
13 | [cryogen-core.io :refer [path]]))
14 |
15 | (defn init [fast?]
16 | (println "Init: fast compile enabled = " (boolean fast?))
17 | (load-plugins)
18 | (compile-assets-timed)
19 | (let [ignored-files (-> (resolve-config) :ignored-files)]
20 | (run!
21 | #(if fast?
22 | (start-watcher-for-changes! % ignored-files compile-assets-timed {})
23 | (start-watcher! % ignored-files compile-assets-timed))
24 | ["content" "themes"])))
25 |
26 | (defn wrap-subdirectories
27 | [handler]
28 | (fn [request]
29 | (let [{:keys [clean-urls blog-prefix public-dest]} (resolve-config)
30 | req-uri (.substring (url-decode (:uri request)) 1)
31 | res-path (if (or (.endsWith req-uri "/")
32 | (.endsWith req-uri ".html")
33 | (-> (string/split req-uri #"/")
34 | last
35 | (string/includes? ".")
36 | not))
37 | (condp = clean-urls
38 | :trailing-slash (path req-uri "index.html")
39 | :no-trailing-slash (if (or (= req-uri "")
40 | (= req-uri "/")
41 | (= req-uri
42 | (if (string/blank? blog-prefix)
43 | blog-prefix
44 | (.substring blog-prefix 1))))
45 | (path req-uri "index.html")
46 | (path (str req-uri ".html")))
47 | :dirty (path (str req-uri ".html")))
48 | req-uri)]
49 | (or (file-response res-path {:root public-dest})
50 | (handler request)))))
51 |
52 | (defroutes routes
53 | (GET "/" [] (redirect (let [config (resolve-config)]
54 | (path (:blog-prefix config)
55 | (when (= (:clean-urls config) :dirty)
56 | "index.html")))))
57 | (route/files "/")
58 | (route/not-found "Page not found"))
59 |
60 | (def handler (wrap-subdirectories routes))
61 |
62 | (defn serve
63 | "Entrypoint for running via tools-deps (clojure)"
64 | [{:keys [fast] :as opts}]
65 | (ring-server/serve
66 | handler
67 | (merge
68 | {:init (partial init fast)}
69 | opts
70 | {:open-browser? false})))
71 |
72 | (defn -main [& args]
73 | (serve {:port 3000
74 | :fast ((set args) "fast")}))
75 |
--------------------------------------------------------------------------------
/dev/clj/graal/repl.clj:
--------------------------------------------------------------------------------
1 | (ns repl
2 | (:require
3 | [cider.nrepl]
4 | [clojure.string :as string]
5 | [clojure.tools.cli :as cli]
6 | hashp.core
7 | [io.aviso.repl]
8 | [nrepl.cmdline]
9 | [reply.main]
10 | [taoensso.timbre :as timbre]
11 | [taoensso.timbre.appenders.community.rotor :as rotor]
12 | user)
13 | (:import
14 | (java.awt Desktop Desktop$Action)))
15 |
16 |
17 | (set! *warn-on-reflection* true)
18 |
19 |
20 | (def ^:private dev-log-path "repl.log")
21 |
22 |
23 | (defn log-to-file []
24 | (println "Setting up log to" dev-log-path)
25 | (timbre/merge-config!
26 | {:min-level :info
27 | :appenders
28 | {:rotor (rotor/rotor-appender
29 | {:path dev-log-path
30 | :max-size 10000000
31 | :backlog 5})}}))
32 |
33 | (defn disable-print-log []
34 | (timbre/merge-config!
35 | {:appenders
36 | {:println {:enabled? false}}}))
37 |
38 |
39 | (def middleware
40 | [;'cider.nrepl/cider-middleware
41 | 'cider.nrepl/wrap-clojuredocs
42 | 'cider.nrepl/wrap-classpath
43 | 'cider.nrepl/wrap-complete
44 | 'cider.nrepl/wrap-debug
45 | 'cider.nrepl/wrap-format
46 | 'cider.nrepl/wrap-info
47 | 'cider.nrepl/wrap-inspect
48 | 'cider.nrepl/wrap-macroexpand
49 | 'cider.nrepl/wrap-ns
50 | 'cider.nrepl/wrap-spec
51 | 'cider.nrepl/wrap-profile
52 | 'cider.nrepl/wrap-resource
53 | ;'cider.nrepl/wrap-refresh TODO re-render
54 | 'cider.nrepl/wrap-stacktrace
55 | 'cider.nrepl/wrap-test
56 | 'cider.nrepl/wrap-trace
57 | 'cider.nrepl/wrap-out
58 | 'cider.nrepl/wrap-undef
59 | 'cider.nrepl/wrap-version])
60 |
61 | (def cli-options [])
62 |
63 | (defn browse-url [url]
64 | (try
65 | (let [desktop (Desktop/getDesktop)]
66 | (println "Browsing" url)
67 | (if (.isSupported desktop Desktop$Action/BROWSE)
68 | (.browse desktop (java.net.URI. url))
69 | (let [runtime (Runtime/getRuntime)
70 | command ["xdg-open" url] ; https://stackoverflow.com/a/5116553
71 | ^"[Ljava.lang.String;" cmdarray (into-array String command)]
72 | (.exec runtime cmdarray nil nil))))
73 | (catch Exception e
74 | (println "Error browsing url" url e))))
75 |
76 |
77 | (defn -main [& args]
78 | (let [parsed (cli/parse-opts args cli-options)]
79 | (log-to-file)
80 | (disable-print-log)
81 | (future
82 | (nrepl.cmdline/-main
83 | "--middleware"
84 | (str "[" (string/join "," middleware) "]")
85 | ;"--interactive"
86 | "--color"))
87 | (user/init parsed)
88 | (browse-url "http://localhost:12345")
89 | (loop []
90 | (when
91 | (try
92 | (println "Trying to start REPLy")
93 | (reply.main/launch-nrepl
94 | {:attach (slurp ".nrepl-port")
95 | :caught io.aviso.repl/pretty-pst
96 | :color true})
97 | false
98 | (catch Exception _e
99 | (println "Error connecting REPLy, sleeping")
100 | (Thread/sleep 500)
101 | true))
102 | (recur)))
103 | (System/exit 0)))
104 |
--------------------------------------------------------------------------------
/src/clj/skylobby/download/butler.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.download.butler
2 | (:require
3 | [cheshire.core :as json]
4 | [clj-http.client :as clj-http]
5 | [clojure.java.io :as io]
6 | [skylobby.fs :as fs]
7 | [skylobby.http :as http]
8 | [taoensso.timbre :as log]))
9 |
10 |
11 | (set! *warn-on-reflection* true)
12 |
13 |
14 | ; https://github.com/gajop/spring-launcher/blob/master/src/nextgen_downloader.js
15 |
16 |
17 | (def pkg-url "https://content.spring-launcher.com/pkg")
18 | (def fallback-url "https://spring-launcher.ams3.digitaloceanspaces.com/pkg")
19 |
20 | (def api-backend "https://backend.spring-launcher.com/api")
21 |
22 |
23 | (defn pkg-dir [root]
24 | (fs/file root "pkgs"))
25 |
26 |
27 | (defn version-from-spring-name [spring-name]
28 | (->> (clj-http/post
29 | (str api-backend "/versions/from-springname/")
30 | {:body (json/generate-string {:springName spring-name})
31 | :content-type :json
32 | :accept :json
33 | :as :json})
34 | :body))
35 |
36 | ; {:nextgenName "beyond-all-reason/Beyond-All-Reason@main:27"}
37 |
38 |
39 | (defn butler-download-url
40 | ([]
41 | (let [platform (if (fs/windows?) "windows-amd64"
42 | "linux-amd64")]
43 | (butler-download-url platform)))
44 | ([platform]
45 | (str "https://broth.itch.ovh/butler/" platform "/LATEST/archive/default")))
46 |
47 | (defn get-butler [state-atom]
48 | (let [dest-file (fs/file (fs/download-dir) "butler.zip")]
49 | @(http/download-file state-atom (butler-download-url) dest-file)
50 | (fs/extract-7z-fast dest-file (fs/file (fs/download-dir) "butler"))))
51 |
52 |
53 | (defn download-with-butler [url]
54 | (future
55 | (try
56 | (let [butler-file (fs/file (fs/download-dir) "butler" (fs/executable "butler"))
57 | _ (fs/set-executable butler-file)
58 | tmp-dest (fs/canonical-path (fs/file (fs/download-dir) "butler-tmp"))
59 | command [(fs/canonical-path butler-file)
60 | "-j" "-v" "dl" url tmp-dest]
61 | runtime (Runtime/getRuntime)]
62 | (log/info "Running '" command "'")
63 | (let [^"[Ljava.lang.String;" cmdarray (into-array String command)
64 | ^"[Ljava.lang.String;" envp nil
65 | ^java.lang.Process process (.exec runtime cmdarray envp ^java.io.File (fs/app-root))]
66 | (future
67 | (with-open [^java.io.BufferedReader reader (io/reader (.getInputStream process))]
68 | (loop []
69 | (if-let [line (.readLine reader)]
70 | (do
71 | (log/info "(butler" url "out)" line)
72 | (recur))
73 | (log/info "butler" url "stdout stream closed")))))
74 | (future
75 | (with-open [^java.io.BufferedReader reader (io/reader (.getErrorStream process))]
76 | (loop []
77 | (if-let [line (.readLine reader)]
78 | (do
79 | (log/info "(butler" url "err)" line)
80 | (recur))
81 | (log/info "butler" url "stderr stream closed")))))
82 | (.waitFor process)))
83 | (catch Exception e
84 | (log/error e "Error downloading" url)))))
85 |
--------------------------------------------------------------------------------
/graal/clj/skylobby/config.clj:
--------------------------------------------------------------------------------
1 | (ns skylobby.config
2 | (:require
3 | [clojure.edn :as edn]
4 | [clojure.java.io :as io]
5 | [clojure.pprint :refer [pprint]]
6 | [skylobby.fs :as fs]
7 | [taoensso.timbre :as log])
8 | (:import
9 | (java.io File)
10 | (java.net URL)))
11 |
12 |
13 | (set! *warn-on-reflection* true)
14 |
15 |
16 | ; https://github.com/clojure/clojure/blob/28efe345d5e995dc152a0286fb0be81443a0d9ac/src/clj/clojure/instant.clj#L274-L279
17 | (defn- read-file-tag [cs]
18 | (io/file cs))
19 | (defn- read-url-tag [spec]
20 | (URL. spec))
21 |
22 |
23 | ; https://github.com/clojure/clojure/blob/0754746f476c4ddf6a6b699d9547830b2fdad17c/src/clj/clojure/core.clj#L7755-L7761
24 | (def custom-readers
25 | {'spring-lobby/java.io.File #'skylobby.config/read-file-tag
26 | 'spring-lobby/java.net.URL #'skylobby.config/read-url-tag})
27 |
28 |
29 | ; https://stackoverflow.com/a/23592006/984393
30 | (defmethod print-method File [f ^java.io.Writer w]
31 | (.write w (str "#spring-lobby/java.io.File " (pr-str (fs/canonical-path f)))))
32 | (defmethod print-method URL [url ^java.io.Writer w]
33 | (.write w (str "#spring-lobby/java.net.URL " (pr-str (str url)))))
34 |
35 |
36 | (defn slurp-edn
37 | "Returns data loaded from a .edn file in this application's root directory."
38 | [edn-filename]
39 | (try
40 | (let [config-file (fs/config-file edn-filename)]
41 | (log/info "Slurping config edn from" config-file)
42 | (when (fs/exists? config-file)
43 | (let [data (->> config-file slurp (edn/read-string {:readers custom-readers}))]
44 | (if (map? data)
45 | (do
46 | (try
47 | (log/info "Backing up config file that we could parse")
48 | (fs/copy config-file (fs/config-file (str edn-filename ".known-good")))
49 | (catch Exception e
50 | (log/error e "Error backing up config file")))
51 | data)
52 | (do
53 | (log/warn "Config file data from" edn-filename "is not a map")
54 | {})))))
55 | (catch Exception e
56 | (log/warn e "Exception loading app edn file" edn-filename)
57 | (try
58 | (log/info "Copying bad config file for debug")
59 | (fs/copy (fs/config-file edn-filename) (fs/config-file (str edn-filename ".debug")))
60 | (catch Exception e
61 | (log/warn e "Exception copying bad edn file" edn-filename)))
62 | {})))
63 |
64 | (defn spit-edn
65 | "Writes the given data as edn to the given file in the application directory."
66 | ([data filename]
67 | (spit-edn data filename nil))
68 | ([data filename {:keys [pretty]}]
69 | (let [output (if pretty
70 | (with-out-str (pprint (if (map? data)
71 | (into (sorted-map) data)
72 | data)))
73 | (pr-str data))
74 | parsable (try
75 | (edn/read-string {:readers custom-readers} output)
76 | true
77 | (catch Exception e
78 | (log/error e "Config EDN for" filename "does not parse, keeping old file")))
79 | file (fs/config-file (if parsable
80 | filename
81 | (str filename ".bad")))]
82 | (fs/make-parent-dirs file)
83 | (log/info "Spitting edn to" file)
84 | (spit file output))))
85 |
--------------------------------------------------------------------------------
/cryogen/themes/blue/css/screen.css:
--------------------------------------------------------------------------------
1 | h1, h2, h3, h4, h5, h6 {
2 | font-family: 'Alegreya';
3 | }
4 |
5 | body {
6 | color: #333;
7 | background-color: #f2f2f2;
8 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
9 | font-size: 16px;
10 | }
11 |
12 | .container {
13 | max-width: 1000px;
14 | }
15 |
16 | .right {
17 | float: right;
18 | text-align: right;
19 | }
20 |
21 | .navbar {
22 | border-radius: 0;
23 | box-shadow: 0 0 0 0,0 6px 12px rgba(34,34,34,0.3);
24 | }
25 |
26 | .navbar-default {
27 | background-color: #428bca;
28 | border: none;
29 | }
30 |
31 | .navbar-default .navbar-brand {
32 | color: #fff;
33 | font-family: 'Alegreya';
34 | }
35 |
36 | .navbar-default .navbar-brand:hover {
37 | color: #fff;
38 | }
39 |
40 | .navbar-default .navbar-nav li a {
41 | color: #fff;
42 | }
43 |
44 | .navbar-default .navbar-nav li a:hover {
45 | color: #fff;
46 | background-color: #3d80ba;
47 | }
48 |
49 | .navbar-default .navbar-nav .active a {
50 | color: #fff;
51 | background-color: #3d80ba;
52 | }
53 |
54 | .navbar-default .navbar-toggle:hover{
55 | background-color: #3d80ba;
56 | }
57 |
58 | .navbar-default .navbar-toggle .icon-bar {
59 | background-color: #fff;
60 | }
61 |
62 | #sidebar {
63 | margin-left: 15px;
64 | margin-top: 50px;
65 | }
66 |
67 | #content {
68 | background-color: #fff;
69 | border-radius: 3px;
70 | box-shadow: 0 0 0 0,0 6px 12px rgba(34,34,34,0.1);
71 | }
72 |
73 | #content img {
74 | max-width: 100%;
75 | height: auto;
76 | }
77 |
78 | footer {
79 | font-size: 14px;
80 | text-align: center;
81 | padding-top: 75px;
82 | padding-bottom: 30px;
83 | }
84 |
85 | blockquote footer {
86 | text-align: left;
87 | padding-top: 0px;
88 | padding-bottom: 0px;
89 | }
90 |
91 | #post-tags {
92 | margin-top: 30px;
93 | }
94 |
95 | #prev-next {
96 | padding: 15px 0;
97 | }
98 |
99 | .post-header {
100 | margin-bottom: 20px;
101 | }
102 | .post-header h2 {
103 | font-size: 32px;
104 | }
105 |
106 | #post-meta {
107 | font-size: 14px;
108 | color: rgba(0,0,0,0.4)
109 | }
110 |
111 | #page-header {
112 | border-bottom: 1px solid #dbdbdb;
113 | margin-bottom: 20px;
114 | }
115 | #page-header h2 {
116 | font-size: 32px;
117 | }
118 |
119 | pre {
120 | overflow-x: auto;
121 | }
122 | pre code {
123 | display: block;
124 | padding: 0.5em;
125 | overflow-wrap: normal;
126 | white-space: pre;
127 | }
128 |
129 | code {
130 | color: #428bca;
131 | }
132 |
133 | pre, code, .hljs {
134 | background-color: #f7f9fd;
135 | }
136 |
137 | @media (min-width: 768px) {
138 | .navbar {
139 | min-height: 70px;
140 | }
141 | .navbar-nav>li>a {
142 | padding: 30px 20px;
143 | }
144 | .navbar-default .navbar-brand {
145 | font-size: 36px;
146 | padding: 25px 15px;
147 | }
148 | #content{
149 | margin-top: 30px;
150 | padding: 30px 40px;
151 | }
152 | }
153 |
154 | @media (max-width: 767px) {
155 | body{
156 | font-size: 14px;
157 | }
158 | .navbar-default .navbar-brand {
159 | font-size: 30px;
160 | }
161 | #content{
162 | padding: 15px;
163 | }
164 | #post-meta .right {
165 | float:left;
166 | text-align: left;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------