Skip to content

Commit a0189f7

Browse files
committed
MapDownloader module
1 parent 1445c38 commit a0189f7

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.module.modules.player
19+
20+
import com.lambda.event.events.TickEvent
21+
import com.lambda.event.listener.SafeListener.Companion.listen
22+
import com.lambda.module.Module
23+
import com.lambda.module.tag.ModuleTag
24+
import com.lambda.util.FolderRegister
25+
import com.lambda.util.FolderRegister.locationBoundDirectory
26+
import com.lambda.util.StringUtils.hash
27+
import com.lambda.util.player.SlotUtils.combined
28+
import com.lambda.util.world.entitySearch
29+
import net.minecraft.block.MapColor
30+
import net.minecraft.entity.decoration.ItemFrameEntity
31+
import net.minecraft.item.FilledMapItem
32+
import net.minecraft.item.map.MapState
33+
import java.awt.image.BufferedImage
34+
import javax.imageio.ImageIO
35+
36+
object MapDownloader : Module(
37+
name = "MapDownloader",
38+
description = "Save map data to your computer",
39+
defaultTags = setOf(ModuleTag.PLAYER),
40+
) {
41+
init {
42+
listen<TickEvent.Pre> {
43+
val mapStates = entitySearch<ItemFrameEntity>(128.0)
44+
.mapNotNull { FilledMapItem.getMapState(it.heldItemStack, world) } +
45+
player.combined.mapNotNull { FilledMapItem.getMapState(it, world) }
46+
47+
mapStates.forEach { map ->
48+
val name = map.hash
49+
val image = map.toBufferedImage()
50+
51+
val file = FolderRegister.maps.toFile().locationBoundDirectory().resolve("$name.png")
52+
if (file.exists()) return@listen
53+
54+
ImageIO.write(image, "png", file)
55+
}
56+
}
57+
}
58+
59+
private val MapState.hash: String
60+
get() = colors.hash("SHA-256")
61+
62+
fun MapState.toBufferedImage(): BufferedImage {
63+
val image = BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB)
64+
65+
repeat(128) { x ->
66+
repeat(128) { y ->
67+
val index = colors[x + y * 128].toInt()
68+
val color = MapColor.getRenderColor(index)
69+
70+
val b = (color shr 16) and 0xFF
71+
val g = (color shr 8) and 0xFF
72+
val r = (color shr 0) and 0xFF
73+
74+
val argb = -0x1000000 or (r shl 16) or (g shl 8) or (b shl 0)
75+
image.setRGB(x, y, argb)
76+
}
77+
}
78+
79+
return image
80+
}
81+
}

common/src/main/kotlin/com/lambda/util/FolderRegister.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ object FolderRegister : Loadable {
4848
val replay: Path = lambda.resolve("replay")
4949
val cache: Path = lambda.resolve("cache")
5050
val structure: Path = lambda.resolve("structure")
51+
val maps: Path = lambda.resolve("maps")
5152

5253
override fun load(): String {
53-
val folders = listOf(lambda, config, packetLogs, replay, cache, structure)
54+
val folders = listOf(lambda, config, packetLogs, replay, cache, structure, maps)
5455
val createdFolders = folders.mapNotNull {
5556
if (it.notExists()) {
5657
it.createDirectories()

common/src/main/kotlin/com/lambda/util/StringUtils.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package com.lambda.util
1919

20+
import java.security.MessageDigest
21+
2022
object StringUtils {
2123
/**
2224
* Returns a sanitized file path for both Unix and Linux systems
@@ -89,4 +91,32 @@ object StringUtils {
8991

9092
return cost[len0 - 1]
9193
}
94+
95+
/**
96+
* See [MessageDigest section](https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms) of the Java Security Standard Algorithm Names Specification
97+
*
98+
* @receiver The string to hash
99+
* @param algorithm The algorithm instance to use
100+
*
101+
* @return The string representation of the hash
102+
*/
103+
fun String.hash(algorithm: String): String =
104+
MessageDigest
105+
.getInstance(algorithm)
106+
.digest(toByteArray())
107+
.joinToString(separator = "") { "%02x".format(it) }
108+
109+
/**
110+
* See [MessageDigest section](https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#messagedigest-algorithms) of the Java Security Standard Algorithm Names Specification
111+
*
112+
* @receiver The byte array to hash
113+
* @param algorithm The algorithm instance to use
114+
*
115+
* @return The string representation of the hash
116+
*/
117+
fun ByteArray.hash(algorithm: String): String =
118+
MessageDigest
119+
.getInstance(algorithm)
120+
.digest(this)
121+
.joinToString(separator = "") { "%02x".format(it) }
92122
}

0 commit comments

Comments
 (0)