190 lines
8.3 KiB
Java
190 lines
8.3 KiB
Java
package vip.fubuki.playersync;
|
|
|
|
import com.mojang.logging.LogUtils;
|
|
import com.mysql.cj.jdbc.Driver;
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.event.server.ServerStartingEvent;
|
|
import net.minecraftforge.eventbus.api.IEventBus;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.ModList;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
import net.minecraftforge.fml.config.ModConfig;
|
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
|
import org.slf4j.Logger;
|
|
import vip.fubuki.playersync.config.JdbcConfig;
|
|
import vip.fubuki.playersync.sync.ChatSync;
|
|
import vip.fubuki.playersync.sync.VanillaSync;
|
|
import vip.fubuki.playersync.util.JDBCsetUp;
|
|
|
|
import java.sql.*;
|
|
|
|
@Mod(PlayerSync.MODID)
|
|
public class PlayerSync {
|
|
public static final String MODID = "playersync";
|
|
public static final Logger LOGGER = LogUtils.getLogger();
|
|
|
|
public PlayerSync(FMLJavaModLoadingContext context) {
|
|
IEventBus modEventBus = context.getModEventBus();
|
|
context.registerConfig(ModConfig.Type.COMMON, JdbcConfig.COMMON_CONFIG);
|
|
modEventBus.addListener(this::commonSetup);
|
|
MinecraftForge.EVENT_BUS.register(this);
|
|
}
|
|
|
|
private void commonSetup(final FMLCommonSetupEvent event) {
|
|
// JDBC driver auto-detection is broken in Forge as of v47.4.0
|
|
// We need to register the driver manually
|
|
try {
|
|
DriverManager.registerDriver(new Driver());
|
|
} catch (SQLException e) {
|
|
LOGGER.error("Unable to register JDBC MySQL driver", e);
|
|
}
|
|
|
|
VanillaSync.register();
|
|
event.enqueueWork(() -> {
|
|
// read SYNC_CHAT only within the enqueueWork to reliably get the real
|
|
// config value and not its default value.
|
|
if (JdbcConfig.SYNC_CHAT.get()) {
|
|
LOGGER.info("Chat sync enabled.");
|
|
ChatSync.register();
|
|
}
|
|
});
|
|
}
|
|
|
|
@SubscribeEvent
|
|
public void onServerStarting(ServerStartingEvent event) throws SQLException {
|
|
String dbName = JdbcConfig.DATABASE_NAME.get();
|
|
|
|
// Step 1: Create the database using a connection that does not select a database.
|
|
JDBCsetUp.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbName, 1);
|
|
|
|
// Step 2: Explicitly select the database on a connection obtained without default database.
|
|
try (Connection conn = JDBCsetUp.getConnection(false);
|
|
Statement st = conn.createStatement()) {
|
|
st.execute("USE " + dbName);
|
|
} catch (SQLException e) {
|
|
LOGGER.error("Error selecting database " + dbName, e);
|
|
throw e;
|
|
}
|
|
|
|
// Step 3: Create and alter tables using fully qualified names.
|
|
// Create player_data table
|
|
JDBCsetUp.executeUpdate(
|
|
"CREATE TABLE IF NOT EXISTS " + dbName + ".`player_data` (" +
|
|
"`uuid` char(36) NOT NULL," +
|
|
"`inventory` mediumblob," +
|
|
"`armor` blob," +
|
|
"`advancements` blob," +
|
|
"`enderchest` mediumblob," +
|
|
"`effects` blob," +
|
|
"`left_hand` blob," +
|
|
"`cursors` blob," +
|
|
"`xp` int DEFAULT NULL," +
|
|
"`food_level` int DEFAULT NULL," +
|
|
"`score` int DEFAULT NULL," +
|
|
"`health` int DEFAULT NULL," +
|
|
"`online` tinyint(1) DEFAULT NULL," +
|
|
"`last_server` int DEFAULT NULL," +
|
|
"PRIMARY KEY (`uuid`)" +
|
|
");"
|
|
);
|
|
|
|
// Check and alter player_data table if columns are missing
|
|
JDBCsetUp.QueryResult queryResult = JDBCsetUp.executeQuery(
|
|
"SELECT COUNT(*) AS column_count " +
|
|
"FROM INFORMATION_SCHEMA.COLUMNS " +
|
|
"WHERE TABLE_SCHEMA = '" + dbName + "' " +
|
|
"AND TABLE_NAME = 'player_data';"
|
|
);
|
|
ResultSet resultSet = queryResult.resultSet();
|
|
int columnCount = 0;
|
|
if (resultSet.next()) {
|
|
columnCount = resultSet.getInt("column_count");
|
|
}
|
|
if (columnCount < 14) {
|
|
JDBCsetUp.executeUpdate(
|
|
"ALTER TABLE " + dbName + ".player_data " +
|
|
"ADD COLUMN left_hand blob, " +
|
|
"ADD COLUMN cursors blob;"
|
|
);
|
|
}
|
|
|
|
// Create server_info table
|
|
JDBCsetUp.executeUpdate(
|
|
"CREATE TABLE IF NOT EXISTS " + dbName + ".server_info (" +
|
|
"`id` INT NOT NULL," +
|
|
"`enable` boolean NOT NULL," +
|
|
"`last_update` BIGINT NOT NULL," +
|
|
"PRIMARY KEY (`id`)" +
|
|
");"
|
|
);
|
|
long current = System.currentTimeMillis();
|
|
JDBCsetUp.executeUpdate(
|
|
"INSERT INTO " + dbName + ".server_info(id,enable,last_update) " +
|
|
"VALUES(" + JdbcConfig.SERVER_ID.get() + ",true," + current + ") " +
|
|
"ON DUPLICATE KEY UPDATE id= " + JdbcConfig.SERVER_ID.get() + ",enable = 1," +
|
|
"last_update=" + current + ";"
|
|
);
|
|
JDBCsetUp.executeUpdate(
|
|
"UPDATE " + dbName + ".server_info SET last_update=" + System.currentTimeMillis() +
|
|
" WHERE id='" + JdbcConfig.SERVER_ID.get() + "'"
|
|
);
|
|
|
|
// Create curios table if the Curios mod is loaded
|
|
if (ModList.get().isLoaded("curios")) {
|
|
JDBCsetUp.executeUpdate(
|
|
"CREATE TABLE IF NOT EXISTS " + dbName + ".curios (" +
|
|
"uuid CHAR(36) NOT NULL, curios_item BLOB, PRIMARY KEY (uuid)" +
|
|
")"
|
|
);
|
|
}
|
|
|
|
// Create backpack_data table
|
|
if (ModList.get().isLoaded("sophisticatedbackpacks")) {
|
|
JDBCsetUp.executeUpdate(
|
|
"CREATE TABLE IF NOT EXISTS " + dbName + ".backpack_data (" +
|
|
"uuid CHAR(36) NOT NULL, backpack_nbt MEDIUMBLOB, PRIMARY KEY (uuid)" +
|
|
");", 1
|
|
);
|
|
|
|
// 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();
|
|
backpackColCheck.connection().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!");
|
|
}
|
|
|
|
}
|