diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt
index 5f69cb94..80cb3a6d 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Starbound.kt
@@ -48,6 +48,21 @@ object Starbound {
 	 * Служит переменной для указания из какой папки происходит чтение asset'а в данном потоке
 	 */
 	var readingFolder by ThreadLocal<String>()
+		private set
+
+	fun readingFolderTransformer(input: String): String {
+		if (input[0] == '/')
+			return input
+
+		return "$readingFolder/$input"
+	}
+
+	fun readingFolderTransformerNullable(input: String?): String? {
+		if (input != null)
+			return readingFolderTransformer(input)
+
+		return null
+	}
 
 	private val tiles = HashMap<String, TileDefinition>()
 	private val tilesByMaterialID = Int2ObjectAVLTreeMap<TileDefinition>()
@@ -432,5 +447,7 @@ object Starbound {
 				}
 			}
 		}
+
+		items.values.forEach { println(it) }
 	}
 }
diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt
index 5483a4b1..83f35a88 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/defs/item/ItemDefinition.kt
@@ -1,10 +1,10 @@
 package ru.dbotthepony.kstarbound.defs.item
 
 import com.google.gson.GsonBuilder
+import ru.dbotthepony.kstarbound.Starbound
 import ru.dbotthepony.kstarbound.io.KConcreteTypeAdapter
 import ru.dbotthepony.kstarbound.registerTypeAdapter
 import ru.dbotthepony.kvector.vector.ndouble.Vector2d
-import ru.dbotthepony.kvector.vector.nint.Vector2i
 
 data class ItemDefinition(
 	/**
@@ -136,7 +136,7 @@ data class ItemDefinition(
 			.plain(ItemDefinition::price)
 			.plain(ItemDefinition::rarity)
 			.plain(ItemDefinition::category)
-			.plain(ItemDefinition::inventoryIcon)
+			.plain(ItemDefinition::inventoryIcon, Starbound::readingFolderTransformerNullable)
 			.plain(ItemDefinition::description)
 			.plain(ItemDefinition::shortdescription)
 
@@ -149,7 +149,7 @@ data class ItemDefinition(
 			.list(ItemDefinition::pickupQuestTemplates)
 
 			.plain(ItemDefinition::race)
-			.plain(ItemDefinition::displayImage)
+			.plain(ItemDefinition::displayImage, Starbound::readingFolderTransformerNullable)
 			.plain(ItemDefinition::displayoffset)
 			.plain(ItemDefinition::fossilSetName)
 			.plain(ItemDefinition::setIndex)
diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt
index 009098f5..b2b6f326 100644
--- a/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt
+++ b/src/main/kotlin/ru/dbotthepony/kstarbound/io/KConcreteTypeAdapter.kt
@@ -11,7 +11,6 @@ import com.google.gson.stream.JsonReader
 import com.google.gson.stream.JsonToken
 import com.google.gson.stream.JsonWriter
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
-import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
 import it.unimi.dsi.fastutil.objects.ObjectArraySet
 import org.apache.logging.log4j.LogManager
 import ru.dbotthepony.kstarbound.Starbound
@@ -302,10 +301,11 @@ class KConcreteTypeAdapter<T : Any> private constructor(
 					continue
 				}
 
-				val (field, adapter) = iterator.next()
+				val tuple = iterator.next()
+				val (field, adapter) = tuple
 
 				try {
-					readValues[fieldId] = adapter.read(reader)
+					readValues[fieldId] = (tuple.transformer as (Any?) -> Any?)(adapter.read(reader))
 					presentValues[fieldId] = true
 				} catch(err: Throwable) {
 					throw JsonSyntaxException("Exception reading field ${field.name} for ${bound.qualifiedName}", err)
@@ -330,10 +330,11 @@ class KConcreteTypeAdapter<T : Any> private constructor(
 
 					reader.skipValue()
 				} else {
-					val (field, adapter) = types[fieldId]
+					val tuple = types[fieldId]
+					val (field, adapter) = tuple
 
 					try {
-						readValues[fieldId] = adapter.read(reader)
+						readValues[fieldId] = (tuple.transformer as (Any?) -> Any?)(adapter.read(reader))
 						presentValues[fieldId] = true
 					} catch(err: Throwable) {
 						if (currentSymbolicName == null) {
@@ -462,29 +463,38 @@ class KConcreteTypeAdapter<T : Any> private constructor(
 		}
 
 		/**
-		 * Добавляет поле(я) без generic типов и без преобразователей
+		 * Добавляет поля без generic типов и без преобразователей
 		 */
 		@Suppress("unchecked_cast")
 		fun plain(vararg fields: KProperty1<T, *>): Builder<T> {
-			for (field in fields) {
-				val returnType = field.returnType
-				val classifier = returnType.classifier as? KClass<*> ?: throw ClassCastException("Unable to cast ${returnType.classifier} to KClass of property ${field.name}!")
+			for (field in fields)
+				plain(field)
 
-				if (classifier.isSuperclassOf(Float::class)) {
-					types.add(PackedProperty(field as KProperty1<T, Float>, TypeAdapters.FLOAT))
-				} else if (classifier.isSuperclassOf(Double::class)) {
-					types.add(PackedProperty(field as KProperty1<T, Double>, TypeAdapters.DOUBLE))
-				} else if (classifier.isSuperclassOf(Int::class)) {
-					types.add(PackedProperty(field as KProperty1<T, Int>, TypeAdapters.INTEGER))
-				} else if (classifier.isSuperclassOf(Long::class)) {
-					types.add(PackedProperty(field as KProperty1<T, Long>, TypeAdapters.LONG))
-				} else if (classifier.isSuperclassOf(String::class)) {
-					types.add(PackedProperty(field as KProperty1<T, String>, internedStringAdapter))
-				} else if (classifier.isSuperclassOf(Boolean::class)) {
-					types.add(PackedProperty(field as KProperty1<T, Boolean>, TypeAdapters.BOOLEAN))
-				} else {
-					types.add(PackedProperty(field, LazyTypeProvider(classifier.java) as TypeAdapter<Any?>))
-				}
+			return this
+		}
+
+		/**
+		 * Добавляет поле без generic типов, опционально с преобразователем
+		 */
+		@Suppress("unchecked_cast")
+		fun <In> plain(field: KProperty1<T, In>, transformer: (In) -> In = { it }): Builder<T> {
+			val returnType = field.returnType
+			val classifier = returnType.classifier as? KClass<*> ?: throw ClassCastException("Unable to cast ${returnType.classifier} to KClass of property ${field.name}!")
+
+			if (classifier.isSuperclassOf(Float::class)) {
+				types.add(PackedProperty(field as KProperty1<T, Float>, TypeAdapters.FLOAT, transformer = transformer as (Number) -> Number))
+			} else if (classifier.isSuperclassOf(Double::class)) {
+				types.add(PackedProperty(field as KProperty1<T, Double>, TypeAdapters.DOUBLE, transformer = transformer as (Number) -> Number))
+			} else if (classifier.isSuperclassOf(Int::class)) {
+				types.add(PackedProperty(field as KProperty1<T, Int>, TypeAdapters.INTEGER, transformer = transformer as (Number) -> Number))
+			} else if (classifier.isSuperclassOf(Long::class)) {
+				types.add(PackedProperty(field as KProperty1<T, Long>, TypeAdapters.LONG, transformer = transformer as (Number) -> Number))
+			} else if (classifier.isSuperclassOf(String::class)) {
+				types.add(PackedProperty(field as KProperty1<T, String>, internedStringAdapter, transformer = transformer as (String) -> String))
+			} else if (classifier.isSuperclassOf(Boolean::class)) {
+				types.add(PackedProperty(field as KProperty1<T, Boolean>, TypeAdapters.BOOLEAN, transformer = transformer as (Boolean) -> Boolean))
+			} else {
+				types.add(PackedProperty(field, LazyTypeProvider(classifier.java) as TypeAdapter<Any?>, transformer = transformer as (Any?) -> Any?))
 			}
 
 			return this