Starting to work on database ...
This commit is contained in:
samo_lego 2019-11-05 20:24:58 +01:00
parent b98f627875
commit b6c1ff6c3b
25 changed files with 237 additions and 204 deletions

View File

@ -7,9 +7,9 @@
3. To build run the following command:
```
./gradlew idea
./gradlew build
```
## License
This template is available under the MIT license.
This project is licensed under the MIT license.

View File

@ -22,18 +22,14 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway.
modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// jBCrypt library for password hashing
implementation "org.mindrot:jbcrypt:0.4"
// Argon2 library for password hashing
compile 'de.mkammerer:argon2-jvm-nolibs:2.6'
// IDEA stuff
implementation 'org.jetbrains:annotations:15.0'
// TextileLib by NerdHubMC for events
/*repositories {
maven {
name = "NerdHub Maven"
url = "https://maven.abusedmaster.xyz"
}
}
modCompile "com.github.NerdHubMC:TextileLib:${textilelib_version}"*/
// JDBC SQLite Driver
compile group:'org.xerial', name:'sqlite-jdbc', version:'3.8.11.2'
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.

View File

@ -14,6 +14,4 @@ org.gradle.jvmargs=-Xmx1G
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.3.2+build.218-1.14
# textilelib
textilelib_version=1.0.0-SNAPSHOT
fabric_version=0.3.2+build.218-1.14

View File

@ -5,14 +5,7 @@ pluginManagement {
name = 'Fabric'
url = 'https://maven.fabricmc.net/'
}
/*maven {
name = "NerdHub Maven"
url = "https://maven.abusedmaster.xyz"
}*/
gradlePluginPortal()
}
/*dependencies {
modCompile "com.github.NerdHubMC:TextileLib:${textilelib_version}"
}*/
}

View File

@ -1,18 +1,20 @@
package org.samo_lego.simpleauth;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.registry.CommandRegistry;
import net.minecraft.server.network.ServerPlayerEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.samo_lego.simpleauth.commands.LoginCommand;
import org.samo_lego.simpleauth.commands.RegisterCommand;
import org.samo_lego.simpleauth.database.SimpleAuthDatabase;
import org.samo_lego.simpleauth.event.AuthEventHandler;
import org.samo_lego.simpleauth.event.entity.player.BreakBlockCallback;
import org.samo_lego.simpleauth.event.entity.player.InteractBlockCallback;
import org.samo_lego.simpleauth.event.entity.player.InteractItemCallback;
import org.samo_lego.simpleauth.event.entity.player.PlayerJoinWorldCallback;
import org.samo_lego.simpleauth.event.block.BreakBlockCallback;
import org.samo_lego.simpleauth.event.block.InteractBlockCallback;
import org.samo_lego.simpleauth.event.entity.player.*;
import java.io.File;
import java.util.HashSet;
public class SimpleAuth implements DedicatedServerModInitializer {
@ -24,17 +26,28 @@ public class SimpleAuth implements DedicatedServerModInitializer {
LOGGER.info("SimpleAuth mod by samo_lego.");
LOGGER.info("This mod wouldn't exist without the awesome Fabric Community. TYSM guys!");
// Creating data directory (database is stored there)
File file = new File("./mods/SimpleAuth");
if (!file.exists() && !file.mkdir()) {
LOGGER.error("Error creating directory");
}
// Registering the commands
CommandRegistry.INSTANCE.register(false, dispatcher -> {
RegisterCommand.register(dispatcher);
LoginCommand.register(dispatcher);
RegisterCommand.registerCommand(dispatcher);
LoginCommand.registerCommand(dispatcher);
});
// Registering the events
InteractBlockCallback.EVENT.register(AuthEventHandler::onInteractBlock);
AttackBlockCallback.EVENT.register((playerEntity, world, hand, blockPos, direction) -> AuthEventHandler.interact(playerEntity));
InteractItemCallback.EVENT.register(AuthEventHandler::onInteractItem);
PlayerJoinWorldCallback.EVENT.register((world, player) -> AuthEventHandler.onPlayerJoin(player));
PlayerJoinServerCallback.EVENT.register(AuthEventHandler::onPlayerJoin);
PlayerLeaveServerCallback.EVENT.register(AuthEventHandler::onPlayerLeave);
BreakBlockCallback.EVENT.register((world, pos, state, player) -> AuthEventHandler.onBlockBroken(player));
// Connection to database
SimpleAuthDatabase.connect();
}
public static HashSet<ServerPlayerEntity> authenticatedUsers = new HashSet<>();

View File

@ -6,7 +6,6 @@ import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import org.mindrot.jbcrypt.BCrypt;
import org.samo_lego.simpleauth.SimpleAuth;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
@ -15,14 +14,17 @@ import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class LoginCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
private static LiteralText PleaseLogin = new LiteralText("§4Type /login <password> to login.");
private static LiteralText EnterPassword = new LiteralText("§6You need to enter your password.");
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
// Registering the "/login" command
dispatcher.register(literal("login")
.then(argument("password", word())
.executes(ctx -> login(ctx.getSource(), getString(ctx, "password")) // Tries to authenticate user
))
.executes(ctx -> {
System.out.println("You need to enter your password!");
ctx.getSource().getPlayer().sendMessage(EnterPassword);
return 1;
}));
}

View File

@ -4,7 +4,6 @@ import com.google.common.io.Files;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
import org.mindrot.jbcrypt.BCrypt;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static com.mojang.brigadier.arguments.StringArgumentType.word;
@ -13,8 +12,10 @@ import static net.minecraft.server.command.CommandManager.literal;
public class RegisterCommand {
private static LiteralText PleaseRegister = new LiteralText("§4Type /register <password> <password> to login.");
private static LiteralText EnterPassword = new LiteralText("§6You need to enter your password twice.");
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
// Registering the "/register" command
dispatcher.register(literal("register")
@ -23,7 +24,7 @@ public class RegisterCommand {
.executes( ctx -> register(ctx.getSource(), getString(ctx, "password"), getString(ctx, "passwordAgain")))
))
.executes(ctx -> {
System.out.println("You need to enter your password twice!");
ctx.getSource().getPlayer().sendMessage(EnterPassword);
return 1;
}));
}
@ -31,9 +32,7 @@ public class RegisterCommand {
// Registering our "register" command
private static int register(ServerCommandSource source, String pass1, String pass2) {
if(pass1.equals(pass2)){
// Hashing the password with help of jBCrypt library
String hashed = BCrypt.hashpw(pass1, BCrypt.gensalt());
// Hashing the password
source.getMinecraftServer().getPlayerManager().broadcastChatMessage(
new LiteralText(source.getName() + ", you have registered successfully!"),
false

View File

@ -0,0 +1,46 @@
package org.samo_lego.simpleauth.database;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
*
* @author sqlitetutorial.net
*/
public class SimpleAuthDatabase {
public static void connect() {
Connection conn = null;
try {
// db parameters
String url = "jdbc:sqlite:mods/SimpleAuth/players.db";
// create a connection to the database
conn = DriverManager.getConnection(url);
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
try {
if (conn != null) {
conn.close();
// Main stuff here?
main(conn);
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
}
private static void main(Connection conn) {
String sql = "";
try (Statement stmt = conn.createStatement()) {
// create a new table
stmt.execute(sql);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
}

View File

@ -2,22 +2,33 @@ package org.samo_lego.simpleauth.event;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
import net.minecraft.util.ActionResult;
import org.samo_lego.simpleauth.SimpleAuth;
/**
* This class will take care of actions players try to do,
* and cancels them if they aren't authenticated
*/
public class AuthEventHandler {
private static LiteralText notAuthenticated = new LiteralText("§4You aren't authenticated.");
// Player joining the server
public static void onPlayerJoin(ServerPlayerEntity player) {
// Player not authenticated
if (!SimpleAuth.isAuthenticated(player))
System.out.println("Not authenticated!");
player.sendMessage(notAuthenticated);
}
// Player leaving the server
public static void onPlayerLeave(ServerPlayerEntity player) {
SimpleAuth.authenticatedUsers.remove(player);
}
// Breaking block
public static boolean onBlockBroken(PlayerEntity player) {
// Player not authenticated
if (!SimpleAuth.isAuthenticated((ServerPlayerEntity) player))
{
System.out.println("Not authenticated!");
if (!SimpleAuth.isAuthenticated((ServerPlayerEntity) player)) {
player.sendMessage(notAuthenticated);
return true;
}
return false;
@ -25,15 +36,29 @@ public class AuthEventHandler {
// Interacting with block
public static ActionResult onInteractBlock(ServerPlayerEntity player) {
if(!SimpleAuth.authenticatedUsers.contains(player))
if(!SimpleAuth.authenticatedUsers.contains(player)) {
player.sendMessage(notAuthenticated);
return ActionResult.FAIL;
}
return ActionResult.PASS;
}
// Punching a block
public static ActionResult interact(PlayerEntity playerEntity) {
if(!SimpleAuth.authenticatedUsers.contains(playerEntity)) {
playerEntity.sendMessage(notAuthenticated);
return ActionResult.FAIL;
}
return ActionResult.PASS;
}
// Interacting with item
public static ActionResult onInteractItem(ServerPlayerEntity player) {
System.out.println("Called");
if(!SimpleAuth.authenticatedUsers.contains(player))
if(!SimpleAuth.authenticatedUsers.contains(player)) {
player.sendMessage(notAuthenticated);
return ActionResult.FAIL;
}
return ActionResult.PASS;
}
}

View File

@ -1,31 +0,0 @@
package org.samo_lego.simpleauth.event.block;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface BlockDropsCallback {
Event<BlockDropsCallback> EVENT = EventFactory.createArrayBacked(BlockDropsCallback.class, listeners -> (world, pos, state, drops, harvester, tool) -> {
for(BlockDropsCallback callback : listeners) {
if(callback.onDrop(world, pos, state, drops, harvester, tool)) {
return true;
}
}
return false;
});
/**
* fired when a block is about to drop it's items
*
* @return {@code true} to cancel all drops
*/
boolean onDrop(World world, BlockPos pos, BlockState state, List<ItemStack> drops, @Nullable PlayerEntity harvester, ItemStack tool);
}

View File

@ -1,4 +1,4 @@
package org.samo_lego.simpleauth.event.entity.player;
package org.samo_lego.simpleauth.event.block;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
@ -6,7 +6,6 @@ import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
public interface BreakBlockCallback {
@ -18,11 +17,5 @@ public interface BreakBlockCallback {
}
return false;
});
/**
* fired when a block is broken by a player
*
* @return {@code true} to cancel the event
*/
boolean onBlockBroken(World world, BlockPos pos, BlockState state, @Nullable PlayerEntity player);
boolean onBlockBroken(World world, BlockPos pos, BlockState state, PlayerEntity player);
}

View File

@ -1,4 +1,4 @@
package org.samo_lego.simpleauth.event.entity.player;
package org.samo_lego.simpleauth.event.block;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;

View File

@ -1,24 +0,0 @@
package org.samo_lego.simpleauth.event.entity;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.Entity;
public interface EntitySpawnCallback {
Event<EntitySpawnCallback> EVENT = EventFactory.createArrayBacked(EntitySpawnCallback.class, listeners -> entity -> {
for(EntitySpawnCallback callback : listeners) {
if(callback.spawnEntity(entity)) {
return true;
}
}
return false;
});
/**
* fired when an entity is spawned
*
* @return {@code true} to stop the entity from spawning
*/
boolean spawnEntity(Entity entity);
}

View File

@ -0,0 +1,15 @@
package org.samo_lego.simpleauth.event.entity.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.network.ServerPlayerEntity;
public interface PlayerJoinServerCallback {
Event<PlayerJoinServerCallback> EVENT = EventFactory.createArrayBacked(PlayerJoinServerCallback.class, listeners -> (player) -> {
for (PlayerJoinServerCallback callback : listeners) {
callback.onPlayerJoin(player);
}
});
void onPlayerJoin(ServerPlayerEntity player);
}

View File

@ -1,20 +0,0 @@
package org.samo_lego.simpleauth.event.entity.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
public interface PlayerJoinWorldCallback {
Event<PlayerJoinWorldCallback> EVENT = EventFactory.createArrayBacked(PlayerJoinWorldCallback.class, listeners -> (world, player) -> {
for (PlayerJoinWorldCallback callback : listeners) {
callback.onPlayerJoin(world, player);
}
});
/**
* Fired when a player joins a world
*/
void onPlayerJoin(ServerWorld world, ServerPlayerEntity player);
}

View File

@ -0,0 +1,15 @@
package org.samo_lego.simpleauth.event.entity.player;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.network.ServerPlayerEntity;
public interface PlayerLeaveServerCallback {
Event<PlayerLeaveServerCallback> EVENT = EventFactory.createArrayBacked(PlayerLeaveServerCallback.class, listeners -> (player) -> {
for (PlayerLeaveServerCallback callback : listeners) {
callback.onPlayerLeave(player);
}
});
void onPlayerLeave(ServerPlayerEntity player);
}

View File

@ -1,29 +0,0 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import org.samo_lego.simpleauth.event.block.BlockDropsCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//FIXME this needs a better implementation to catch all of a block's drops, not just those from getDroppedStacks
@Mixin(Block.class)
public abstract class MixinBlockOld {
@Inject(method = "afterBreak", at = @At("HEAD"), cancellable = true)
private void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, CallbackInfo ci) {
if(!world.isClient && BlockDropsCallback.EVENT.invoker().onDrop(world, pos, state, Block.getDroppedStacks(state, (ServerWorld) world, pos, blockEntity), player, stack)) {
ci.cancel();
}
}
}

View File

@ -0,0 +1,20 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Entity.class)
public abstract class MixinEntity {
/*@Inject(method = "canSeePlayer", at = @At("HEAD"), cancellable = true)
private void canSeePlayer(PlayerEntity playerEntity_1, CallbackInfoReturnable<Boolean> info) {
if(!CanSeePlayerCallback.EVENT.invoker().canSeePlayer((ServerPlayerEntity) playerEntity_1))
info.setReturnValue(false);
}*/
}

View File

@ -0,0 +1,14 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@Mixin(PlayerEntity.class)
public abstract class MixinPlayerEntity {
/*@Inject(method = "dropItem", at = @At("HEAD"))
private void dropItem(ItemStack itemStack_1, boolean boolean_1) {
}*/
}

View File

@ -0,0 +1,25 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import org.samo_lego.simpleauth.event.entity.player.PlayerJoinServerCallback;
import org.samo_lego.simpleauth.event.entity.player.PlayerLeaveServerCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerManager.class)
public abstract class MixinPlayerManager {
@Inject(method = "onPlayerConnect", at = @At("RETURN"))
private void onPlayerConnect(ClientConnection clientConnection_1, ServerPlayerEntity serverPlayerEntity_1, CallbackInfo ci) {
PlayerJoinServerCallback.EVENT.invoker().onPlayerJoin(serverPlayerEntity_1);
}
@Inject(method = "remove", at = @At("RETURN"))
private void remove(ServerPlayerEntity serverPlayerEntity_1, CallbackInfo ci) {
PlayerLeaveServerCallback.EVENT.invoker().onPlayerLeave(serverPlayerEntity_1);
}
}

View File

@ -0,0 +1,17 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.server.network.packet.PlayerMoveC2SPacket;
import net.minecraft.util.PacketByteBuf;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerMoveC2SPacket.class)
public abstract class MixinServerPlayNetworkHandler {
@Inject(method = "read", at = @At("RETURN"))
private void read(PacketByteBuf packetByteBuf_1, CallbackInfo ci) {
System.out.println("Packet "+packetByteBuf_1);
}
}

View File

@ -1,6 +1,5 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.client.network.packet.BlockUpdateS2CPacket;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
@ -11,9 +10,8 @@ import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.samo_lego.simpleauth.SimpleAuth;
import org.samo_lego.simpleauth.event.entity.player.BreakBlockCallback;
import org.samo_lego.simpleauth.event.entity.player.InteractBlockCallback;
import org.samo_lego.simpleauth.event.block.BreakBlockCallback;
import org.samo_lego.simpleauth.event.block.InteractBlockCallback;
import org.samo_lego.simpleauth.event.entity.player.InteractItemCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -33,10 +31,6 @@ public abstract class MixinServerPlayerInteractionManager {
private void tryBreakBlock(BlockPos pos, CallbackInfoReturnable<Boolean> info) {
// Triggering the event
if(BreakBlockCallback.EVENT.invoker().onBlockBroken(world, pos, world.getBlockState(pos), player)) {
/*// Update client as they will believe they have broken the block.
if(this.player != null) {
this.player.networkHandler.sendPacket(new BlockUpdateS2CPacket(world, pos));
}*/
info.setReturnValue(false);
}
}

View File

@ -1,35 +0,0 @@
package org.samo_lego.simpleauth.mixin;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import org.samo_lego.simpleauth.event.entity.EntitySpawnCallback;
import org.samo_lego.simpleauth.event.entity.player.PlayerJoinWorldCallback;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ServerWorld.class)
public abstract class MixinServerWorld {
@Inject(method = "addPlayer", at = @At("RETURN"))
private void method_18771(ServerPlayerEntity serverPlayerEntity, CallbackInfo ci) {
PlayerJoinWorldCallback.EVENT.invoker().onPlayerJoin(serverPlayerEntity.getServerWorld(), serverPlayerEntity);
}
@Inject(method = "spawnEntity", at = @At("HEAD"), cancellable = true)
private void spawnEntity(Entity entity, CallbackInfoReturnable<Boolean> cir) {
int chunkX = MathHelper.floor(entity.x / 16.0D);
int chunkZ = MathHelper.floor(entity.z / 16.0D);
if(entity.teleporting || entity instanceof PlayerEntity || ((World) (Object) this).isChunkLoaded(chunkX, chunkZ)) {
if(EntitySpawnCallback.EVENT.invoker().spawnEntity(entity)) {
cir.setReturnValue(false);
}
}
}
}

View File

@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS `{TABLE_NAME}` (
`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT,
`UUID` BINARY(16) NOT NULL,
`Username` VARCHAR(16), NOT NULL,
`Password` VARCHAR(64) NOT NULL,
UNIQUE (`UUID`)
);

View File

@ -6,7 +6,7 @@
],
"server": [
"MixinServerPlayerInteractionManager",
"MixinServerWorld"
"MixinPlayerManager"
],
"injectors": {
"defaultRequire": 1