commit
cc687a8ea0
|
|
@ -138,6 +138,42 @@ public class PlayerSync {
|
|||
);
|
||||
}
|
||||
|
||||
// ----- NEW BLOCK: Schema Update for backpack_data and player_data -----
|
||||
// Check if backpack_data table has the 'uuid' column
|
||||
JDBCsetUp.QueryResult backpackColCheck = JDBCsetUp.executeQuery(
|
||||
"SELECT COUNT(*) AS colCount FROM INFORMATION_SCHEMA.COLUMNS " +
|
||||
"WHERE TABLE_SCHEMA = '" + dbName + "' " +
|
||||
"AND TABLE_NAME = 'backpack_data' " +
|
||||
"AND COLUMN_NAME = 'uuid';"
|
||||
);
|
||||
ResultSet rsBackpackCol = backpackColCheck.resultSet();
|
||||
if (rsBackpackCol.next() && rsBackpackCol.getInt("colCount") == 0) {
|
||||
LOGGER.info("Altering backpack_data table to add missing 'uuid' column.");
|
||||
// Add the missing column and set it as primary key.
|
||||
JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".backpack_data ADD COLUMN uuid CHAR(36) NOT NULL", 1);
|
||||
JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".backpack_data ADD PRIMARY KEY (uuid)", 1);
|
||||
}
|
||||
rsBackpackCol.close();
|
||||
|
||||
// Check and alter the 'advancements' column in player_data if necessary
|
||||
JDBCsetUp.QueryResult advColCheck = JDBCsetUp.executeQuery(
|
||||
"SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS " +
|
||||
"WHERE TABLE_SCHEMA = '" + dbName + "' " +
|
||||
"AND TABLE_NAME = 'player_data' " +
|
||||
"AND COLUMN_NAME = 'advancements';"
|
||||
);
|
||||
ResultSet rsAdvCol = advColCheck.resultSet();
|
||||
if (rsAdvCol.next()) {
|
||||
String dataType = rsAdvCol.getString("DATA_TYPE");
|
||||
if (!"mediumblob".equalsIgnoreCase(dataType)) {
|
||||
LOGGER.info("Altering player_data table to modify 'advancements' column to MEDIUMBLOB.");
|
||||
JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".player_data MODIFY COLUMN advancements MEDIUMBLOB", 1);
|
||||
}
|
||||
}
|
||||
rsAdvCol.close();
|
||||
// ----- END NEW BLOCK -----
|
||||
|
||||
LOGGER.info("PlayerSync is ready!");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package vip.fubuki.playersync.sync;
|
|||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
|
|
@ -15,6 +14,11 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import top.theillusivec4.curios.api.CuriosApi;
|
||||
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
|
||||
import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler;
|
||||
import top.theillusivec4.curios.api.type.inventory.IDynamicStackHandler;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -23,43 +27,74 @@ import static vip.fubuki.playersync.sync.VanillaSync.deserializeString;
|
|||
|
||||
public class ModsSupport {
|
||||
|
||||
public void onPlayerJoin(Player player) throws SQLException {
|
||||
/**
|
||||
* Restores the Curios inventory for a player.
|
||||
* The saved data is stored as a flat map with composite keys ("slotType:index").
|
||||
*/
|
||||
public void onPlayerJoin(net.minecraft.world.entity.player.Player player) throws SQLException {
|
||||
if (ModList.get().isLoaded("curios")) {
|
||||
/*
|
||||
Curios Support
|
||||
*/
|
||||
LazyOptional<top.theillusivec4.curios.api.type.capability.ICuriosItemHandler> itemHandler = top.theillusivec4.curios.api.CuriosApi.getCuriosInventory(player);
|
||||
JDBCsetUp.QueryResult queryResult = JDBCsetUp.executeQuery("SELECT curios_item FROM curios WHERE uuid = '"+player.getUUID()+"'");
|
||||
ResultSet resultSet = queryResult.resultSet();
|
||||
if(resultSet.next()) {
|
||||
String curios_data=resultSet.getString("curios_item");
|
||||
if(curios_data.length()<=2)
|
||||
// Obtain the handler from the API.
|
||||
LazyOptional<ICuriosItemHandler> handlerOpt = CuriosApi.getCuriosInventory(player);
|
||||
JDBCsetUp.QueryResult qr = JDBCsetUp.executeQuery("SELECT curios_item FROM curios WHERE uuid = '" + player.getUUID() + "'");
|
||||
ResultSet rs = qr.resultSet();
|
||||
if (rs.next()) {
|
||||
String curiosData = rs.getString("curios_item");
|
||||
if (curiosData.length() <= 2) {
|
||||
rs.close();
|
||||
qr.connection().close();
|
||||
return;
|
||||
itemHandler.ifPresent(handler ->{
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
handler.getEquippedCurios().setStackInSlot(i,ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
// Parse the stored data (assumes a simple Map.toString() format: "{key=value, key2=value2, ...}")
|
||||
Map<String, String> storedMap = LocalJsonUtil.StringToMap(curiosData);
|
||||
|
||||
// Clear current Curios slots to avoid conflicts.
|
||||
handlerOpt.ifPresent(handler -> {
|
||||
handler.getCurios().forEach((slotType, stacksHandler) -> {
|
||||
// Use the dynamic stack handler to clear slots.
|
||||
IDynamicStackHandler dynStacks = stacksHandler.getStacks();
|
||||
for (int i = 0; i < dynStacks.getSlots(); i++) {
|
||||
dynStacks.setStackInSlot(i, ItemStack.EMPTY);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Map<Integer, String> curios = LocalJsonUtil.StringToEntryMap(curios_data);
|
||||
itemHandler.ifPresent(handler -> {
|
||||
handler.reset();
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
// Restore each saved item.
|
||||
handlerOpt.ifPresent(handler -> {
|
||||
for (Map.Entry<String, String> entry : storedMap.entrySet()) {
|
||||
String compositeKey = entry.getKey(); // Expected format: "slotType:index"
|
||||
String[] parts = compositeKey.split(":");
|
||||
if (parts.length != 2) {
|
||||
continue;
|
||||
}
|
||||
String slotType = parts[0];
|
||||
int slotIndex;
|
||||
try {
|
||||
if (curios.get(i) != null){
|
||||
handler.getEquippedCurios().setStackInSlot(i, ItemStack.of(NbtUtils.snbtToStructure(curios.get(i).replace("|",",").replace("^","\"").replace("<","{").replace(">","}").replace("~", "'"))));
|
||||
slotIndex = Integer.parseInt(parts[1]);
|
||||
} catch (NumberFormatException ex) {
|
||||
continue;
|
||||
}
|
||||
String serialized = entry.getValue();
|
||||
try {
|
||||
String nbtString = VanillaSync.deserializeString(serialized);
|
||||
CompoundTag tag = NbtUtils.snbtToStructure(nbtString);
|
||||
ItemStack stack = ItemStack.of(tag);
|
||||
if (handler.getCurios().containsKey(slotType)) {
|
||||
ICurioStacksHandler stacksHandler = handler.getCurios().get(slotType);
|
||||
IDynamicStackHandler dynStacks = stacksHandler.getStacks();
|
||||
if (slotIndex < dynStacks.getSlots()) {
|
||||
dynStacks.setStackInSlot(slotIndex, stack);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (CommandSyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new RuntimeException("Error deserializing Curio data for key " + compositeKey, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
resultSet.close();
|
||||
queryResult.connection().close();
|
||||
}else{
|
||||
StoreCurios(player,true);
|
||||
rs.close();
|
||||
qr.connection().close();
|
||||
} else {
|
||||
// No stored data; perform an initial save.
|
||||
StoreCurios(player, true);
|
||||
}
|
||||
}
|
||||
if(ModList.get().isLoaded("sophisticatedbackpacks")){
|
||||
|
|
@ -100,27 +135,39 @@ public class ModsSupport {
|
|||
}
|
||||
}
|
||||
|
||||
public void onPlayerLeave(Player player) throws SQLException {
|
||||
/**
|
||||
* Saves the current Curios inventory for a player.
|
||||
* It builds a flat map keyed by "slotType:index" using the dynamic stack handler.
|
||||
*/
|
||||
public void onPlayerLeave(net.minecraft.world.entity.player.Player player) throws SQLException {
|
||||
if (ModList.get().isLoaded("curios")) {
|
||||
StoreCurios(player, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void StoreCurios(Player player,boolean init) throws SQLException {
|
||||
LazyOptional<top.theillusivec4.curios.api.type.capability.ICuriosItemHandler> itemHandler = top.theillusivec4.curios.api.CuriosApi.getCuriosInventory(player);
|
||||
Map<Integer, String> curios = new HashMap<>();
|
||||
itemHandler.ifPresent(handler -> {
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
if (!handler.getEquippedCurios().getStackInSlot(i).isEmpty()) {
|
||||
String sNBT= VanillaSync.serialize(handler.getEquippedCurios().getStackInSlot(i).serializeNBT().toString());
|
||||
curios.put(i, sNBT);
|
||||
public void StoreCurios(net.minecraft.world.entity.player.Player player, boolean init) throws SQLException {
|
||||
LazyOptional<ICuriosItemHandler> handlerOpt = CuriosApi.getCuriosInventory(player);
|
||||
Map<String, String> flatMap = new HashMap<>();
|
||||
|
||||
handlerOpt.ifPresent(handler -> {
|
||||
// Iterate over each slot type.
|
||||
handler.getCurios().forEach((slotType, stacksHandler) -> {
|
||||
IDynamicStackHandler dynStacks = stacksHandler.getStacks();
|
||||
for (int i = 0; i < dynStacks.getSlots(); i++) {
|
||||
ItemStack stack = dynStacks.getStackInSlot(i);
|
||||
if (!stack.isEmpty()) {
|
||||
String serialized = VanillaSync.serialize(stack.serializeNBT().toString());
|
||||
flatMap.put(slotType + ":" + i, serialized);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if(init) {
|
||||
JDBCsetUp.executeUpdate("INSERT INTO curios (uuid,curios_item) VALUES ('"+player.getUUID()+"','"+ curios+"')");
|
||||
|
||||
String serializedData = flatMap.toString();
|
||||
if (init) {
|
||||
JDBCsetUp.executeUpdate("INSERT INTO curios (uuid,curios_item) VALUES ('" + player.getUUID() + "', '" + serializedData + "')");
|
||||
} else {
|
||||
JDBCsetUp.executeUpdate("UPDATE curios SET curios_item = '"+ curios+"' WHERE uuid = '"+player.getUUID()+"'");
|
||||
JDBCsetUp.executeUpdate("UPDATE curios SET curios_item = '" + serializedData + "' WHERE uuid = '" + player.getUUID() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.util.concurrent.Executors;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
|
|
@ -31,6 +32,7 @@ import net.minecraftforge.event.entity.player.PlayerEvent;
|
|||
import net.minecraftforge.event.server.ServerStoppedEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
import vip.fubuki.playersync.PlayerSync;
|
||||
import vip.fubuki.playersync.config.JdbcConfig;
|
||||
import vip.fubuki.playersync.sync.ModsSupport;
|
||||
|
|
@ -369,4 +371,44 @@ public class VanillaSync {
|
|||
JDBCsetUp.executeUpdate("UPDATE server_info SET last_update =" + current + " WHERE id= " + JdbcConfig.SERVER_ID.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// New fields for auto-save
|
||||
private static int autoSaveTickCounter = 0;
|
||||
private static final int AUTO_SAVE_INTERVAL_TICKS = 1200; // Every Minute
|
||||
|
||||
//AutoSave
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
// Run at the end phase to avoid interfering with game logic
|
||||
if (event.phase == TickEvent.Phase.END) {
|
||||
autoSaveTickCounter++;
|
||||
if (autoSaveTickCounter >= AUTO_SAVE_INTERVAL_TICKS) {
|
||||
autoSaveTickCounter = 0;
|
||||
// Retrieve the current server instance
|
||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
||||
if (server != null) {
|
||||
// Iterate through all online players
|
||||
for (ServerPlayer player : server.getPlayerList().getPlayers()) {
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
// Call the same store method used in logout and file save events.
|
||||
store(player, false, server.isDedicatedServer());
|
||||
} catch (Exception e) {
|
||||
PlayerSync.LOGGER.error("Error auto-saving player " + player.getUUID(), e);
|
||||
}
|
||||
});
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
new ModsSupport().StoreCurios(player, false);
|
||||
} catch (SQLException e) {
|
||||
PlayerSync.LOGGER.error("Error auto-saving Curios data for player " + player.getUUID(), e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user