Skip to content

Commit

Permalink
Rework database system to serialize the entire item stack instead of …
Browse files Browse the repository at this point in the history
…just the identifier and count. Show the item stack when hovering over the item's identifier in the log. Include new mod banner made by @SwanLab
  • Loading branch information
ArkoSammy12 committed Jul 26, 2024
1 parent e230e65 commit f04a9ce
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 58 deletions.
Binary file added media/publicEnderChestBanner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package xd.arkosammy.publicenderchest.inventory

import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.component.ComponentMap
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventories
import net.minecraft.inventory.Inventory
Expand All @@ -17,7 +16,6 @@ import xd.arkosammy.publicenderchest.config.ConfigSettings
import xd.arkosammy.publicenderchest.logging.InventoryInteractionLog
import xd.arkosammy.publicenderchest.logging.InventoryInteractionType
import xd.arkosammy.publicenderchest.serialization.SerializedItemStack
import kotlin.math.abs

class PublicInventory(private val itemStacks: DefaultedList<ItemStack> = DefaultedList.ofSize(SLOT_SIZE, ItemStack.EMPTY)) : Inventory {

Expand Down Expand Up @@ -114,10 +112,10 @@ class PublicInventory(private val itemStacks: DefaultedList<ItemStack> = Default
if (ItemStack.areItemsAndComponentsEqual(previousStack, currentStack)) {
val countDifference: Int = currentStack.count - previousStack.count
if (countDifference > 0) {
val insertAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_INSERT, player, currentStack.copy(), abs(countDifference))
val insertAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_INSERT, player, currentStack, countDifference)
PublicEnderChest.DATABASE_MANAGER.logInventoryInteraction(insertAction, player.server)
} else if (countDifference < 0) {
val removeAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_REMOVE, player, currentStack.copy(), abs(countDifference))
val removeAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_REMOVE, player, currentStack, countDifference)
PublicEnderChest.DATABASE_MANAGER.logInventoryInteraction(removeAction, player.server)
}
continue
Expand All @@ -128,11 +126,11 @@ class PublicInventory(private val itemStacks: DefaultedList<ItemStack> = Default
// so a complete replacement of the stack has occurred in this slot.
// Log a removal and insertion based on the previous and current items stacks for the slot.
if (!previousStack.isEmpty) {
val removeAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_REMOVE, player, previousStack.copy(), previousStack.count)
val removeAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_REMOVE, player, previousStack)
PublicEnderChest.DATABASE_MANAGER.logInventoryInteraction(removeAction, player.server)
}
if (!currentStack.isEmpty) {
val insertAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_INSERT, player, currentStack.copy(), currentStack.count)
val insertAction: InventoryInteractionLog = InventoryInteractionLog.of(InventoryInteractionType.ITEM_INSERT, player, currentStack)
PublicEnderChest.DATABASE_MANAGER.logInventoryInteraction(insertAction, player.server)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package xd.arkosammy.publicenderchest.logging

import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.JsonParser
import com.mojang.serialization.DataResult
import com.mojang.serialization.JsonOps
import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey
import net.minecraft.server.MinecraftServer
import net.minecraft.util.Identifier
import xd.arkosammy.publicenderchest.PublicEnderChest
Expand All @@ -8,6 +17,7 @@ import java.sql.DriverManager
import java.sql.Statement
import java.sql.Timestamp
import java.time.LocalDateTime
import java.util.*

class InventoryDatabaseManager(server: MinecraftServer) {

Expand All @@ -18,10 +28,9 @@ class InventoryDatabaseManager(server: MinecraftServer) {
id INTEGER PRIMARY KEY AUTOINCREMENT,
player TEXT,
uuid TEXT,
item TEXT,
quantity INTEGER,
itemStack TEXT,
timestamp TIMESTAMP,
interaction_type TEXT
interactionType TEXT
);"""

val url: String = getDatabaseFileUrl(server)
Expand Down Expand Up @@ -67,18 +76,13 @@ class InventoryDatabaseManager(server: MinecraftServer) {
while (resultSet.next()) {
val playerName: String = resultSet.getString("player")
val uuid: String = resultSet.getString("uuid")
val itemString: String = resultSet.getString("item")
val quantity: Int = resultSet.getInt("quantity")
val itemString: String = resultSet.getString("itemStack")
val timeStamp: LocalDateTime = resultSet.getTimestamp("timestamp").toLocalDateTime()
val interactionType: String = resultSet.getString("interaction_type")
val itemId: Identifier? = Identifier.tryParse(itemString)
if (itemId == null) {
PublicEnderChest.LOGGER.error("Could not retrieve database entry due to invalid Item identifier: \"${itemString}\"")
continue
}
val interactionType: String = resultSet.getString("interactionType")
val itemStack: ItemStack = getItemStackFromJsonString(itemString) ?: continue
val inventoryInteractionLog: InventoryInteractionLog = when (interactionType) {
InventoryInteractionType.ITEM_REMOVE.asString() -> ItemRemoveLog(playerName, uuid, itemId, quantity, timeStamp)
InventoryInteractionType.ITEM_INSERT.asString() -> ItemInsertLog(playerName, uuid, itemId, quantity, timeStamp)
InventoryInteractionType.ITEM_REMOVE.asString() -> ItemRemoveLog(playerName, uuid, itemStack, timeStamp)
InventoryInteractionType.ITEM_INSERT.asString() -> ItemInsertLog(playerName, uuid, itemStack, timeStamp)
else -> continue
}
results.add(inventoryInteractionLog)
Expand Down Expand Up @@ -121,3 +125,46 @@ class InventoryDatabaseManager(server: MinecraftServer) {

}

fun ItemStack.getJsonString() : String? {
val encodedStack: DataResult<JsonElement> = ItemStack.CODEC.encodeStart(JsonOps.COMPRESSED, this)
val jsonOptional: Optional<JsonElement> = encodedStack.resultOrPartial { e ->
PublicEnderChest.LOGGER.error("Error attempting to log Item stack data: $e")
}
if (jsonOptional.isEmpty) {
return null
}
val jsonElement: JsonElement = jsonOptional.get()
val gson = Gson()
return gson.toJson(jsonElement)
}

fun getItemStackFromJsonString(jsonString: String) : ItemStack? {
try {
val jsonElement: JsonElement = JsonParser.parseString(jsonString)
val decodedStack: DataResult<ItemStack> = ItemStack.CODEC.parse(JsonOps.COMPRESSED, jsonElement)
val itemStackOptional: Optional<ItemStack> = decodedStack.resultOrPartial { e ->
PublicEnderChest.LOGGER.error("Error attempting to read Item stack from database: $e")
}
if (itemStackOptional.isEmpty) {
return null
}
return itemStackOptional.get()
} catch (e: Exception) {
PublicEnderChest.LOGGER.error("Error attempting to read Item stack from database: $e")
return null
}

}

fun ItemStack.getIdentifier() : Identifier {
val itemStackRegistryKey: RegistryKey<Item>? = Registries.ITEM.getKey(this.item).orElse(null)
val itemStackId: Identifier = if (itemStackRegistryKey == null) {
PublicEnderChest.LOGGER.error("Error logging Public Ender Chest interaction: Unknown Item \"$item\"")
Identifier.ofVanilla("unknown_item_identifier")
} else {
itemStackRegistryKey.value
}
return itemStackId
}


Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
package xd.arkosammy.publicenderchest.logging

import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.text.MutableText
import net.minecraft.util.Identifier
import xd.arkosammy.publicenderchest.PublicEnderChest
import java.sql.Connection
import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.math.abs

sealed interface InventoryInteractionLog {

val playerName: String

val uuid: String

val itemStackId: Identifier

val quantity: Int
val itemStack: ItemStack

val timestamp: LocalDateTime

Expand All @@ -33,21 +27,13 @@ sealed interface InventoryInteractionLog {

val DTF: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy, hh:mm:ss a")

fun of(inventoryInteractionType: InventoryInteractionType, player: ServerPlayerEntity, itemStack: ItemStack, quantity: Int) : InventoryInteractionLog {
fun of(inventoryInteractionType: InventoryInteractionType, player: ServerPlayerEntity, itemStack: ItemStack, count: Int = itemStack.count) : InventoryInteractionLog {
val now: LocalDateTime = LocalDateTime.now()
val playerName: String = player.name.string
val uuid: String = player.uuid.toString()
val item: Item = itemStack.item
val itemStackRegistryKey: RegistryKey<Item>? = Registries.ITEM.getKey(item).orElse(null)
val itemStackId: Identifier = if (itemStackRegistryKey == null) {
PublicEnderChest.LOGGER.error("Error logging Public Ender Chest interaction: Unknown Item \"$item\"")
Identifier.ofVanilla("unknown_item")
} else {
itemStackRegistryKey.value
}
return when (inventoryInteractionType) {
InventoryInteractionType.ITEM_REMOVE -> ItemRemoveLog(playerName, uuid, itemStackId, quantity, now)
InventoryInteractionType.ITEM_INSERT -> ItemInsertLog(playerName, uuid, itemStackId, quantity, now)
InventoryInteractionType.ITEM_REMOVE -> ItemRemoveLog(playerName, uuid, itemStack.copy().also { s -> s.count = abs(count) }, now)
InventoryInteractionType.ITEM_INSERT -> ItemInsertLog(playerName, uuid, itemStack.copy().also { s -> s.count = abs(count) }, now)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package xd.arkosammy.publicenderchest.logging

import net.minecraft.item.ItemStack
import net.minecraft.text.*
import net.minecraft.util.Formatting
import net.minecraft.util.Identifier
import java.sql.Connection
import java.sql.Timestamp
import java.time.Duration
Expand All @@ -11,8 +11,7 @@ import java.time.LocalDateTime
class ItemInsertLog(
override val playerName: String,
override val uuid: String,
override val itemStackId: Identifier,
override val quantity: Int,
override val itemStack: ItemStack,
override val timestamp: LocalDateTime
) : InventoryInteractionLog {

Expand All @@ -26,22 +25,23 @@ class ItemInsertLog(
.formatted(Formatting.AQUA)
val interactedInventoryText: MutableText = Text.literal("inserted ")
.formatted(Formatting.GOLD)
val quantityText: MutableText = Text.literal("$quantity ")
val quantityText: MutableText = Text.literal("${itemStack.count} ")
.formatted(Formatting.BLUE)
val itemText: MutableText = Text.literal("$itemStackId")
val itemText: MutableText = Text.literal("${itemStack.getIdentifier()}")
.setStyle(Style.EMPTY.withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_ITEM, HoverEvent.ItemStackContent(this.itemStack))))
.formatted(Formatting.GREEN)

return Text.empty().append(timestampText).append(playerNameText).append(interactedInventoryText).append(quantityText).append(itemText)
}

override fun consumeDbConnection(connection: Connection) {
connection.prepareStatement("INSERT INTO ${InventoryDatabaseManager.MAIN_TABLE_NAME} (player, uuid, item, quantity, timestamp, interaction_type) VALUES (?, ?, ?, ?, ?, ?)").use { statement ->
val itemStackJson: String = this.itemStack.getJsonString() ?: return
connection.prepareStatement("INSERT INTO ${InventoryDatabaseManager.MAIN_TABLE_NAME} (player, uuid, itemStack, timestamp, interactionType) VALUES (?, ?, ?, ?, ?)").use { statement ->
statement.setString(1, playerName)
statement.setString(2, uuid)
statement.setString(3, itemStackId.toString())
statement.setInt(4, quantity)
statement.setTimestamp(5, Timestamp.valueOf(timestamp))
statement.setString(6, InventoryInteractionType.ITEM_INSERT.asString())
statement.setString(3, itemStackJson)
statement.setTimestamp(4, Timestamp.valueOf(timestamp))
statement.setString(5, InventoryInteractionType.ITEM_INSERT.asString())
statement.executeUpdate()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package xd.arkosammy.publicenderchest.logging

import net.minecraft.item.ItemStack
import net.minecraft.text.*
import net.minecraft.util.Formatting
import net.minecraft.util.Identifier
import java.sql.Connection
import java.sql.Timestamp
import java.time.Duration
Expand All @@ -11,8 +11,7 @@ import java.time.LocalDateTime
class ItemRemoveLog(
override val playerName: String,
override val uuid: String,
override val itemStackId: Identifier,
override val quantity: Int,
override val itemStack: ItemStack,
override val timestamp: LocalDateTime
) : InventoryInteractionLog {

Expand All @@ -26,22 +25,23 @@ class ItemRemoveLog(
.formatted(Formatting.AQUA)
val interactedInventoryText: MutableText = Text.literal("removed ")
.formatted(Formatting.YELLOW)
val quantityText: MutableText = Text.literal("$quantity ")
val quantityText: MutableText = Text.literal("${itemStack.count} ")
.formatted(Formatting.BLUE)
val itemText: MutableText = Text.literal("$itemStackId")
val itemText: MutableText = Text.literal("${itemStack.getIdentifier()}")
.setStyle(Style.EMPTY.withHoverEvent(HoverEvent(HoverEvent.Action.SHOW_ITEM, HoverEvent.ItemStackContent(this.itemStack))))
.formatted(Formatting.GREEN)

return Text.empty().append(timestampText).append(playerNameText).append(interactedInventoryText).append(quantityText).append(itemText)
}

override fun consumeDbConnection(connection: Connection) {
connection.prepareStatement("INSERT INTO ${InventoryDatabaseManager.MAIN_TABLE_NAME} (player, uuid, item, quantity, timestamp, interaction_type) VALUES (?, ?, ?, ?, ?, ?)").use { statement ->
val itemStackJson: String = this.itemStack.getJsonString() ?: return
connection.prepareStatement("INSERT INTO ${InventoryDatabaseManager.MAIN_TABLE_NAME} (player, uuid, itemStack, timestamp, interactionType) VALUES (?, ?, ?, ?, ?)").use { statement ->
statement.setString(1, playerName)
statement.setString(2, uuid)
statement.setString(3, itemStackId.toString())
statement.setInt(4, quantity)
statement.setTimestamp(5, Timestamp.valueOf(timestamp))
statement.setString(6, InventoryInteractionType.ITEM_REMOVE.asString())
statement.setString(3, itemStackJson)
statement.setTimestamp(4, Timestamp.valueOf(timestamp))
statement.setString(5, InventoryInteractionType.ITEM_REMOVE.asString())
statement.executeUpdate()
}
}
Expand Down

0 comments on commit f04a9ce

Please sign in to comment.