diff --git a/.idea/libraries/android_lint.xml b/.idea/libraries/android_lint.xml
new file mode 100644
index 000000000..6e3e4b9b0
--- /dev/null
+++ b/.idea/libraries/android_lint.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ModuleComputers/ModuleComputers.iml b/ModuleComputers/ModuleComputers.iml
index d069d1020..71633623d 100644
--- a/ModuleComputers/ModuleComputers.iml
+++ b/ModuleComputers/ModuleComputers.iml
@@ -16,5 +16,6 @@
+
\ No newline at end of file
diff --git a/TerrarumBuild.iml b/TerrarumBuild.iml
index 11adfe1b7..d564708a8 100644
--- a/TerrarumBuild.iml
+++ b/TerrarumBuild.iml
@@ -24,5 +24,6 @@
+
\ No newline at end of file
diff --git a/lib/android-lint/common-31.0.1.jar b/lib/android-lint/common-31.0.1.jar
new file mode 100644
index 000000000..0a9b6bade
--- /dev/null
+++ b/lib/android-lint/common-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:39b4cdcfc49c4e5724605c5d8b66f62907e80b9b33a23d4fbeda2f13e7ec739e
+size 526635
diff --git a/lib/android-lint/guava-31.0.1-jre.jar b/lib/android-lint/guava-31.0.1-jre.jar
new file mode 100644
index 000000000..bf65e67c8
--- /dev/null
+++ b/lib/android-lint/guava-31.0.1-jre.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d5be94d65e87bd219fb3193ad1517baa55a3b88fc91d21cf735826ab5af087b9
+size 2974216
diff --git a/lib/android-lint/intellij-core-31.0.1.jar b/lib/android-lint/intellij-core-31.0.1.jar
new file mode 100644
index 000000000..03ff042bf
--- /dev/null
+++ b/lib/android-lint/intellij-core-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2d258f6137c7585608ea43320cfa0a685d32a40e6dd4cd0c21f466e60fd01ace
+size 22786526
diff --git a/lib/android-lint/kotlin-compiler-31.0.1.jar b/lib/android-lint/kotlin-compiler-31.0.1.jar
new file mode 100644
index 000000000..e41e02d2c
--- /dev/null
+++ b/lib/android-lint/kotlin-compiler-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1b1ff8dca59b78e59aaa02818e1aef4aa142302fdfa7fb9041ca0c342da0bbe3
+size 47773961
diff --git a/lib/android-lint/kxml2-2.3.0.jar b/lib/android-lint/kxml2-2.3.0.jar
new file mode 100644
index 000000000..953572cc1
--- /dev/null
+++ b/lib/android-lint/kxml2-2.3.0.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2
+size 43858
diff --git a/lib/android-lint/layoutlib-api-31.0.1.jar b/lib/android-lint/layoutlib-api-31.0.1.jar
new file mode 100644
index 000000000..60df2a14e
--- /dev/null
+++ b/lib/android-lint/layoutlib-api-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3df9c0423d26dffae97d9d622492c817dd57ac2d46b15e077b2af5fd9bf8ac05
+size 118413
diff --git a/lib/android-lint/lint-31.0.1.pom b/lib/android-lint/lint-31.0.1.pom
new file mode 100644
index 000000000..ae75c8b19
--- /dev/null
+++ b/lib/android-lint/lint-31.0.1.pom
@@ -0,0 +1,127 @@
+
+
+ 4.0.0
+ com.android.tools.lint
+ lint
+ 31.0.1
+ com.android.tools.lint.lint
+ Lint tools. Both a Command line tool and a library to add lint features to other tools
+ http://tools.android.com/
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ The Android Open Source Project
+
+
+
+
+ com.android.tools.lint
+ lint-api
+ 31.0.1
+ compile
+
+
+ com.android.tools.lint
+ lint-checks
+ 31.0.1
+ compile
+
+
+ com.android.tools.external.com-intellij
+ intellij-core
+ 31.0.1
+ runtime
+
+
+ com.android.tools.external.com-intellij
+ kotlin-compiler
+ 31.0.1
+ runtime
+
+
+ com.android.tools.external.org-jetbrains
+ uast
+ 31.0.1
+ runtime
+
+
+ com.android.tools.analytics-library
+ protos
+ 31.0.1
+ runtime
+
+
+ com.android.tools.analytics-library
+ shared
+ 31.0.1
+ runtime
+
+
+ com.android.tools.analytics-library
+ tracker
+ 31.0.1
+ runtime
+
+
+ com.android.tools.build
+ manifest-merger
+ 31.0.1
+ runtime
+
+
+ com.android.tools
+ common
+ 31.0.1
+ runtime
+
+
+ com.android.tools.layoutlib
+ layoutlib-api
+ 31.0.1
+ runtime
+
+
+ com.android.tools
+ sdk-common
+ 31.0.1
+ runtime
+
+
+ com.android.tools
+ sdklib
+ 31.0.1
+ runtime
+
+
+ com.google.guava
+ guava
+ 31.0.1-jre
+ runtime
+
+
+ net.sf.kxml
+ kxml2
+ 2.3.0
+ runtime
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ 1.7.10
+ runtime
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ 1.7.10
+ runtime
+
+
+
diff --git a/lib/android-lint/lint-api-31.0.1.jar b/lib/android-lint/lint-api-31.0.1.jar
new file mode 100644
index 000000000..11533eb83
--- /dev/null
+++ b/lib/android-lint/lint-api-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b574c059dbe7c0bd5a8fb99b239e6ba844484a59c6622f2636c107eb87c3c24b
+size 1228529
diff --git a/lib/android-lint/lint-checks-31.0.1.jar b/lib/android-lint/lint-checks-31.0.1.jar
new file mode 100644
index 000000000..d1d44103d
--- /dev/null
+++ b/lib/android-lint/lint-checks-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:67d210b6331030d27b11d7e081a9d299eb1d7a5519304de5a2c00fbb19044d42
+size 5451675
diff --git a/lib/android-lint/manifest-merger-31.0.1.jar b/lib/android-lint/manifest-merger-31.0.1.jar
new file mode 100644
index 000000000..d7285880f
--- /dev/null
+++ b/lib/android-lint/manifest-merger-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f7082a48ad04dc93cbdf4247569c3ce1c25c1488724951f00c04f7253a9bfba5
+size 224062
diff --git a/lib/android-lint/protos-31.0.1.jar b/lib/android-lint/protos-31.0.1.jar
new file mode 100644
index 000000000..ebecce219
--- /dev/null
+++ b/lib/android-lint/protos-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d074b93c2395722c6fff42b0397c5ba6cb2be44338a49a5133fbfb9b8191a68d
+size 6268854
diff --git a/lib/android-lint/sdk-common-31.0.1.jar b/lib/android-lint/sdk-common-31.0.1.jar
new file mode 100644
index 000000000..c1bbbf5c6
--- /dev/null
+++ b/lib/android-lint/sdk-common-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:766aa3b48b8c87adb8a1b0fed6689d48ec85ea803f85ab9f155c0e40c510e258
+size 1529180
diff --git a/lib/android-lint/sdklib-31.0.1.jar b/lib/android-lint/sdklib-31.0.1.jar
new file mode 100644
index 000000000..70f86e235
--- /dev/null
+++ b/lib/android-lint/sdklib-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9770b9aaedcb5543497b9abb79ac0e1ee5ba3a8197969b52aa51a06f6bc10964
+size 707911
diff --git a/lib/android-lint/shared-31.0.1.jar b/lib/android-lint/shared-31.0.1.jar
new file mode 100644
index 000000000..8e5dd0ba5
--- /dev/null
+++ b/lib/android-lint/shared-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d7efd1542cf705b1a0a46ac493849f7cf3d5e4b3bcdc78a4fa0478ea6c7caccb
+size 122231
diff --git a/lib/android-lint/tracker-31.0.1.jar b/lib/android-lint/tracker-31.0.1.jar
new file mode 100644
index 000000000..431000820
--- /dev/null
+++ b/lib/android-lint/tracker-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a62bcf8ad3816bdc276999e80c8edd52bdb1a20bfd571d8f5f7e91fce1c74545
+size 40677
diff --git a/lib/android-lint/uast-31.0.1.jar b/lib/android-lint/uast-31.0.1.jar
new file mode 100644
index 000000000..d084eb4d5
--- /dev/null
+++ b/lib/android-lint/uast-31.0.1.jar
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b4b1a74a712518c0dfd9930e9ffa69288ec84cf2fb55a5abd09f30b73ab0cac0
+size 2530116
diff --git a/src/net/torvald/terrarum/UnserialisableTypeIssueRegistry.kt b/src/net/torvald/terrarum/UnserialisableTypeIssueRegistry.kt
new file mode 100644
index 000000000..4ea2b02d4
--- /dev/null
+++ b/src/net/torvald/terrarum/UnserialisableTypeIssueRegistry.kt
@@ -0,0 +1,97 @@
+package net.torvald.terrarum
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.*
+import net.torvald.random.HQRNG
+import net.torvald.terrarum.gameactors.Actor
+import net.torvald.terrarum.gameitems.GameItem
+import net.torvald.terrarum.gameworld.BlockLayer
+import net.torvald.terrarum.gameworld.WorldTime
+import net.torvald.terrarum.savegame.ByteArray64
+import net.torvald.terrarum.utils.*
+import org.jetbrains.uast.UClass
+import org.jetbrains.uast.UField
+import org.jetbrains.uast.util.classSetOf
+import org.jetbrains.uast.util.isInstanceOf
+import java.math.BigInteger
+import java.util.*
+
+/**
+ * https://medium.com/@vanniktech/writing-your-first-lint-check-39ad0e90b9e6
+ * https://medium.com/mobile-app-development-publication/making-custom-lint-for-kotlin-code-8a6c203bf474
+ * https://github.com/googlesamples/android-custom-lint-rules
+ * https://googlesamples.github.io/android-custom-lint-rules/api-guide.html
+ *
+ * Created by minjaesong on 2023-05-22.
+ */
+class UnserialisableTypeIssueRegistry : IssueRegistry() {
+ override val issues = listOf(ISSUE_SAVEGAME_UNSERIALISABLE_TYPE_USED_WITHOUT_TRANSIENT)
+}
+
+val ISSUE_SAVEGAME_UNSERIALISABLE_TYPE_USED_WITHOUT_TRANSIENT = Issue.create("TerrarumNonTransientUnserialisableType",
+ "Unserialisable Type Used Without Care",
+ "Unserialisable type is used on the potentially serialised class without @Transient annotation",
+ Category.CORRECTNESS,
+ 9,
+ Severity.ERROR,
+ Implementation(TerrarumNonTransientUnserialisableType::class.java, EnumSet.of(Scope.JAVA_FILE))
+)
+
+class TerrarumNonTransientUnserialisableType : Detector(), Detector.UastScanner {
+ override fun getApplicablePsiTypes() = listOf(UClass::class.java)
+ override fun createUastHandler(context: JavaContext) = TerrarumNonTransientUnserialisableTypeHandler(context)
+
+ class TerrarumNonTransientUnserialisableTypeHandler(private val context: JavaContext) : UElementHandler() {
+ override fun visitClass(clazz: UClass) {
+ /*if (clazz.name?.isDefinedCamelCase() == false) {
+ context.report(ISSUE_SAVEGAME_UNSERIALISABLE_TYPE_USED_WITHOUT_TRANSIENT, clazz,
+ context.getNameLocation(clazz),
+ "Not named in defined camel case.")
+ }*/
+ }
+
+ override fun visitField(node: UField) {
+ if (node.uastParent.isInstanceOf(classSetOf(Actor::class.java, GameItem::class.java)) &&
+ !node.hasAnnotation("Transient") &&
+ !node.isInstanceOf(classSetOf(
+ // primitives
+ String::class.java,
+ Array::class.java,
+ Boolean::class.java,
+ Byte::class.java,
+ ByteArray::class.java,
+ ByteArray64::class.java,
+ Short::class.java,
+ ShortArray::class.java,
+ Int::class.java,
+ IntArray::class.java,
+ Long::class.java,
+ LongArray::class.java,
+ Float::class.java,
+ FloatArray::class.java,
+ Double::class.java,
+ DoubleArray::class.java,
+ // has serialiser on net.torvald.terrarum.serialise.Common
+ BigInteger::class.java,
+ ZipCodedStr::class.java,
+ BlockLayer::class.java,
+ WorldTime::class.java,
+ HashArray::class.java,
+ HashedWirings::class.java,
+ HashedWiringGraph::class.java,
+ WiringGraphMap::class.java,
+ UUID::class.java,
+ HQRNG::class.java,
+ ))) {
+
+ context.report(
+ ISSUE_SAVEGAME_UNSERIALISABLE_TYPE_USED_WITHOUT_TRANSIENT,
+ node,
+ context.getNameLocation(node),
+ "Unserialisable type is used on the potentially serialised class without @Transient annotation"
+ )
+ }
+ }
+ }
+}