Skip to content

Commit 56449b9

Browse files
committed
So much containers.
1 parent ec2fb5f commit 56449b9

File tree

12 files changed

+416
-240
lines changed

12 files changed

+416
-240
lines changed

common/src/main/java/generations/gg/generations/core/generationscore/common/api/data/Codecs.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import com.mojang.serialization.DataResult;
88
import com.mojang.serialization.JsonOps;
99
import com.mojang.serialization.codecs.RecordCodecBuilder;
10+
import net.minecraft.network.chat.Component;
11+
import net.minecraft.network.chat.MutableComponent;
1012
import org.joml.Vector3d;
1113

1214
import java.lang.reflect.Type;

common/src/main/java/generations/gg/generations/core/generationscore/common/network/packets/GenerationsNetworkPacket.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import static com.cobblemon.mod.common.util.DistributionUtilsKt.server;
1616

17-
public interface GenerationsNetworkPacket<T> extends Encodable {
17+
public interface GenerationsNetworkPacket<T> extends Encodable {
1818
ResourceLocation getId();
1919
default void sendToPlayer(ServerPlayer player) {
2020
GenerationsNetwork.INSTANCE.sendPacketToPlayer(player, this);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package generations.gg.generations.core.generationscore.common.util
2+
3+
import com.cobblemon.mod.common.api.text.text
4+
import com.mojang.serialization.Codec
5+
import net.minecraft.ChatFormatting
6+
import net.minecraft.network.chat.MutableComponent
7+
import net.minecraft.network.chat.contents.PlainTextContents.LiteralContents
8+
import net.minecraft.network.codec.ByteBufCodecs
9+
import net.minecraft.network.codec.StreamCodec
10+
11+
val TEXT_CODEC = Codec.STRING.xmap(String::text) { it.serialize() }
12+
val TEXT_STREAM_CODEC = ByteBufCodecs.STRING_UTF8.map(String::text) { it.serialize() }
13+
14+
fun MutableComponent.serialize(): String {
15+
val result = StringBuilder()
16+
17+
// Iterate over the siblings of the component to build the formatted string.
18+
for (sibling in this.siblings) {
19+
if (sibling is MutableComponent) {
20+
result.append(extractFormattedText(sibling))
21+
} else {
22+
result.append(sibling.contents)
23+
}
24+
}
25+
26+
return result.toString()
27+
}
28+
29+
private fun extractFormattedText(component: MutableComponent): String {
30+
val formattedText = StringBuilder()
31+
val text = component.contents
32+
val style = component.style
33+
34+
// Append formatting codes based on the style.
35+
if (style.isBold) {
36+
formattedText.append("&l")
37+
}
38+
if (style.isItalic) {
39+
formattedText.append("&o")
40+
}
41+
if (style.isUnderlined) {
42+
formattedText.append("&n")
43+
}
44+
if (style.isStrikethrough) {
45+
formattedText.append("&m")
46+
}
47+
if (style.isObfuscated) {
48+
formattedText.append("&k")
49+
}
50+
51+
// Append color code if present.
52+
style.color?.let {
53+
val chatFormatting = it.let { ChatFormatting.getByName(it.serialize()) }
54+
55+
if(chatFormatting != null) formattedText.append(getColorCode(chatFormatting))
56+
}
57+
58+
formattedText.append(text)
59+
60+
// Append a reset code after the text to avoid style bleeding.
61+
formattedText.append("&r")
62+
63+
// Recursively process any child components.
64+
for (child in component.siblings) {
65+
if (child is MutableComponent) {
66+
formattedText.append(extractFormattedText(child))
67+
} else {
68+
formattedText.append((child.contents as LiteralContents).text)
69+
}
70+
}
71+
72+
return formattedText.toString()
73+
}
74+
75+
private fun getColorCode(color: ChatFormatting): String {
76+
return when (color) {
77+
ChatFormatting.BLACK -> "&0"
78+
ChatFormatting.DARK_BLUE -> "&1"
79+
ChatFormatting.DARK_GREEN -> "&2"
80+
ChatFormatting.DARK_AQUA -> "&3"
81+
ChatFormatting.DARK_RED -> "&4"
82+
ChatFormatting.DARK_PURPLE -> "&5"
83+
ChatFormatting.GOLD -> "&6"
84+
ChatFormatting.GRAY -> "&7"
85+
ChatFormatting.DARK_GRAY -> "&8"
86+
ChatFormatting.BLUE -> "&9"
87+
ChatFormatting.GREEN -> "&a"
88+
ChatFormatting.AQUA -> "&b"
89+
ChatFormatting.RED -> "&c"
90+
ChatFormatting.LIGHT_PURPLE -> "&d"
91+
ChatFormatting.YELLOW -> "&e"
92+
ChatFormatting.WHITE -> "&f"
93+
else -> "" // Return an empty string if the color is not recognized.
94+
}
95+
}

common/src/main/java/generations/gg/generations/core/generationscore/common/world/container/CalyrexSteedContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public Slot getSlot(Container container, int slot, int x, int y) {
2929
public void save(Player player) {
3030
var stack = getPlayerInventory().getItem(this.getLocked());
3131
if(stack.getItem() instanceof CalyrexSteedItem walkmon) {
32-
walkmon.save((GenericContainer.SimpleGenericContainer) getContainer(), stack);
32+
walkmon.save((CalyrexSteedItem.CarrotHolder) getContainer(), stack);
3333
}
3434
}
3535
}

common/src/main/java/generations/gg/generations/core/generationscore/common/world/container/GenericContainer.java

Lines changed: 0 additions & 97 deletions
This file was deleted.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package generations.gg.generations.core.generationscore.common.world.container
2+
3+
import com.cobblemon.mod.common.util.codec.CodecUtils
4+
import com.mojang.datafixers.util.Pair
5+
import com.mojang.serialization.Codec
6+
import com.mojang.serialization.DataResult
7+
import com.mojang.serialization.Dynamic
8+
import com.mojang.serialization.codecs.RecordCodecBuilder
9+
import dev.architectury.registry.menu.MenuRegistry
10+
import generations.gg.generations.core.generationscore.common.api.data.Codecs
11+
import generations.gg.generations.core.generationscore.common.util.TEXT_CODEC
12+
import generations.gg.generations.core.generationscore.common.util.TEXT_STREAM_CODEC
13+
import net.kyori.adventure.title.Title
14+
import net.minecraft.nbt.CompoundTag
15+
import net.minecraft.nbt.ListTag
16+
import net.minecraft.nbt.NbtOps
17+
import net.minecraft.nbt.Tag
18+
import net.minecraft.network.FriendlyByteBuf
19+
import net.minecraft.network.RegistryFriendlyByteBuf
20+
import net.minecraft.network.chat.Component
21+
import net.minecraft.network.chat.MutableComponent
22+
import net.minecraft.network.codec.ByteBufCodecs
23+
import net.minecraft.network.codec.StreamCodec
24+
import net.minecraft.server.level.ServerPlayer
25+
import net.minecraft.world.Container
26+
import net.minecraft.world.MenuProvider
27+
import net.minecraft.world.SimpleContainer
28+
import net.minecraft.world.entity.player.Inventory
29+
import net.minecraft.world.entity.player.Player
30+
import net.minecraft.world.inventory.AbstractContainerMenu
31+
import net.minecraft.world.item.ItemStack
32+
import org.apache.http.util.TextUtils
33+
import java.util.*
34+
import java.util.function.Function
35+
import kotlin.collections.ArrayList
36+
37+
interface GenericContainer : Container, MenuProvider {
38+
val width: Int
39+
val height: Int
40+
41+
fun openScreen(player: Player, lockedSlot: Int = -1) {
42+
if (!player.isLocalPlayer) MenuRegistry.openExtendedMenu(
43+
player as ServerPlayer,
44+
this
45+
) { byteBuf: FriendlyByteBuf ->
46+
byteBuf.writeVarInt(
47+
width
48+
).writeVarInt(height).writeVarInt(lockedSlot)
49+
}
50+
}
51+
52+
override fun createMenu(i: Int, arg: Inventory, arg2: Player): AbstractContainerMenu? {
53+
return GenericChestContainer(i, arg, this)
54+
}
55+
56+
open class SimpleGenericContainer @JvmOverloads constructor(
57+
override val width: Int,
58+
override val height: Int,
59+
items: List<Pair<Int, ItemStack>> = emptyList(),
60+
val title: MutableComponent = Component.empty()
61+
) :
62+
SimpleContainer(width * height), GenericContainer {
63+
64+
init {
65+
for (pair in items) {
66+
val j = pair.first
67+
if (j < this.containerSize) {
68+
this.setItem(j, pair.second)
69+
}
70+
}
71+
}
72+
73+
override fun getDisplayName(): Component {
74+
return title
75+
}
76+
77+
override fun fromTag(containerNbt: ListTag) {
78+
for (i in 0 until this.containerSize) {
79+
this.setItem(i, ItemStack.EMPTY)
80+
}
81+
82+
for (i in containerNbt.indices) {
83+
val compoundTag = containerNbt.getCompound(i)
84+
val j = compoundTag.getByte("Slot").toInt() and 255
85+
if (j < this.containerSize) {
86+
this.setItem(j, ItemStack.of(compoundTag))
87+
}
88+
}
89+
}
90+
91+
override fun createTag(): ListTag {
92+
val listTag = ListTag()
93+
94+
for (i in 0 until this.containerSize) {
95+
val itemStack = this.getItem(i)
96+
if (!itemStack.isEmpty) {
97+
val compoundTag = CompoundTag()
98+
compoundTag.putByte("Slot", i.toByte())
99+
itemStack.save(compoundTag)
100+
listTag.add(compoundTag)
101+
}
102+
}
103+
104+
return listTag
105+
}
106+
107+
public fun createItemList(): List<Pair<Int, ItemStack>> {
108+
val list = ArrayList<Pair<Int, ItemStack>>()
109+
110+
for (i in 0 until this.containerSize) {
111+
val itemStack = this.getItem(i)
112+
if (!itemStack.isEmpty) {
113+
list.add(Pair.of(i, itemStack))
114+
}
115+
}
116+
117+
return list
118+
}
119+
120+
companion object {
121+
val SLOT_PAIR_CODEC: Codec<Pair<Int, ItemStack>> = Codec.PASSTHROUGH.flatXmap(
122+
{ dynamic: Dynamic<*> ->
123+
val slot = dynamic["Slot"].asInt(-1)
124+
if (slot == -1) return@flatXmap DataResult.error<Pair<Int, ItemStack>> { "Slot can't be -1" }
125+
dynamic.decode(ItemStack.CODEC).map<ItemStack>({ it.first }).map { a: ItemStack -> Pair.of(slot, a) }
126+
},
127+
{ pair: Pair<Int, ItemStack> ->
128+
val tag = ItemStack.STRICT_CODEC.encodeStart(NbtOps.INSTANCE, pair.second).map { a -> a as CompoundTag }.getOrThrow()
129+
tag.putInt("Slot", pair.first)
130+
DataResult.success(Dynamic(NbtOps.INSTANCE, tag))
131+
})
132+
133+
val SLOT_PAIR_CODEC_STREAM: StreamCodec<RegistryFriendlyByteBuf, Pair<Int, ItemStack>> = StreamCodec.composite<RegistryFriendlyByteBuf, Pair<Int, ItemStack>, Int, ItemStack>(StreamCodec.of(ByteBufCodecs.INT::encode, ByteBufCodecs.INT::decode), { it.first }, ItemStack.STREAM_CODEC, { it.second }, { a, b -> Pair.of(a, b) })
134+
135+
val CODEC: Codec<SimpleGenericContainer> =
136+
RecordCodecBuilder.create { instance: RecordCodecBuilder.Instance<SimpleGenericContainer> ->
137+
instance.group(
138+
Codec.INT.fieldOf("width").forGetter { obj: SimpleGenericContainer -> obj.width },
139+
Codec.INT.fieldOf("height").forGetter { obj: SimpleGenericContainer -> obj.height },
140+
SLOT_PAIR_CODEC.listOf().optionalFieldOf("items", Collections.emptyList()).forGetter(SimpleGenericContainer::createItemList),
141+
TEXT_CODEC.optionalFieldOf("title", Component.empty()).forGetter({ it.title })
142+
).apply(
143+
instance
144+
) { width: Int, height: Int, items: List<Pair<Int, ItemStack>>, title: MutableComponent ->
145+
SimpleGenericContainer(
146+
width,
147+
height,
148+
items,
149+
title
150+
)
151+
}
152+
}
153+
154+
val STREAM_CODEC: StreamCodec<RegistryFriendlyByteBuf, SimpleGenericContainer> = StreamCodec.composite(
155+
ByteBufCodecs.INT,
156+
{ it.width },
157+
ByteBufCodecs.INT,
158+
{ it.height },
159+
SLOT_PAIR_CODEC_STREAM.apply(ByteBufCodecs.list()),
160+
{ it.createItemList() },
161+
TEXT_STREAM_CODEC,
162+
{ it.title },
163+
::SimpleGenericContainer)
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)