thread pooling terraingen, WIP

Former-commit-id: 1d0687d8b34d5e8192b652904a437cdb29f27b10
Former-commit-id: 1c06ce97a59eb13455cc180a4d5f13ffbead1f84
This commit is contained in:
Song Minjae
2016-06-13 00:48:37 +09:00
parent f98cd773b1
commit 9f42ae9639
8 changed files with 180 additions and 46 deletions

58
res/books/cjk_test.txt Normal file
View File

@@ -0,0 +1,58 @@
流れてく時の中ででも気だるさが ほらクルクル廻って
흘러만 가는 시간 속 한가운데도 나른함이 봐, 계속 빙글빙글 돌고 있어
私から離れる心も見えないわ そう知らない
보이지 않아, 나에게서 멀어지는 마음 따위는, 그래 나는 몰라
自分から動くこともなく 時の隙間に流され続けて
스스로부터 움직이는 일도 없이 시간의 틈새에서 우두커니 바라볼 뿐
知らないわ周りのことなど 私は私 それだけ
그런 건 몰라, 내 주변의 일 같은 건, 나는 나일 뿐 더는 신경 안 써
夢見てる 何も見てない 語るも無駄な自分の言葉
꿈이 보이니? 어둠만이 보이니? 부질없이 울리는 나 자신의 혼잣말
悲しむなんで疲れるだけよ 何も感じす過ごせばいいの
슬픔에 잠기는 건 이젠 지칠 뿐이야, 아무 감정도 없이 지내면 되는 거야
戸惑う言葉与えられても 自分の心ただ上の空
뜻밖의 놀라운 말 나에게 온다 해도 아직 나의 마음은 그저 흘려들을 뿐
もし私から動くのならば 全て変えるのなら黒にする
만약 나 자신부터 움직일 수 있다면, 모든 걸 바꿀 수 있다면 검게 하겠어
こんな自分に未来はあるの こんな世界に私はいるの
이런 나 자신에게 미래는 있는 걸까, 이런 세상 가운데 난 끼어 있는 걸까
今切ないの 今悲しいの 自分のこともわからないまま
애달퍼하는 걸까, 슬픔에 잠긴 걸까, 이런 자신조차도 알지 못하는 채로
歩むことさえ疲れるだけよ 人のことなど知りもしないわ
발을 내딛는 것도 이젠 지칠 뿐이야, 주변의 일들 따윈 알고 싶지도 않아
こんな私も変われるのなら もし変われるのなら白になる
이런 나 같은 것도 바뀔 수가 있다면, 바뀔 수만 있다면 나는 하얘지겠어
流れてく時の中ででも気だるさが ほらクルクル廻って
흘러만 가는 시간 속 한가운데도 나른함이 봐, 계속 빙글빙글 돌고 있어
私から離れる心も見えないわ そう知らない
보이지 않아, 나에게서 멀어지는 마음 따위는, 그래 나는 몰라
自分から動くこともなく 時の隙間に流され続けて
스스로부터 움직이는 일도 없이 시간의 틈새에서 우두커니 바라볼 뿐
知らないわ周りのことなど 私は私 それだけ
그런 건 몰라, 내 주변의 일 같은 건, 나는 나일 뿐, 더는 신경 안 써
夢見てる 何も見てない 語るも無駄な自分の言葉
꿈이 보이니? 어둠만이 보이니? 부질없이 울리는 나 자신의 혼잣말
悲しむなんで疲れるだけよ 何も感じす過ごせばいいの
슬픔에 잠기는 건 이젠 지칠 뿐이야, 아무 감정도 없이 지내면 되는 거야
戸惑う言葉与えられても 自分の心ただ上の空
뜻밖의 놀라운 말 나에게 온다 해도 아직 나의 마음은 그저 흘려들을 뿐
もし私から動くのならば 全て変えるのなら黒にする
만약 나 자신부터 움직일 수 있다면, 모든 걸 바꿀 수 있다면 검게 하겠어
動くのならば 動くのならば 全て壊すの 全て壊すの
움직이고 있다면, 움직이고 있다면, 모두 다 부숴버려, 모두 다 부숴버려
悲しむならば 悲しむならば 私の心白く変われる
슬퍼하고 있으면, 슬퍼하고 있으면, 이런 나의 마음도 하얘질 수 있을까
貴方のことも 私のことも 全てのこともまだ知らないの
그대에 관해서도, 자신에 관해서도, 모두에 관해서도 아직도 나는 몰라
重い目蓋を開けてのならば 全て壊すのなら黒になれ
무거운 눈꺼풀을 뜨게할 수 있다면, 모든 걸 부순다면 모두 검게 되어라

View File

@@ -1,14 +1,15 @@
"STRING_ID";"IETF language tag(s) without dash";"enUS";"frFR";"esES";"deDE";"itIT";"ptBR";"ptPT";"ruRU";"elGR";"trTR";"daDK";"noNB";"svSE";"nlNL";"plPL";"fiFI";"jaJP";"zhCN";"zhTW";"koKR";"csCZ";"huHU";"roRO";"thTH";"bgBG";"heIL";"jakanaJP";"isIC"
"HELP_OTF_MAIN_1";;"Type “help slow” for the ways to make the game run faster.";"Tapez « help slow » si votre jeu fonctionne lentement.";;;;;;;;;;;;;;;"ゲームの実行がおそければ「help slow」を入力してください。";;;"게임이 느리게 돌아간다면 “help slow”를 입력해 보세요."
"HELP_OTF_MAIN_2";;"Press PageUp/PageDown to scroll the messages.";"Appuyez sur PageUp/PageDown pour faire défiler les messages.";;;;;;;;;;;;;;;"PageUp/PageDownキーを使ってメッセージのスクロールができます。";;;"PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다."
"HELP_OTF_MAIN_1";;"Type “help slow” for the ways to make the game run faster.";"Tapez « help slow » si votre jeu fonctionne lentement.";;;;;;;;;;;;;;;"ゲームの実行がおそければ「help slow」を入力してください。";;;"게임이 느리게 돌아간다면 “help slow”를 입력해 보세요.";;;;;;"ゲームのじっこうが おそければ「help slow」を にんりょくしてください。"
"HELP_OTF_MAIN_2";;"Press PageUp/PageDown to scroll the messages.";"Appuyez sur PageUp/PageDown pour faire défiler les messages.";;;;;;;;;;;;;;;"PageUp/PageDownキーを使ってメッセージのスクロールができます。";;;"PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다.";;;;;;"PageUp/PageDownキーをつかって メッセージのスクロールができます。"
"HELP_OTF_MAIN_3";;"Utility keys:";"Touches utilitaires:";;;;;;;;;;;;;;;"技能キー";;;"기능 키:"
"HELP_OTF_MAIN_4";;"• F3: (debug) basic information";"• F3: (déboguer) informations de base";;;;;;;;;;;;;;;"• F3: (デバッグ)基本的な情報";;;"• F3: (디버그) 기본 정보"
"HELP_OTF_MAIN_5";;"• F7: (debug) toggle light blending";"• F7: (déboguer) basculer fusion de lumière";;;;;;;;;;;;;;;"• F7: (デバッグ)光源のブレンドON/OFF";;;"• F7: (디버그) 광원 블렌딩 켜고 끄기"
"HELP_OTF_MAIN_6";;"• F8: toggle smooth lighting effect";"• F8: basculer effet éclairage lisse";;;;;;;;;;;;;;;"• F8: すべすべの光源効果ON/OFF";;;"• F8: 부드러운 광원 효과 켜고 끄기"
"HELP_OTF_MAIN_4";;"• F3: (debug) basic information";"• F3: (déboguer) informations de base";;;;;;;;;;;;;;;"• F3: (デバッグ)基本的な情報を見る";;;"• F3: (디버그) 기본 정보";;;;;;"• F3: (デバッグ)きほんてきな じょうほうを みる"
"HELP_OTF_MAIN_5";;"• F7: (debug) toggle light blending";"• F7: (déboguer) basculer fusion de lumière";;;;;;;;;;;;;;;"• F7: (デバッグ)光源のブレンドをオン・オフする";;;"• F7: (디버그) 광원 블렌딩 켜고 끄기";;;;;;"• F7: (デバッグ)こうげんのブレンドを オン・オフする"
"HELP_OTF_MAIN_6";;"• F8: toggle smooth lighting effect";"• F8: basculer effet éclairage lisse";;;;;;;;;;;;;;;"• F8: すべすべの光源効果をオン・オフする";;;"• F8: 부드러운 광원 효과 켜고 끄기";;;;;;"• F8: すべすべのこうげん こうかを オン・オフする"
"HELP_OTF_MAIN_JP_1";;"• F4: toggle Kana/Kanji mode";;;;;;;;;;;;;;;;"• F8: 【日本語】かな・漢字モードを変換する";;;"• F8: 부드러운 광원 효과 켜고 끄기";;;;;;"• F8: 【日本語】かな・かんじモードを"
"HELP_OTF_SLOW_1";;"If your game runs slowly:";"Si votre jeu tourne lentement :";;;;;;;;;;;;;;;"ゲームの実行がおそければ";;;"게임이 느리게 돌아간다면"
"HELP_OTF_SLOW_2";;"• Reset screen zoom to 1.";"• Réinitialisez le zoom de lécran à 1.";;;;;;;;;;;;;;;"• スクリーンのズームを1倍にリセットしてください。";;;"• 화면 줌을 1로 돌려주세요. "
"HELP_OTF_SLOW_3";;"• Close the basic information window.";"• Désactivez la fenêtre dinformations.";;;;;;;;;;;;;;;"• 情報ウィンドウをとじてください。";;;"• 기본 정보 창을 꺼 주세요."
"HELP_OTF_SLOW_4";;"• Turn off smooth lighting effect. You can do it now by pressing F8.";"• Désactivez effet éclairage lisse en utilisant F8.";;;;;;;;;;;;;;;"• F8で、すべすべの光源効果をオフしてください。";;;"• 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다."
"HELP_OTF_SLOW_1";;"If your game runs slowly:";"Si votre jeu tourne lentement :";;;;;;;;;;;;;;;"ゲームの実行がおそければ";;;"게임이 느리게 돌아간다면";;;;;;"ゲームのじっこうが おそければ"
"HELP_OTF_SLOW_2";;"• Reset screen zoom to 1.";"• Réinitialisez le zoom de lécran à 1.";;;;;;;;;;;;;;;"• スクリーンのズームを1倍にリセットしてください。";;;"• 화면 줌을 1로 돌려주세요. ";;;;;;"• スクリーンのズームを 1にリセットしてください。"
"HELP_OTF_SLOW_3";;"• Close the basic information window.";"• Désactivez la fenêtre dinformations.";;;;;;;;;;;;;;;"• 情報ウィンドウをとじてください。";;;"• 기본 정보 창을 꺼 주세요.";;;;;;"• じょうほうウィンドウを とじてください。"
"HELP_OTF_SLOW_4";;"• Turn off smooth lighting effect. You can do it now by pressing F8.";"• Désactivez effet éclairage lisse en utilisant F8.";;;;;;;;;;;;;;;"• F8で、すべすべの光源効果をオフしてください。";;;"• 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다.";;;;;;"• F8で、すべすべのこうげん こうかを オフしてください。"
1 STRING_ID IETF language tag(s) without dash enUS frFR esES deDE itIT ptBR ptPT ruRU elGR trTR daDK noNB svSE nlNL plPL fiFI jaJP zhCN zhTW koKR csCZ huHU roRO thTH bgBG heIL jakanaJP isIC
2 HELP_OTF_MAIN_1 Type “help slow” for the ways to make the game run faster. Tapez « help slow » si votre jeu fonctionne lentement. ゲームの実行がおそければ「help slow」を入力してください。 게임이 느리게 돌아간다면 “help slow”를 입력해 보세요. ゲームのじっこうが おそければ「help slow」を にんりょくしてください。
3 HELP_OTF_MAIN_2 Press PageUp/PageDown to scroll the messages. Appuyez sur PageUp/PageDown pour faire défiler les messages. PageUp/PageDownキーを使ってメッセージのスクロールができます。 PageUp/PageDown 키를 사용해 메시지를 스크롤할 수 있습니다. PageUp/PageDownキーをつかって メッセージのスクロールができます。
4 HELP_OTF_MAIN_3 Utility keys: Touches utilitaires: 技能キー 기능 키:
5 HELP_OTF_MAIN_4 • F3: (debug) basic information • F3: (déboguer) informations de base • F3: (デバッグ)基本的な情報 • F3: (デバッグ)基本的な情報を見る • F3: (디버그) 기본 정보 • F3: (デバッグ)きほんてきな じょうほうを みる
6 HELP_OTF_MAIN_5 • F7: (debug) toggle light blending • F7: (déboguer) basculer fusion de lumière • F7: (デバッグ)光源のブレンドON/OFF • F7: (デバッグ)光源のブレンドをオン・オフする • F7: (디버그) 광원 블렌딩 켜고 끄기 • F7: (デバッグ)こうげんのブレンドを オン・オフする
7 HELP_OTF_MAIN_6 • F8: toggle smooth lighting effect • F8: basculer effet éclairage lisse • F8: すべすべの光源効果ON/OFF • F8: すべすべの光源効果をオン・オフする • F8: 부드러운 광원 효과 켜고 끄기 • F8: すべすべのこうげん こうかを オン・オフする
8 HELP_OTF_SLOW_1 HELP_OTF_MAIN_JP_1 If your game runs slowly: • F4: toggle Kana/Kanji mode Si votre jeu tourne lentement : ゲームの実行がおそければ • F8: 【日本語】かな・漢字モードを変換する 게임이 느리게 돌아간다면 • F8: 부드러운 광원 효과 켜고 끄기 • F8: 【日本語】かな・かんじモードを
9 HELP_OTF_SLOW_1 If your game runs slowly: Si votre jeu tourne lentement : ゲームの実行がおそければ 게임이 느리게 돌아간다면 ゲームのじっこうが おそければ
10 HELP_OTF_SLOW_2 • Reset screen zoom to 1. • Réinitialisez le zoom de l‘écran à 1. • スクリーンのズームを1倍にリセットしてください。 • 화면 줌을 1로 돌려주세요. • スクリーンのズームを 1にリセットしてください。
11 HELP_OTF_SLOW_3 • Close the basic information window. • Désactivez la fenêtre d‘informations. • 情報ウィンドウをとじてください。 • 기본 정보 창을 꺼 주세요. • じょうほうウィンドウを とじてください。
12 HELP_OTF_SLOW_4 • Turn off smooth lighting effect. You can do it now by pressing F8. • Désactivez effet éclairage lisse en utilisant F8. • F8で、すべすべの光源効果をオフしてください。 • 부드러운 광원 효과를 꺼 주세요. F8을 사용할 수 있습니다. • F8で、すべすべのこうげん こうかを オフしてください。
13
14
15

View File

@@ -373,7 +373,7 @@ constructor() : BasicGameState() {
}
fun updateActors(gc: GameContainer, delta: Int) {
if (CORES >= 2 && Terrarum.getConfigBoolean("multithread")) {
if (false) { // don't multithread this for now, it's SLOWER //if (Terrarum.MULTITHREAD) {
val actors = actorContainer.size.toFloat()
// set up indices
for (i in 0..ThreadPool.POOL_SIZE - 1) {

View File

@@ -114,6 +114,15 @@ constructor(gamename: String) : StateBasedGame(gamename) {
/** Available CPU cores */
val CORES = Runtime.getRuntime().availableProcessors();
/**
* If the game is multithreading.
* True if:
*
* CORES >= 2 and config "multithread" is true
*/
val MULTITHREAD: Boolean
get() = CORES >= 2 && getConfigBoolean("multithread")
private lateinit var configDir: String
/**

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.gameactors.Player
import net.torvald.terrarum.Terrarum
import org.newdawn.slick.GameContainer
/**

View File

@@ -6,12 +6,15 @@ import net.torvald.terrarum.tileproperties.TileNameCode
import com.jme3.math.FastMath
import com.sudoplay.joise.Joise
import com.sudoplay.joise.module.*
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.concurrent.ThreadPool
import net.torvald.terrarum.gameactors.ThreadActorUpdate
import java.util.*
object MapGenerator {
private lateinit var map: GameMap
private lateinit var random: Random
internal lateinit var map: GameMap
internal lateinit var random: Random
//private static float[] noiseArray;
var SEED: Long = 0
var WIDTH: Int = 0
@@ -56,7 +59,7 @@ object MapGenerator {
private val GRASSCUR_DOWN = 2
private val GRASSCUR_LEFT = 3
private val TILE_MACRO_ALL = -1
internal val TILE_MACRO_ALL = -1
fun attachMap(map: GameMap) {
this.map = map
@@ -665,33 +668,50 @@ object MapGenerator {
}
private fun processNoiseLayers(noiseRecords: Array<TaggedJoise>) {
for (record in noiseRecords) {
println("[mapgenerator] ${record.message}...")
for (y in 0..HEIGHT - 1) {
for (x in 0..WIDTH - 1) {
val noise: Float = record.noiseModule.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
val fromTerr = record.replaceFromTerrain
val fromWall = record.replaceFromWall
val to: Int = when(record.replaceTo) {
is Int -> record.replaceTo as Int
is IntArray -> (record.replaceTo as IntArray)[random.nextInt((record.replaceTo as IntArray).size)]
else -> throw IllegalArgumentException("[mapgenerator] Unknown replaceTo tile type '${record.replaceTo.javaClass.canonicalName}': Only 'kotlin.Int' and 'kotlin.IntArray' is valid.")
}
if (to == TILE_MACRO_ALL) throw IllegalArgumentException("[mapgenerator] Invalid replaceTo: TILE_MACRO_ALL")
val threshold = record.filter.getGrad(y, record.filterArg1, record.filterArg2)
if (noise > threshold * record.scarcity) {
if ((map.getTileFromTerrain(x, y) == fromTerr || fromTerr == TILE_MACRO_ALL)
&& (map.getTileFromWall(x, y) == fromWall || fromWall == TILE_MACRO_ALL)) {
map.setTileTerrain(x, y, to)
}
}
}
if (Terrarum.MULTITHREAD) {
// set up indices
for (i in 0..ThreadPool.POOL_SIZE - 1) {
ThreadPool.map(
i,
ThreadProcessNoiseLayers(
((HEIGHT / Terrarum.CORES) * i).toInt(),
((HEIGHT / Terrarum.CORES) * i.plus(1)).toInt() - 1,
noiseRecords
),
"SampleJoiseMap"
)
}
ThreadPool.startAll()
// FIXME game starts prematurely
/* Console:
[mapgenerator] Seed: 85336530
[mapgenerator] Raising and eroding terrain...
[mapgenerator] Shaping world...
[mapgenerator] Carving caves...
[mapgenerator] Carving caves...
[mapgenerator] Carving caves...
[mapgenerator] Flooding bottom lava...
[mapgenerator] Carving caves...
[mapgenerator] Planting grass...
[mapgenerator] Placing floating islands...
[UIHandler] Creating UI 'ConsoleWindow'
Mon Jun 13 00:43:57 KST 2016 INFO:Offscreen Buffers FBO=true PBUFFER=true PBUFFERRT=false
Mon Jun 13 00:43:57 KST 2016 DEBUG:Creating FBO 2048x256
[UIHandler] Creating UI 'BasicDebugInfoWindow'
Mon Jun 13 00:43:57 KST 2016 INFO:Offscreen Buffers FBO=true PBUFFER=true PBUFFERRT=false
Mon Jun 13 00:43:57 KST 2016 DEBUG:Creating FBO 2048x1024
[UIHandler] Creating UI 'Notification'
Mon Jun 13 00:43:57 KST 2016 INFO:Offscreen Buffers FBO=true PBUFFER=true PBUFFERRT=false
Mon Jun 13 00:43:57 KST 2016 DEBUG:Creating FBO 512x64
[mapgenerator] Collapsing caves...
[mapgenerator] Collapsing caves...
[mapgenerator] Collapsing caves...
[mapgenerator] Collapsing caves...
*/
}
else {
ThreadProcessNoiseLayers(0, HEIGHT - 1, noiseRecords).run()
}
}

View File

@@ -0,0 +1,46 @@
package net.torvald.terrarum.mapgenerator
/**
* Created by minjaesong on 16-06-13.
*/
class ThreadProcessNoiseLayers(val startIndex: Int, val endIndex: Int,
val noiseRecords: Array<MapGenerator.TaggedJoise>) : Runnable {
override fun run() {
for (record in noiseRecords) {
println("[mapgenerator] ${record.message}...")
for (y in startIndex..endIndex) {
for (x in 0..MapGenerator.WIDTH - 1) {
val noise: Float = record.noiseModule.get(
x.toDouble() / 48.0, // 48: Fixed value
y.toDouble() / 48.0
).toFloat()
val fromTerr = record.replaceFromTerrain
val fromWall = record.replaceFromWall
val to: Int = when (record.replaceTo) {
// replace to designated tile
is Int -> record.replaceTo as Int
// replace to randomly selected tile from given array of tile IDs
is IntArray -> (record.replaceTo as IntArray)[MapGenerator.random.nextInt((record.replaceTo as IntArray).size)]
else -> throw IllegalArgumentException("[mapgenerator] Unknown replaceTo tile type '${record.replaceTo.javaClass.canonicalName}': Only 'kotlin.Int' and 'kotlin.IntArray' is valid.")
}
// replace to ALL? this is bullshit
if (to == MapGenerator.TILE_MACRO_ALL) throw IllegalArgumentException("[mapgenerator] Invalid replaceTo: TILE_MACRO_ALL")
// filtered threshold
val threshold = record.filter.getGrad(y, record.filterArg1, record.filterArg2)
if (noise > threshold * record.scarcity) {
if ((MapGenerator.map.getTileFromTerrain(x, y) == fromTerr || fromTerr == MapGenerator.TILE_MACRO_ALL)
&& (MapGenerator.map.getTileFromWall(x, y) == fromWall || fromWall == MapGenerator.TILE_MACRO_ALL)) {
MapGenerator.map.setTileTerrain(x, y, to)
}
}
}
}
}
}
}

View File

@@ -45,7 +45,7 @@
"11"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "81916159"; "11"; "1"; "0";"16"
"12"; "0";"TILE_TORCH" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "0"; "0";"16"
"12"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "1"; "0";"16"
"13"; "0";"TILE_ILLUMINATOR_WHITE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "248768744"; "13"; "0"; "0";"16"
"13"; "0";"TILE_ILLUMINATOR_WHITE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "239319274"; "13"; "0"; "0";"16"
"13"; "1";"TILE_ILLUMINATOR_YELLOW" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246656000"; "13"; "1"; "0";"16"
"13"; "2";"TILE_ILLUMINATOR_ORANGE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246602752"; "13"; "2"; "0";"16"
"13"; "3";"TILE_ILLUMINATOR_RED" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246415360"; "13"; "3"; "0";"16"
@@ -128,12 +128,12 @@
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
## Illuminants ##
## Illuminators ##
# Illuminant white: RGB(237,250,232), simulation of mercury-vapour lamp (If you want high CRI lamp, collect a daylight!)
# Illuminator white: RGB(228,238,234), simulation of a halophosphate FL lamp (If you want high CRI lamp, collect a daylight!)
# Defalut torch : L 70 a 51 b 59; real candlelight colour taken from properly configured camera.
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight. Set by game's code.
# Sunlight capacitor: daylight at 11h of 22h day. Set by game's code.
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight. The light is set by game's code.
# Sunlight capacitor: daylight at noon. Set by game's code.
## Tiles ##
Can't render this file because it contains an unexpected character in line 1 and column 18.