diff --git a/bukkit/readme.txt b/bukkit/readme.txt new file mode 100644 index 0000000..b4796db --- /dev/null +++ b/bukkit/readme.txt @@ -0,0 +1,10 @@ +To compile: + +1. Link "src/main/java" as a source folder +2. Link "src/main/resources" as a source folder +3. Add "server/craftbukkit-bin.jar" to the build path as a dependency +4. Add "server/java_websocket.jar" to the build path as a dependency +5. Set "watchdog.WatchDog" as the main class +6. Export the project as a runnable jar file + +You cannot run the project from within the IDE, you must export it every time as a runnable jar file for both testing and production. \ No newline at end of file diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftConfig.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftConfig.java new file mode 100644 index 0000000..8cb49ec --- /dev/null +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftConfig.java @@ -0,0 +1,119 @@ +package net.lax1dude.eaglercraft.beta.server; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bukkit.util.config.Configuration; + +public class EaglercraftConfig { + + private Configuration yamlFile = null; + + private boolean enablePasswordLoginValue = true; + private boolean requirePasswordLoginValue = true; + private boolean allowSelfRegistrationValue = false; + private boolean allowSelfRegistrationWithoutExpireValue = false; + private boolean allowSelfChangePasswordValue = true; + private boolean allowSelfRenewPasswordValue = true; + private boolean allowSelfRenewPasswordWithTimeValue = false; + private boolean allowSelfDeletePasswordValue = false; + private int defaultPasswordExpireTimeValue = 7 * 24 * 60 * 60; + private int maximumPasswordExpireTimeValue = 21 * 24 * 60 * 60; + private boolean allowPasswordsWithoutExpireValue = true; + + private static final File configFile = new File("eagler.yml"); + + public boolean enablePasswordLogin() { + return enablePasswordLoginValue; + } + + public boolean requirePasswordLogin() { + return requirePasswordLoginValue; + } + + public boolean allowSelfRegistration() { + return allowSelfRegistrationValue; + } + + public boolean allowSelfRegistrationWithoutExpire() { + return allowSelfRegistrationWithoutExpireValue; + } + + public boolean allowSelfChangePassword() { + return allowSelfChangePasswordValue; + } + + public boolean allowSelfRenewPassword() { + return allowSelfRenewPasswordValue; + } + + public boolean allowSelfRenewPasswordWithTime() { + return allowSelfRenewPasswordWithTimeValue; + } + + public boolean allowSelfDeletePassword() { + return allowSelfDeletePasswordValue; + } + + public int defaultPasswordExpireTime() { + return defaultPasswordExpireTimeValue; + } + + public int maximumPasswordExpireTime() { + return maximumPasswordExpireTimeValue; + } + + public boolean allowPasswordsWithoutExpire() { + return allowPasswordsWithoutExpireValue; + } + + public void reload() { + if(yamlFile == null) { + if(!configFile.exists()) { + InputStream is = EaglercraftConfig.class.getResourceAsStream("/default_eagler_config.yml"); + if(is == null) { + System.err.println("The file '/default_eagler_config.yml' could not be located in this jar!"); + return; + } + try(FileOutputStream os = new FileOutputStream(configFile)) { + byte[] buffer = new byte[1024]; + int i; + while((i = is.read(buffer)) > 0) { + os.write(buffer, 0, i); + } + os.close(); + }catch(IOException ex) { + System.err.println("The default config fould not be written! (writing '" + configFile.getName() + "')"); + ex.printStackTrace(); + } + try { + is.close(); + } catch (IOException e) { + } + } + yamlFile = new Configuration(configFile); + yamlFile.load(); + enablePasswordLoginValue = yamlFile.getBoolean("enable_password_logins", true); + }else { + yamlFile.load(); + } + + if(enablePasswordLoginValue != yamlFile.getBoolean("enable_password_logins", true)) { + System.err.println("Please restart the server when you change the 'enable_password_logins' option "); + } + + requirePasswordLoginValue = yamlFile.getBoolean("only_allow_registered_users_to_login", true); + allowPasswordsWithoutExpireValue = yamlFile.getBoolean("allow_passwords_without_expiration", true); + allowSelfRegistrationValue = yamlFile.getBoolean("allow_self_registration", false); + allowSelfRegistrationWithoutExpireValue = yamlFile.getBoolean("allow_self_registration_without_expiration", false); + allowSelfChangePasswordValue = yamlFile.getBoolean("allow_self_change_password", true); + allowSelfRenewPasswordValue = yamlFile.getBoolean("allow_self_renew_password", true); + allowSelfRenewPasswordWithTimeValue = yamlFile.getBoolean("allow_self_change_password_expiration", false); + allowSelfDeletePasswordValue = yamlFile.getBoolean("allow_self_delete_password", false); + defaultPasswordExpireTimeValue = yamlFile.getInt("default_password_expire_time_seconds", 604800); // 1 week + maximumPasswordExpireTimeValue = yamlFile.getInt("maximum_password_expire_time_seconds", 1814400); // 1 week + } + +} diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftServer.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftServer.java index a47fa89..d7bd427 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftServer.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/EaglercraftServer.java @@ -2,21 +2,34 @@ package net.lax1dude.eaglercraft.beta.server; import java.io.File; import java.io.IOException; +import java.util.regex.Pattern; import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.event.Event.Priority; +import org.bukkit.event.Event.Type; +import org.bukkit.event.Event; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.InvalidDescriptionException; +import org.bukkit.plugin.InvalidPluginException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.PluginManager; import org.bukkit.util.config.Configuration; +import net.lax1dude.eaglercraft.beta.server.PasswordManager.PasswordEntry; import net.lax1dude.eaglercraft.beta.server.commands.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PacketRegister; -public class EaglercraftServer { +public class EaglercraftServer extends PlayerListener { private static final File dataFolder = new File("."); private static CraftServer server = null; @@ -24,11 +37,33 @@ public class EaglercraftServer { private static PluginManager pluginManager = null; private static boolean passwordDBWorking = false; + private static EaglercraftServer instance = null; + + public static final EaglercraftConfig config = new EaglercraftConfig(); + private static final Plugin dummyPlugin = new Plugin() { @Override public File getDataFolder() { return dataFolder; } @Override public PluginDescriptionFile getDescription() { return new PluginDescriptionFile("EaglercraftServer", "0.0.0", ""); } @Override public Configuration getConfiguration() { return null; } - @Override public PluginLoader getPluginLoader() { return null; } + @Override public PluginLoader getPluginLoader() { return new PluginLoader() { + @Override public Plugin loadPlugin(File var1) throws InvalidPluginException, InvalidDescriptionException { + return dummyPlugin; + } + @Override public Pattern[] getPluginFileFilters() { + return new Pattern[0]; + } + @Override public EventExecutor createExecutor(Type var1, Listener var2) { + if(var1 == Type.PLAYER_JOIN) { + return new EventExecutor() { @Override public void execute(Listener var1, Event var2) { + ((PlayerListener)var1).onPlayerJoin((PlayerEvent)var2); + }}; + }else { + return null; + } + } + @Override public void enablePlugin(Plugin var1) { } + @Override public void disablePlugin(Plugin var1) { } + }; } @Override public Server getServer() { return server; } @Override public boolean isEnabled() { return true; } @Override public void onDisable() { } @@ -38,27 +73,42 @@ public class EaglercraftServer { return false; } }; + + static { + PacketRegister.register(69, Packet69EaglercraftData.class); + } public static void installHooks(CraftServer craftServer, CommandMap commandMap) { server = craftServer; commands = commandMap; pluginManager = craftServer.getPluginManager(); + instance = new EaglercraftServer(); - try { - PasswordManager.loadPasswordDB(); - passwordDBWorking = true; - } catch (IOException e) { - PasswordManager.log.severe("ERROR: could not create or load password database!"); - PasswordManager.log.severe("Eaglercraft will not function correctly, unless you disable password login"); - e.printStackTrace(); - passwordDBWorking = false; + PasswordManager.log.info("Loading Eaglercraft Bukkit..."); + + config.reload(); + + if(config.enablePasswordLogin()) { + try { + PasswordManager.loadPasswordDB(); + passwordDBWorking = true; + } catch (IOException e) { + PasswordManager.log.severe("ERROR: could not create or load password database!"); + PasswordManager.log.severe("Eaglercraft will not function correctly, unless you disable password login"); + e.printStackTrace(); + passwordDBWorking = false; + } } + + pluginManager.registerEvent(Type.PLAYER_JOIN, instance, Priority.Normal, dummyPlugin); registerCommand(new CommandSetPassword()); registerCommand(new CommandChangePassword()); registerCommand(new CommandClearPassword()); registerCommand(new CommandListPasswords()); registerCommand(new CommandPasswordExpires()); + registerCommand(new CommandRenewPassword()); + registerCommand(new CommandRegister()); } @@ -68,6 +118,30 @@ public class EaglercraftServer { private static void registerCommand(Command command) { commands.register(command.getName(), "eagler", command); + for(String s : command.getAliases()) { + commands.register(s, "eagler", command); + } + } + + @Override + public void onPlayerJoin(PlayerEvent event) { + if(config.enablePasswordLogin()) { + PasswordEntry et = PasswordManager.load(event.getPlayer().getName()); + if(et != null && et.secondsRemaining() != Integer.MAX_VALUE) { + event.getPlayer().sendMessage("Your password will expire after " + CommandListPasswords.expiresAfter(et.secondsRemaining())); + if(config.allowSelfRenewPassword()) { + event.getPlayer().sendMessage("Use /renew-password to extend"); + } + } + } + } + + public static CraftServer getMinecraftServer() { + return server; + } + + public static PluginManager getPluginManager() { + return pluginManager; } } diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/NetEaglerServerHandler.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/NetEaglerServerHandler.java new file mode 100644 index 0000000..36994cb --- /dev/null +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/NetEaglerServerHandler.java @@ -0,0 +1,56 @@ +package net.lax1dude.eaglercraft.beta.server; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; + +import net.minecraft.server.EntityPlayer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.NetServerHandler; +import net.minecraft.server.NetworkManager; +import net.minecraft.server.Packet255KickDisconnect; + +public class NetEaglerServerHandler extends NetServerHandler { + + public final byte[] skinData; + private final MinecraftServer server; + + public NetEaglerServerHandler(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer, byte[] skinData) { + super(minecraftserver, networkmanager, entityplayer); + this.server = minecraftserver; + this.skinData = skinData; + } + + public void a(Packet69EaglercraftData pkt) { + if(pkt.type.equals("EAG|RequestPlayerSkin")) { + DataInputStream dis = new DataInputStream(new ByteArrayInputStream(pkt.data)); + try { + int cookie = dis.readUnsignedShort(); + String un = dis.readUTF(); + if(dis.available() > 0) { + throw new IOException("Packet has " + dis.available() + " extra bytes!"); + } + EntityPlayer ep = server.f.i(un); + if(ep != null) { + if(ep.a instanceof NetEaglerServerHandler) { + byte[] pk = ((NetEaglerServerHandler)ep.a).skinData; + if(pk != null) { + byte[] ret = new byte[pk.length + 2]; + ret[0] = (byte)((cookie >> 8) & 0xFF); + ret[1] = (byte)(cookie & 0xFF); + System.arraycopy(pk, 0, ret, 2, pk.length); + this.b.a(new Packet69EaglercraftData("EAG|PlayerSkin", ret)); + }else { + this.b.a(new Packet69EaglercraftData("EAG|PlayerSkin", new byte[] { (byte)((cookie >> 8) & 0xFF), (byte)(cookie & 0xFF), (byte)0, (byte)0 })); + } + } + } + }catch(IOException ex) { + this.b.a(new Packet255KickDisconnect("Invalid Skin Request")); + this.b.c(); + this.c = true; + } + } + } + +} diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/Packet69EaglercraftData.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/Packet69EaglercraftData.java new file mode 100644 index 0000000..0710591 --- /dev/null +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/Packet69EaglercraftData.java @@ -0,0 +1,58 @@ +package net.lax1dude.eaglercraft.beta.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.server.NetHandler; +import net.minecraft.server.Packet; + +public class Packet69EaglercraftData extends Packet { + + public String type; + public byte[] data; + + public Packet69EaglercraftData() { + } + + public Packet69EaglercraftData(String type, byte[] data) { + if(data.length > 65535) { + throw new IllegalArgumentException("Packet69EaglercraftData may at most carry a 65535 byte payload"); + } + this.type = type; + this.data = data; + } + + @Override + public void a(DataInputStream datainputstream) { + try { + type = datainputstream.readUTF(); + data = new byte[datainputstream.readUnsignedShort()]; + datainputstream.read(data); + }catch(IOException ex) { + throw new RuntimeException("IOException was thrown while reading Packet69EaglercraftData!", ex); + } + } + + @Override + public void a(DataOutputStream var1) { + try { + var1.writeUTF(type); + var1.writeShort(data.length); + var1.write(data); + }catch(IOException ex) { + throw new RuntimeException("IOException was thrown while writing Packet69EaglercraftData!", ex); + } + } + + @Override + public void a(NetHandler var1) { + var1.a(this); + } + + @Override + public int a() { + return 2 + type.length() + 2 + data.length; + } + +} diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/PasswordManager.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/PasswordManager.java index bb70e04..51014f0 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/PasswordManager.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/PasswordManager.java @@ -169,7 +169,7 @@ public class PasswordManager { continue; } synchronized(passwordEntries) { - if(pse.secondsRemaining() > 0) { + if(pse.secondsRemaining() > 0 && !(!EaglercraftServer.config.allowPasswordsWithoutExpire() && pse.expiresAfter == -1)) { passwordEntries.put(pse.username, pse); }else { mustRewrite = true; @@ -410,6 +410,10 @@ public class PasswordManager { public static void create(String username, String password, int expiresAfter) { discardExpiredPasswords(); + if(expiresAfter < -1) { + expiresAfter = -1; + } + byte[] salt = new byte[9]; synchronized(rand) { rand.nextBytes(salt); @@ -444,12 +448,43 @@ public class PasswordManager { } } + public static int changeExpires(String username, int expiresAfter) { + PasswordEntry et; + synchronized(passwordEntries) { + et = passwordEntries.get(username.toLowerCase()); + } + if(et != null) { + if(expiresAfter == -1) { + expiresAfter = et.expiresAfter; + } + synchronized(passwordEntries) { + passwordEntries.put(et.username, new PasswordEntry(et.username, et.salt, et.password, System.currentTimeMillis(), expiresAfter == -2 ? -1 : expiresAfter)); + } + } + if(discardExpiredPasswords() || et != null) { + try { + syncDatabase(); + }catch(SyncException e) { + Throwable t = e.getCause(); + System.err.println("Could not write passwords to disk!"); + if(t != null) { + t.printStackTrace(); + }else { + e.printStackTrace(); + } + } + } + return et == null ? -1 : (expiresAfter == -1 ? -2 : expiresAfter); + } + private static boolean discardExpiredPasswords() { boolean flag = false; + boolean removePasswordsWithoutExpire = !EaglercraftServer.config.allowPasswordsWithoutExpire(); synchronized(passwordEntries) { Iterator itr = passwordEntries.values().iterator(); while(itr.hasNext()) { - if(itr.next().secondsRemaining() <= 0) { + PasswordEntry et = itr.next(); + if(et.secondsRemaining() <= 0 || (removePasswordsWithoutExpire && et.expiresAfter == -1)) { flag = true; itr.remove(); } diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandChangePassword.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandChangePassword.java index 154a676..8576fe6 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandChangePassword.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandChangePassword.java @@ -24,6 +24,10 @@ public class CommandChangePassword extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } if(sender instanceof Player) { if(!EaglercraftServer.hasPasswordDB()) { sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); @@ -31,8 +35,14 @@ public class CommandChangePassword extends EaglerCommand { if(args.length != 1) { throw new IncorrectUsageException("this command only takes 1 argument!"); } - + if(args[0].length() < 3) { + throw new IncorrectUsageException("A password must be at least 3 characters!"); + } if(((CraftPlayer)sender).getHandle().a.b instanceof EaglercraftWebsocketNetworkManager) { + if(!EaglercraftServer.config.allowSelfChangePassword()) { + sender.sendMessage(ChatColor.RED + "Error: you are not allowed to change your password"); + return; + } PasswordEntry et = PasswordManager.load(((Player)sender).getName()); if(et != null) { PasswordManager.create(et.username, args[0], et.expiresAfter); diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandClearPassword.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandClearPassword.java index 20cc006..58cce61 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandClearPassword.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandClearPassword.java @@ -15,7 +15,7 @@ public class CommandClearPassword extends EaglerCommand { public CommandClearPassword() { super("clear-password"); - setAliases(Arrays.asList("clear-pass")); + setAliases(Arrays.asList("clear-pass", "remove-password", "remove-pass", "delete-password", "delete-pass")); setNeedsOp(false); setTooltip("Removes a password from a username, or your own username, for Eaglercraft connections"); setUsage("/clear-password [username]"); @@ -23,15 +23,28 @@ public class CommandClearPassword extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } if(!EaglercraftServer.hasPasswordDB()) { sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); } if(sender instanceof CraftPlayer && ((CraftPlayer)sender).getHandle().a.b instanceof EaglercraftWebsocketNetworkManager && (args.length == 0 || (args.length == 1 && args[0].equalsIgnoreCase(((Player)sender).getName())))) { - if(PasswordManager.delete(((Player)sender).getName())) { - sender.sendMessage("Your password was removed."); + if(EaglercraftServer.config.allowSelfDeletePassword() || EaglercraftServer.config.allowSelfRegistration()) { + if(PasswordManager.delete(((Player)sender).getName())) { + if(EaglercraftServer.config.requirePasswordLogin()) { + ((Player)sender).kickPlayer("Your password was removed."); + }else { + sender.sendMessage("Your password was removed."); + } + }else { + sender.sendMessage(ChatColor.RED + "You do not have a password on this account!"); + } }else { - sender.sendMessage(ChatColor.RED + "You do not have a password on this account!"); + sender.sendMessage(ChatColor.RED + "You cannot remove the password from your username."); } + return; }else if(args.length != 1) { throw new IncorrectUsageException("this command only takes 1 argument!"); } diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandListPasswords.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandListPasswords.java index 33e0e59..c754e97 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandListPasswords.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandListPasswords.java @@ -22,6 +22,10 @@ public class CommandListPasswords extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } if(args.length != 0) { throw new IncorrectUsageException("This command does not take any arguments"); } @@ -36,24 +40,27 @@ public class CommandListPasswords extends EaglerCommand { int characterWidth = (sender instanceof Player) ? 60 : 40; String row = ""; for(PasswordEntry s : cc) { - String rowAdd = s.username + (s.expiresAfter <= 0 ? " (*)" : " (" + expiresAfter(s.expiresAfter) + ")"); + String rowAdd = s.username + (s.expiresAfter <= 0 ? " (*)" : " (" + expiresAfter(s.secondsRemaining()) + ")"); if(row.length() + rowAdd.length() + 2 > characterWidth) { - sender.sendMessage(" " + row); + sender.sendMessage(" " + row); row = ""; } if(row.length() > 0) { - row = ", " + rowAdd; + row = row + ", " + rowAdd; }else { row = rowAdd; } } if(row.length() > 0) { - sender.sendMessage(" " + row); + sender.sendMessage(" " + row); } } } public static String expiresAfter(int remaining) { + if(remaining < 0) { + return "never"; + } if(remaining < 60) { return remaining + "s"; }else if(remaining < 60 * 60) { diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandPasswordExpires.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandPasswordExpires.java index 6aa7292..ee68246 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandPasswordExpires.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandPasswordExpires.java @@ -24,6 +24,10 @@ public class CommandPasswordExpires extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } if(!EaglercraftServer.hasPasswordDB()) { sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); } diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRegister.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRegister.java new file mode 100644 index 0000000..ed2a497 --- /dev/null +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRegister.java @@ -0,0 +1,70 @@ +package net.lax1dude.eaglercraft.beta.server.commands; + +import java.util.Arrays; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import net.lax1dude.eaglercraft.beta.server.EaglercraftServer; +import net.lax1dude.eaglercraft.beta.server.PasswordManager; +import net.minecraft.server.EaglercraftWebsocketNetworkManager; + +public class CommandRegister extends EaglerCommand { + + public CommandRegister() { + super("register-password"); + setAliases(Arrays.asList("register-pass", "password-register", "pass-register", "eagler-register", "eag-register")); + setNeedsOp(false); + setTooltip("Register a password for your username"); + setUsage("/register-password [expires after][s|m|h|d|w]"); + } + + @Override + protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } + if(!EaglercraftServer.hasPasswordDB()) { + sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); + } + if(sender instanceof Player && ((CraftPlayer)sender).getHandle().a.b instanceof EaglercraftWebsocketNetworkManager) { + if(!EaglercraftServer.config.allowSelfRegistration()) { + sender.sendMessage(ChatColor.RED + "Error: password registration is disabled"); + return; + } + if(PasswordManager.load(((Player)sender).getName()) != null) { + sender.sendMessage(ChatColor.RED + "Error: you are already registered on this server, use /change-password to edit it"); + }else { + if(args.length != 1 && args.length != 2) { + throw new IncorrectUsageException("this command takes 1 or 2 arguments!"); + } + if(args[0].length() < 3) { + throw new IncorrectUsageException("A password must be at least 3 characters!"); + } + int expires = EaglercraftServer.config.defaultPasswordExpireTime(); + if(args.length == 2) { + expires = CommandRenewPassword.tryParseTime(args[1]); + if(expires == -1) { + throw new IncorrectUsageException("Expires time is invalid!"); + } + } + if(expires == -2 && !(EaglercraftServer.config.allowSelfRegistrationWithoutExpire() || !EaglercraftServer.config.allowPasswordsWithoutExpire())) { + sender.sendMessage(ChatColor.RED + "Error: you cannot register a password"); + return; + } + if(expires > EaglercraftServer.config.maximumPasswordExpireTime()) { + sender.sendMessage(ChatColor.RED + "Error: the maximum time before your password expires can be at most " + CommandListPasswords.expiresAfter(expires)); + return; + } + PasswordManager.create(((Player)sender).getName(), args[0], expires == -2 ? -1 : expires); + sender.sendMessage("Your password was registered." + (expires == -2 ? "" : " It will expire in " + CommandListPasswords.expiresAfter(expires))); + } + }else { + sender.sendMessage(ChatColor.RED + "Error: only players connected via websocket can use this command"); + } + } + +} diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRenewPassword.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRenewPassword.java index 1bd46a9..e52db61 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRenewPassword.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandRenewPassword.java @@ -9,6 +9,7 @@ import org.bukkit.entity.Player; import net.lax1dude.eaglercraft.beta.server.EaglercraftServer; import net.lax1dude.eaglercraft.beta.server.PasswordManager; +import net.lax1dude.eaglercraft.beta.server.PasswordManager.PasswordEntry; import net.minecraft.server.EaglercraftWebsocketNetworkManager; public class CommandRenewPassword extends EaglerCommand { @@ -23,31 +24,166 @@ public class CommandRenewPassword extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } - // Tomorrow: program this command + boolean isPlayer = sender instanceof Player; + boolean isWsPlayer = isPlayer && ((CraftPlayer)sender).getHandle().a.b instanceof EaglercraftWebsocketNetworkManager; + boolean isSelfPlayer = isPlayer && args.length >= 1 && args[0].equalsIgnoreCase(((Player)sender).getName()); + int is1stTime = args.length >= 1 ? tryParseTime(args[0]) : -1; + int is2stTime = args.length >= 2 ? tryParseTime(args[1]) : -1; + int mpe = EaglercraftServer.config.maximumPasswordExpireTime(); + if(is1stTime > mpe || is2stTime > mpe) { + sender.sendMessage(ChatColor.RED + "Error: the maximum time before a password expires can be at most " + CommandListPasswords.expiresAfter(mpe)); + return; + } + + if(!EaglercraftServer.config.allowPasswordsWithoutExpire() && (is1stTime == -2 || is2stTime == -2)) { + sender.sendMessage(ChatColor.RED + "Error: passwords that do not expire are not enabled on this server!"); + return; + } if(!EaglercraftServer.hasPasswordDB()) { sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); } - if(sender instanceof CraftPlayer && ((CraftPlayer)sender).getHandle().a.b instanceof EaglercraftWebsocketNetworkManager && (args.length == 0 || (args.length == 1 && args[0].equalsIgnoreCase(((Player)sender).getName())))) { - if(PasswordManager.delete(((Player)sender).getName())) { - sender.sendMessage("Your password was removed."); + + if(args.length == 0 || (args.length == 1 && isSelfPlayer)) { + if(isPlayer && (isWsPlayer || sender.isOp())) { + if(!sender.isOp() && !EaglercraftServer.config.allowSelfRenewPassword()) { + sender.sendMessage(ChatColor.RED + "Error: you cannot renew your password on this server"); + return; + } + int n = PasswordManager.changeExpires(((Player)sender).getName(), -1); + if(n > 0) { + sender.sendMessage("Your password will expire in " + CommandListPasswords.expiresAfter(n) + "."); + }else { + if(n == -2) { + sender.sendMessage("Your password is not going to expire."); + }else { + sender.sendMessage(ChatColor.RED + "Error: you do not have a password to renew"); + } + } }else { - sender.sendMessage(ChatColor.RED + "You do not have a password on this account!"); + sender.sendMessage(ChatColor.RED + "Error: you need to be logged in via websocket to use this command"); } - }else if(args.length != 1) { - throw new IncorrectUsageException("this command only takes 1 argument!"); - } - if(sender.isOp()) { - if(PasswordManager.delete(args[0])) { - sender.sendMessage("Password for '" + args[0] + "' was removed"); + }else if(args.length == 1 && is1stTime != -1) { + if(isPlayer && (isWsPlayer || sender.isOp())) { + if(!sender.isOp() && !EaglercraftServer.config.allowSelfRenewPassword()) { + sender.sendMessage(ChatColor.RED + "Error: you cannot renew your password on this server"); + return; + } + System.out.println(EaglercraftServer.config.allowSelfRenewPasswordWithTime()); + if(!sender.isOp() && !EaglercraftServer.config.allowSelfRenewPasswordWithTime()) { + sender.sendMessage(ChatColor.RED + "Error: you cannot manually set the time until your password expires on this server"); + return; + } + PasswordEntry pe = PasswordManager.load(((Player)sender).getName()); + if(pe.expiresAfter == -1) { + sender.sendMessage("Your password is not going to expire."); + }else { + if(!sender.isOp() && is1stTime == -2) { + sender.sendMessage(ChatColor.RED + "Error: you cannot renew your password not to expire"); + return; + }else { + int n = PasswordManager.changeExpires(((Player)sender).getName(), is1stTime); + if(n > 0) { + sender.sendMessage("Your password will expire in " + CommandListPasswords.expiresAfter(n) + "."); + }else { + if(n == -2) { + sender.sendMessage("Your password is not going to expire."); + }else { + sender.sendMessage(ChatColor.RED + "Error: you do not have a password to renew"); + } + } + } + } }else { - sender.sendMessage(ChatColor.RED + "The user '" + args[0] + "' does not have a password!"); + sender.sendMessage(ChatColor.RED + "Error: you need to be logged in via websocket to use this command"); + } + }else if(args.length == 2 && isSelfPlayer && is2stTime != -1) { + if(isPlayer && (isWsPlayer || sender.isOp())) { + if(!sender.isOp() && !EaglercraftServer.config.allowSelfRenewPassword()) { + sender.sendMessage(ChatColor.RED + "Error: you cannot renew your password on this server"); + return; + } + if(!sender.isOp() && !EaglercraftServer.config.allowSelfRenewPasswordWithTime()) { + sender.sendMessage(ChatColor.RED + "Error: you cannot manually set the time until your password expires on this server"); + return; + } + PasswordEntry pe = PasswordManager.load(((Player)sender).getName()); + if(pe.expiresAfter == -1) { + sender.sendMessage("Your password is not going to expire."); + }else { + if(!sender.isOp() && is2stTime == -2) { + sender.sendMessage(ChatColor.RED + "Error: you cannot renew your password not to expire"); + return; + }else { + int n = PasswordManager.changeExpires(((Player)sender).getName(), is2stTime); + if(n > 0) { + sender.sendMessage("Your password will expire in " + CommandListPasswords.expiresAfter(n) + "."); + }else { + if(n == -2) { + sender.sendMessage("Your password is not going to expire."); + }else { + sender.sendMessage(ChatColor.RED + "Error: you do not have a password to renew"); + } + } + } + } + }else { + sender.sendMessage(ChatColor.RED + "Error: you need to be logged in via websocket to use this command"); + } + }else if(args.length == 2 && is2stTime != -1) { + if(sender.isOp()) { + int n = PasswordManager.changeExpires(args[0], is2stTime); + if(n > 0) { + sender.sendMessage("The password for '" + args[0] + "' will expire in " + CommandListPasswords.expiresAfter(n) + "."); + }else { + if(n == -2) { + sender.sendMessage("The password for '" + args[0] + "' will not expire."); + }else { + sender.sendMessage(ChatColor.RED + "Error: this player '" + args[0] + "' does not have a password to renew"); + } + } + }else { + sender.sendMessage(ChatColor.RED + "Error: you need /op to use this command!"); } }else { - sender.sendMessage(ChatColor.RED + "Error: you need /op to use this command!"); + throw new IncorrectUsageException("Illegal argument combination"); } } - + + public static int tryParseTime(String str) { + int expires = -1; + if(str.length() >= 2) { + if(str.equalsIgnoreCase("never") || str.equalsIgnoreCase("infinite") || str.equalsIgnoreCase("infinity")) { + return -2; + } + int mul = 60 * 60 * 24; + String exp = str.toLowerCase(); + if(exp.endsWith("s")) { + mul = 1; + exp = exp.substring(0, exp.length() - 1); + }else if(exp.endsWith("m")) { + mul = 60; + exp = exp.substring(0, exp.length() - 1); + }else if(exp.endsWith("h")) { + mul = 60 * 60; + exp = exp.substring(0, exp.length() - 1); + }else if(exp.endsWith("d")) { + exp = exp.substring(0, exp.length() - 1); + }else if(exp.endsWith("w")) { + mul = 60 * 60 * 24 * 7; + exp = exp.substring(0, exp.length() - 1); + } + try { + expires = Integer.parseInt(exp) * mul; + }catch(NumberFormatException ex) { + } + } + return expires < 0 ? -1 : expires; + } } diff --git a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandSetPassword.java b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandSetPassword.java index 745e145..4ce7c32 100644 --- a/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandSetPassword.java +++ b/bukkit/src/main/java/net/lax1dude/eaglercraft/beta/server/commands/CommandSetPassword.java @@ -19,6 +19,10 @@ public class CommandSetPassword extends EaglerCommand { @Override protected void execute(CommandSender sender, String[] args) { + if(!EaglercraftServer.config.enablePasswordLogin()) { + sender.sendMessage(ChatColor.RED + "Error: password login is disabled"); + return; + } if(!EaglercraftServer.hasPasswordDB()) { sender.sendMessage(ChatColor.RED + "Error: the password database is not initialized, it probably won't save your changes"); } @@ -28,34 +32,27 @@ public class CommandSetPassword extends EaglerCommand { if(args[0].length() > 16) { throw new IncorrectUsageException("the maximum length for a username is 16 characters!"); } - int expires = -1; + if(args[1].length() < 3) { + throw new IncorrectUsageException("A password must be at least 3 characters!"); + } + int expires = EaglercraftServer.config.defaultPasswordExpireTime(); if(args.length == 3) { - int mul = 60 * 60 * 24; - String exp = args[2].toLowerCase(); - if(exp.endsWith("s")) { - mul = 1; - exp = exp.substring(0, exp.length() - 1); - }else if(exp.endsWith("m")) { - mul = 60; - exp = exp.substring(0, exp.length() - 1); - }else if(exp.endsWith("h")) { - mul = 60 * 60; - exp = exp.substring(0, exp.length() - 1); - }else if(exp.endsWith("d")) { - exp = exp.substring(0, exp.length() - 1); - }else if(exp.endsWith("w")) { - mul = 60 * 60 * 24 * 7; - exp = exp.substring(0, exp.length() - 1); + expires = CommandRenewPassword.tryParseTime(args[2]); + if(expires == -1) { + throw new IncorrectUsageException("Expires time is invalid!"); } - try { - expires = Integer.parseInt(exp) * mul; - }catch(NumberFormatException ex) { - throw new IncorrectUsageException("The number '" + exp + "' is invalid!"); - } - if(expires < 1) { - throw new IncorrectUsageException("Expires time must be positive!"); + if(expires == -2) { + expires = -1; } } + if(expires > EaglercraftServer.config.maximumPasswordExpireTime()) { + sender.sendMessage(ChatColor.RED + "Error: the maximum time before a password expires can be at most " + CommandListPasswords.expiresAfter(EaglercraftServer.config.maximumPasswordExpireTime())); + return; + } + if(expires == -1 && !EaglercraftServer.config.allowPasswordsWithoutExpire()) { + sender.sendMessage(ChatColor.RED + "Error: passwords that do not expire are disabled!"); + return; + } PasswordManager.create(args[0], args[1], expires); sender.sendMessage("Password for '" + args[0] + "' was changed"); } diff --git a/bukkit/src/main/java/net/minecraft/server/EaglercraftVanillaNetworkManager.java b/bukkit/src/main/java/net/minecraft/server/EaglercraftVanillaNetworkManager.java index dcff6f3..4a03be9 100644 --- a/bukkit/src/main/java/net/minecraft/server/EaglercraftVanillaNetworkManager.java +++ b/bukkit/src/main/java/net/minecraft/server/EaglercraftVanillaNetworkManager.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class EaglercraftVanillaNetworkManager implements NetworkManager { +public class EaglercraftVanillaNetworkManager extends NetworkManager { public static final Object a = new Object(); public static int b; public static int c; diff --git a/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketListenerThread.java b/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketListenerThread.java index e56bc90..a302fea 100644 --- a/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketListenerThread.java +++ b/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketListenerThread.java @@ -29,7 +29,10 @@ public class EaglercraftWebsocketListenerThread extends WebSocketServer { @Override public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) { - // rip + EaglercraftWebsocketNetworkManager mgr = arg0.getAttachment(); + if(mgr != null && !mgr.disconnected) { + mgr.a("disconnect.close"); + } } @Override diff --git a/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketNetworkManager.java b/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketNetworkManager.java index c012f71..84ab508 100644 --- a/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketNetworkManager.java +++ b/bukkit/src/main/java/net/minecraft/server/EaglercraftWebsocketNetworkManager.java @@ -11,31 +11,23 @@ import java.util.List; import org.java_websocket.WebSocket; -import net.minecraft.server.NetHandler; -import net.minecraft.server.NetServerHandler; -import net.minecraft.server.Packet; - -public class EaglercraftWebsocketNetworkManager implements NetworkManager { +public class EaglercraftWebsocketNetworkManager extends NetworkManager { public static final int PACKET_LIMIT = 300; public static final int PACKET_PER_SECOND_QUOTA = 1000 / 35; - public static final int PACKET_MAX_SIZE = 1536; + public static final int PACKET_MAX_SIZE = 9600; final WebSocket websocket; NetHandler netHandler; - - // Next step: add cooldown to implement 'delayedPackets' private volatile int packetCounter = 0; private long packetDecrement; private int timeoutCounter = 0; - private final List delayedPackets = new LinkedList(); private final List readPackets = new LinkedList(); protected final List writePackets = new LinkedList(); - private boolean delay = false; - private int delayTimer = 0; + public boolean disconnected = false; private final Thread writeThread; protected final Object writeThreadLock = new Object(); @@ -108,6 +100,10 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { manager.websocket.send(ByteBuffer.wrap(pktBytes)); } } + if(manager.disconnected) { + manager.websocket.close(); + break main_loop; + } }catch(Throwable t) { t.printStackTrace(); manager.a("disconnect.closed", "Packet write fault"); @@ -131,18 +127,11 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { */ @Override public void a(Packet var1) { - if (var1.k) { - synchronized(delayedPackets) { - delayedPackets.add(var1); - } - }else { - delay = true; - synchronized(writePackets) { - writePackets.add(var1); - } - synchronized(writeThreadLock) { - writeThreadLock.notify(); - } + synchronized(writePackets) { + writePackets.add(var1); + } + synchronized(writeThreadLock) { + writeThreadLock.notify(); } } @@ -151,10 +140,8 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { */ @Override public void a(String var1, Object... var2) { - if(!websocket.isClosed()) { - netHandler.a(var1, var2); - websocket.close(); - } + netHandler.a(var1, var2); + disconnected = true; } /** @@ -175,7 +162,7 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { } long t = System.currentTimeMillis(); - int decr = (int) ((packetDecrement - t) / PACKET_PER_SECOND_QUOTA); + int decr = (int) ((t - packetDecrement) / PACKET_PER_SECOND_QUOTA); packetCounter -= decr; packetDecrement += decr * PACKET_PER_SECOND_QUOTA; @@ -205,20 +192,6 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { p.a(netHandler); } } - - synchronized(delayedPackets) { - if(!delayedPackets.isEmpty() && (!delay || --delayTimer <= 0)) { - synchronized(writePackets) { - writePackets.add(delayedPackets.remove(0)); - } - synchronized(writeThreadLock) { - writeThreadLock.notify(); - } - delayTimer = 50; - } - } - - delay = false; } /** @@ -242,9 +215,7 @@ public class EaglercraftWebsocketNetworkManager implements NetworkManager { */ @Override public int d() { - synchronized(delayedPackets) { - return delayedPackets.size(); - } + return 0; } @Override diff --git a/bukkit/src/main/java/net/minecraft/server/NetHandler.java b/bukkit/src/main/java/net/minecraft/server/NetHandler.java new file mode 100644 index 0000000..a131141 --- /dev/null +++ b/bukkit/src/main/java/net/minecraft/server/NetHandler.java @@ -0,0 +1,192 @@ +package net.minecraft.server; + +import net.lax1dude.eaglercraft.beta.server.Packet69EaglercraftData; + +public class NetHandler { + public void a(Packet51MapChunk var1) { + } + + public void a(Packet var1) { + } + + public void a(String var1, Object[] var2) { + } + + public void a(Packet255KickDisconnect var1) { + this.a((Packet) var1); + } + + public void a(Packet1Login var1) { + this.a((Packet) var1); + } + + public void a(Packet10Flying var1) { + this.a((Packet) var1); + } + + public void a(Packet52MultiBlockChange var1) { + this.a((Packet) var1); + } + + public void a(Packet14BlockDig var1) { + this.a((Packet) var1); + } + + public void a(Packet53BlockChange var1) { + this.a((Packet) var1); + } + + public void a(Packet50PreChunk var1) { + this.a((Packet) var1); + } + + public void a(Packet20NamedEntitySpawn var1) { + this.a((Packet) var1); + } + + public void a(Packet30Entity var1) { + this.a((Packet) var1); + } + + public void a(Packet34EntityTeleport var1) { + this.a((Packet) var1); + } + + public void a(Packet15Place var1) { + this.a((Packet) var1); + } + + public void a(Packet16BlockItemSwitch var1) { + this.a((Packet) var1); + } + + public void a(Packet29DestroyEntity var1) { + this.a((Packet) var1); + } + + public void a(Packet21PickupSpawn var1) { + this.a((Packet) var1); + } + + public void a(Packet22Collect var1) { + this.a((Packet) var1); + } + + public void a(Packet3Chat var1) { + this.a((Packet) var1); + } + + public void a(Packet23VehicleSpawn var1) { + this.a((Packet) var1); + } + + public void a(Packet18ArmAnimation var1) { + this.a((Packet) var1); + } + + public void a(Packet19EntityAction var1) { + this.a((Packet) var1); + } + + public void a(Packet2Handshake var1) { + this.a((Packet) var1); + } + + public void a(Packet24MobSpawn var1) { + this.a((Packet) var1); + } + + public void a(Packet4UpdateTime var1) { + this.a((Packet) var1); + } + + public void a(Packet6SpawnPosition var1) { + this.a((Packet) var1); + } + + public void a(Packet28EntityVelocity var1) { + this.a((Packet) var1); + } + + public void a(Packet40EntityMetadata var1) { + this.a((Packet) var1); + } + + public void a(Packet39AttachEntity var1) { + this.a((Packet) var1); + } + + public void a(Packet7UseEntity var1) { + this.a((Packet) var1); + } + + public void a(Packet38EntityStatus var1) { + this.a((Packet) var1); + } + + public void a(Packet8UpdateHealth var1) { + this.a((Packet) var1); + } + + public void a(Packet9Respawn var1) { + this.a((Packet) var1); + } + + public void a(Packet60Explosion var1) { + this.a((Packet) var1); + } + + public void a(Packet100OpenWindow var1) { + this.a((Packet) var1); + } + + public void a(Packet101CloseWindow var1) { + this.a((Packet) var1); + } + + public void a(Packet102WindowClick var1) { + this.a((Packet) var1); + } + + public void a(Packet103SetSlot var1) { + this.a((Packet) var1); + } + + public void a(Packet104WindowItems var1) { + this.a((Packet) var1); + } + + public void a(Packet130UpdateSign var1) { + this.a((Packet) var1); + } + + public void a(Packet105CraftProgressBar var1) { + this.a((Packet) var1); + } + + public void a(Packet5EntityEquipment var1) { + this.a((Packet) var1); + } + + public void a(Packet106Transaction var1) { + this.a((Packet) var1); + } + + public void a(Packet25EntityPainting var1) { + this.a((Packet) var1); + } + + public void a(Packet54PlayNoteBlock var1) { + this.a((Packet) var1); + } + + public void a(Packet69EaglercraftData var1) { + this.a((Packet) var1); + } + + public void a(Packet17 var1) { + } + + public void a(Packet27 var1) { + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/minecraft/server/NetLoginHandler.java b/bukkit/src/main/java/net/minecraft/server/NetLoginHandler.java index 76b280d..c262f34 100644 --- a/bukkit/src/main/java/net/minecraft/server/NetLoginHandler.java +++ b/bukkit/src/main/java/net/minecraft/server/NetLoginHandler.java @@ -9,6 +9,9 @@ import java.util.logging.Logger; import org.java_websocket.WebSocket; import net.lax1dude.eaglercraft.beta.server.Base64; +import net.lax1dude.eaglercraft.beta.server.EaglercraftServer; +import net.lax1dude.eaglercraft.beta.server.NetEaglerServerHandler; +import net.lax1dude.eaglercraft.beta.server.Packet69EaglercraftData; import net.lax1dude.eaglercraft.beta.server.PasswordManager; import net.lax1dude.eaglercraft.beta.server.PasswordManager.PasswordEntry; import net.lax1dude.eaglercraft.beta.server.SHA1Digest; @@ -27,6 +30,7 @@ public class NetLoginHandler extends NetHandler { private String wsUsername = null; private PasswordEntry passEntry = null; private byte[] sentSalt = null; + private byte[] skinData = null; private boolean isWebsocket() { return b instanceof EaglercraftWebsocketNetworkManager; @@ -76,19 +80,34 @@ public class NetLoginHandler extends NetHandler { public void a(Packet2Handshake packet2handshake) { if(isWebsocket()) { wsUsername = packet2handshake.a; - passEntry = PasswordManager.load(wsUsername); - if(passEntry == null) { - this.a("You're not registered on this server!"); + if(!validateUsername(wsUsername)) { + this.a("Invalid username!"); return; } - sentSalt = new byte[9]; - synchronized(PasswordManager.rand) { - PasswordManager.rand.nextBytes(sentSalt); + if(EaglercraftServer.config.enablePasswordLogin()) { + passEntry = PasswordManager.load(wsUsername); + if(passEntry == null) { + if(EaglercraftServer.config.requirePasswordLogin()) { + this.a("You're not registered on this server!"); + return; + }else { + sentSalt = new byte[0]; + this.b.a(new Packet2Handshake("NULL")); + } + }else { + sentSalt = new byte[9]; + synchronized(PasswordManager.rand) { + PasswordManager.rand.nextBytes(sentSalt); + } + byte[] sendHash = new byte[18]; + System.arraycopy(passEntry.salt, 0, sendHash, 0, 9); + System.arraycopy(sentSalt, 0, sendHash, 9, 9); + this.b.a(new Packet2Handshake(Base64.encodeBase64String(sendHash))); + } + }else { + sentSalt = new byte[0]; + this.b.a(new Packet2Handshake("NULL")); } - byte[] sendHash = new byte[18]; - System.arraycopy(passEntry.salt, 0, sendHash, 0, 9); - System.arraycopy(sentSalt, 0, sendHash, 9, 9); - this.b.a(new Packet2Handshake(Base64.encodeBase64String(sendHash))); }else { if (this.e.l) { this.i = Long.toHexString(d.nextLong()); @@ -99,6 +118,16 @@ public class NetLoginHandler extends NetHandler { } } + public static boolean validateUsername(String wsUsername2) { + if (wsUsername2.length() < 3 || wsUsername2.length() > 16) { + return false; + }else if(!wsUsername2.equals(wsUsername2.replaceAll("[^A-Za-z0-9\\-_]", "_").trim())) { + return false; + }else { + return true; + } + } + public void a(Packet1Login packet1login) { if (packet1login.a != 9) { if (packet1login.a > 9) { @@ -109,27 +138,39 @@ public class NetLoginHandler extends NetHandler { return; }else { if(isWebsocket()) { - if(wsUsername == null || !wsUsername.equals(packet1login.b)) { + if(wsUsername == null || sentSalt == null || !wsUsername.equals(packet1login.b)) { this.a("Invalid login!"); }else { this.g = packet1login.b; - SHA1Digest dg = new SHA1Digest(); - dg.update(PasswordManager.eaglerSalt, 0, PasswordManager.eaglerSalt.length); - dg.update(sentSalt, 0, 9); - dg.update(passEntry.password, 0, passEntry.password.length); - byte[] o = new byte[20]; - dg.doFinal(o, 0); - - byte[] hsh = Base64.decodeBase64(packet1login.c.replace('-', '+').replace('_', '/')); - if(Arrays.equals(o, hsh)) { - packet1login.c = "-"; - this.h = packet1login; - this.hf = f; + if(packet1login.c.equalsIgnoreCase("NULL")) { + if(sentSalt.length == 0) { + this.h = packet1login; + }else { + this.a(EaglercraftServer.config.requirePasswordLogin() ? "A password is required to join this server!" : "This username requires a password to join!"); + } }else { - this.a("Wrong password!"); + SHA1Digest dg = new SHA1Digest(); + dg.update(PasswordManager.eaglerSalt, 0, PasswordManager.eaglerSalt.length); + dg.update(sentSalt, 0, 9); + dg.update(passEntry.password, 0, passEntry.password.length); + byte[] o = new byte[20]; + dg.doFinal(o, 0); + + byte[] hsh = Base64.decodeBase64(packet1login.c.replace('-', '+').replace('_', '/')); + if(Arrays.equals(o, hsh)) { + packet1login.c = "-"; + this.h = packet1login; + this.hf = f; + }else { + this.a("Wrong password!"); + } } } }else { + if(!validateUsername(packet1login.b)) { + this.a("Invalid username!"); + return; + } this.g = packet1login.b; if (!this.e.l) { this.b(packet1login); @@ -139,12 +180,45 @@ public class NetLoginHandler extends NetHandler { } } } + + public static final int SKIN_DATA_SIZE = 64*32*4; + public void a(Packet69EaglercraftData pkt) { + if(isWebsocket()) { + if(pkt.type.equals("EAG|MySkin")) { + String inv = "Invalid skin"; + if(pkt.data.length < 2) { + this.a(inv); + }else { + int type = (int)pkt.data[0] & 0xFF; + if(type == 0) { + if(pkt.data.length == 2) { + skinData = pkt.data; + }else { + this.a(inv); + } + }else if(type == 1) { + if(pkt.data.length == SKIN_DATA_SIZE + 1) { + skinData = pkt.data; + }else { + this.a(inv); + } + }else { + this.a(inv); + } + } + } + }else { + a((Packet)pkt); + } + } + public void b(Packet1Login packet1login) { EntityPlayer entityplayer = this.e.f.a(this, packet1login.b, packet1login.c); if (entityplayer != null) { a.info(this.b() + " logged in with entity id " + entityplayer.id); - NetServerHandler netserverhandler = new NetServerHandler(this.e, this.b, entityplayer); + NetServerHandler netserverhandler = isWebsocket() ? new NetEaglerServerHandler(this.e, this.b, entityplayer, skinData) : + new NetServerHandler(this.e, this.b, entityplayer); ChunkCoordinates chunkcoordinates = entityplayer.world.l(); netserverhandler.b( new Packet1Login("", "", entityplayer.id, entityplayer.world.j(), (byte) entityplayer.world.m.g)); @@ -162,7 +236,7 @@ public class NetLoginHandler extends NetHandler { } public void a(String s, Object[] aobject) { - a.info(this.b() + " lost connection"); + a.info(this.b() + " was kicked while logging in: " + s); this.c = true; } diff --git a/bukkit/src/main/java/net/minecraft/server/NetworkManager.java b/bukkit/src/main/java/net/minecraft/server/NetworkManager.java index ac1a439..98050c2 100644 --- a/bukkit/src/main/java/net/minecraft/server/NetworkManager.java +++ b/bukkit/src/main/java/net/minecraft/server/NetworkManager.java @@ -2,45 +2,45 @@ package net.minecraft.server; import java.net.SocketAddress; -public interface NetworkManager { +public abstract class NetworkManager { /** * Set the NetHandler */ - void a(NetHandler var1); + abstract void a(NetHandler var1); /** * addToSendQueue */ - void a(Packet var1); + public abstract void a(Packet var1); /** * disconnect */ - void a(String var1, Object... var2); + abstract void a(String var1, Object... var2); /** * processReadPackets */ - void a(); + abstract void a(); /** * gets the remote address */ - SocketAddress b(); + abstract SocketAddress b(); /** * shuts connection down */ - void c(); + public abstract void c(); /** * gets a number of delayed packets */ - int d(); + abstract int d(); /** * gets if the connection is closed */ - boolean isDead(); + abstract boolean isDead(); } diff --git a/bukkit/src/main/java/net/minecraft/server/PacketRegister.java b/bukkit/src/main/java/net/minecraft/server/PacketRegister.java new file mode 100644 index 0000000..68a86ba --- /dev/null +++ b/bukkit/src/main/java/net/minecraft/server/PacketRegister.java @@ -0,0 +1,9 @@ +package net.minecraft.server; + +public class PacketRegister { + + public static void register(int id, Class pkt) { + Packet.a(id, pkt); + } + +} diff --git a/bukkit/src/main/java/net/minecraft/server/PlayerInstance.java b/bukkit/src/main/java/net/minecraft/server/PlayerInstance.java new file mode 100644 index 0000000..e30cb66 --- /dev/null +++ b/bukkit/src/main/java/net/minecraft/server/PlayerInstance.java @@ -0,0 +1,184 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +class PlayerInstance { + private List b; + private int c; + private int d; + private ChunkCoordIntPair e; + private short[] f; + private int g; + private int h; + private int i; + private int j; + private int k; + private int l; + private int m; + final PlayerManager a; + + public PlayerInstance(PlayerManager playermanager, int i, int j) { + this.a = playermanager; + this.b = new ArrayList(); + this.f = new short[10]; + this.g = 0; + this.c = i; + this.d = j; + this.e = new ChunkCoordIntPair(i, j); + playermanager.world.u.d(i, j); + } + + public void a(EntityPlayer entityplayer) { + if (this.b.contains(entityplayer)) { + //throw new IllegalStateException( + // "Failed to add player. " + entityplayer + " already is in chunk " + this.c + ", " + this.d); + } else { + entityplayer.g.add(this.e); + entityplayer.a.b(new Packet50PreChunk(this.e.a, this.e.b, true)); + this.b.add(entityplayer); + entityplayer.f.add(this.e); + } + } + + public void b(EntityPlayer entityplayer) { + if (!this.b.contains(entityplayer)) { + //(new IllegalStateException( + // "Failed to remove player. " + entityplayer + " isn't in chunk " + this.c + ", " + this.d)) + // .printStackTrace(); + } else { + this.b.remove(entityplayer); + if (this.b.size() == 0) { + long i = (long) this.c + 2147483647L | (long) this.d + 2147483647L << 32; + PlayerManager.b(this.a).b(i); + if (this.g > 0) { + PlayerManager.c(this.a).remove(this); + } + + ((WorldServer) entityplayer.world).u.c(this.c, this.d); + } + + entityplayer.f.remove(this.e); + if (entityplayer.g.contains(this.e)) { + entityplayer.a.b(new Packet50PreChunk(this.c, this.d, false)); + } + } + + } + + public void a(int i, int j, int k) { + if (this.g == 0) { + PlayerManager.c(this.a).add(this); + this.h = this.i = i; + this.j = this.k = j; + this.l = this.m = k; + } + + if (this.h > i) { + this.h = i; + } + + if (this.i < i) { + this.i = i; + } + + if (this.j > j) { + this.j = j; + } + + if (this.k < j) { + this.k = j; + } + + if (this.l > k) { + this.l = k; + } + + if (this.m < k) { + this.m = k; + } + + if (this.g < 10) { + short short1 = (short) (i << 12 | k << 8 | j); + + for (int l = 0; l < this.g; ++l) { + if (this.f[l] == short1) { + return; + } + } + + this.f[this.g++] = short1; + } + + } + + public void a(Packet packet) { + for (int i = 0; i < this.b.size(); ++i) { + EntityPlayer entityplayer = (EntityPlayer) this.b.get(i); + if (entityplayer.g.contains(this.e)) { + entityplayer.a.b(packet); + } + } + + } + + public void a() { + if (this.g != 0) { + int i; + int j; + int k; + if (this.g == 1) { + i = this.c * 16 + this.h; + j = this.j; + k = this.d * 16 + this.l; + this.a((Packet) (new Packet53BlockChange(i, j, k, this.a.world))); + if (Block.p[this.a.world.getTypeId(i, j, k)]) { + this.a(this.a.world.getTileEntity(i, j, k)); + } + } else { + int l; + if (this.g == 10) { + this.j = this.j / 2 * 2; + this.k = (this.k / 2 + 1) * 2; + i = this.h + this.c * 16; + j = this.j; + k = this.l + this.d * 16; + l = this.i - this.h + 1; + int i1 = this.k - this.j + 2; + int j1 = this.m - this.l + 1; + this.a((Packet) (new Packet51MapChunk(i, j, k, l, i1, j1, this.a.world))); + List list = this.a.world.d(i, j, k, i + l, j + i1, k + j1); + + for (int k1 = 0; k1 < list.size(); ++k1) { + this.a((TileEntity) list.get(k1)); + } + } else { + this.a((Packet) (new Packet52MultiBlockChange(this.c, this.d, this.f, this.g, this.a.world))); + + for (i = 0; i < this.g; ++i) { + j = this.c * 16 + (this.g >> 12 & 15); + k = this.g & 255; + l = this.d * 16 + (this.g >> 8 & 15); + if (Block.p[this.a.world.getTypeId(j, k, l)]) { + System.out.println("Sending!"); + this.a(this.a.world.getTileEntity(j, k, l)); + } + } + } + } + + this.g = 0; + } + + } + + private void a(TileEntity tileentity) { + if (tileentity != null) { + Packet packet = tileentity.e(); + if (packet != null) { + this.a(packet); + } + } + + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/minecraft/server/PlayerList.java b/bukkit/src/main/java/net/minecraft/server/PlayerList.java new file mode 100644 index 0000000..15dfca3 --- /dev/null +++ b/bukkit/src/main/java/net/minecraft/server/PlayerList.java @@ -0,0 +1,128 @@ +package net.minecraft.server; + +public class PlayerList { + private transient PlayerListEntry[] a = new PlayerListEntry[16]; + private transient int b; + private int c = 12; + private final float d = 0.75F; + private transient volatile int e; + + private static int e(long var0) { + return a((int) (var0 ^ var0 >>> 32)); + } + + private static int a(int var0) { + var0 ^= var0 >>> 20 ^ var0 >>> 12; + return var0 ^ var0 >>> 7 ^ var0 >>> 4; + } + + private static int a(int var0, int var1) { + return var0 & var1 - 1; + } + + public Object a(long var1) { + int var3 = e(var1); + + for (PlayerListEntry var4 = this.a[a(var3, this.a.length)]; var4 != null; var4 = var4.c) { + if (var4.a == var1) { + return var4.b; + } + } + + return null; + } + + public void a(long var1, Object var3) { + int var4 = e(var1); + int var5 = a(var4, this.a.length); + + for (PlayerListEntry var6 = this.a[var5]; var6 != null; var6 = var6.c) { + if (var6.a == var1) { + var6.b = var3; + } + } + + ++this.e; + this.a(var4, var1, var3, var5); + } + + private void b(int var1) { + PlayerListEntry[] var2 = this.a; + int var3 = var2.length; + if (var3 == 1073741824) { + this.c = Integer.MAX_VALUE; + } else { + PlayerListEntry[] var4 = new PlayerListEntry[var1]; + this.a(var4); + this.a = var4; + this.c = (int) ((float) var1 * this.d); + } + } + + private void a(PlayerListEntry[] var1) { + PlayerListEntry[] var2 = this.a; + int var3 = var1.length; + + for (int var4 = 0; var4 < var2.length; ++var4) { + PlayerListEntry var5 = var2[var4]; + if (var5 != null) { + var2[var4] = null; + + PlayerListEntry var6; + do { + var6 = var5.c; + int var7 = a(var5.d, var3); + var5.c = var1[var7]; + var1[var7] = var5; + var5 = var6; + } while (var6 != null); + } + } + + } + + public Object b(long var1) { + PlayerListEntry var3 = this.c(var1); + return var3 == null ? null : var3.b; + } + + final PlayerListEntry c(long var1) { + int var3 = e(var1); + int var4 = a(var3, this.a.length); + PlayerListEntry var5 = this.a[var4]; + + PlayerListEntry var6; + PlayerListEntry var7; + for (var6 = var5; var6 != null; var6 = var7) { + var7 = var6.c; + if (var6.a == var1) { + ++this.e; + --this.b; + if (var5 == var6) { + this.a[var4] = var7; + } else { + var5.c = var7; + } + + return var6; + } + + var5 = var6; + } + + return var6; + } + + private void a(int var1, long var2, Object var4, int var5) { + PlayerListEntry var6 = this.a[var5]; + this.a[var5] = new PlayerListEntry(var1, var2, var4, var6); + if (this.b++ >= this.c) { + this.b(2 * this.a.length); + } + + } + + public PlayerListEntry[] getMap() { + return a; + } +} \ No newline at end of file diff --git a/bukkit/src/main/java/net/minecraft/server/PlayerManager.java b/bukkit/src/main/java/net/minecraft/server/PlayerManager.java new file mode 100644 index 0000000..703b542 --- /dev/null +++ b/bukkit/src/main/java/net/minecraft/server/PlayerManager.java @@ -0,0 +1,181 @@ +package net.minecraft.server; + +import java.util.ArrayList; +import java.util.List; + +public class PlayerManager { + private List a = new ArrayList(); + private PlayerList b = new PlayerList(); + private List c = new ArrayList(); + private MinecraftServer d; + private final int[][] e = new int[][]{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; + public WorldServer world; + + public PlayerManager(MinecraftServer minecraftserver, WorldServer world) { + this.d = minecraftserver; + this.world = world; + } + + public void a() { + for (int i = 0; i < this.c.size(); ++i) { + ((PlayerInstance) this.c.get(i)).a(); + } + + this.c.clear(); + } + + private PlayerInstance a(int i, int j, boolean flag) { + long k = (long) i + 2147483647L | (long) j + 2147483647L << 32; + PlayerInstance playerinstance = (PlayerInstance) this.b.a(k); + if (playerinstance == null && flag) { + playerinstance = new PlayerInstance(this, i, j); + this.b.a(k, playerinstance); + } + + return playerinstance; + } + + public void a(int i, int j, int k) { + int l = i >> 4; + int i1 = k >> 4; + PlayerInstance playerinstance = this.a(l, i1, false); + if (playerinstance != null) { + playerinstance.a(i & 15, j, k & 15); + } + + } + + public void a(EntityPlayer entityplayer) { + int i = (int) entityplayer.locX >> 4; + int j = (int) entityplayer.locZ >> 4; + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; + int k = 0; + byte b0 = 10; + int l = 0; + int i1 = 0; + this.a(i, j, true).a(entityplayer); + + int j1; + for (j1 = 1; j1 <= b0 * 2; ++j1) { + for (int k1 = 0; k1 < 2; ++k1) { + int[] aint = this.e[k++ % 4]; + + for (int l1 = 0; l1 < j1; ++l1) { + l += aint[0]; + i1 += aint[1]; + this.a(i + l, j + i1, true).a(entityplayer); + } + } + } + + k %= 4; + + for (j1 = 0; j1 < b0 * 2; ++j1) { + l += this.e[k][0]; + i1 += this.e[k][1]; + this.a(i + l, j + i1, true).a(entityplayer); + } + + this.a.add(entityplayer); + } + + public void b(EntityPlayer entityplayer) { + /* + int i = (int) entityplayer.d >> 4; + int j = (int) entityplayer.e >> 4; + + for (int k = i - 10; k <= i + 10; ++k) { + for (int l = j - 10; l <= j + 10; ++l) { + PlayerInstance playerinstance = this.a(k, l, false); + if (playerinstance != null) { + playerinstance.b(entityplayer); + } + } + } + */ + + // rewritten to remove player from all loaded chunks + + PlayerListEntry[] et = this.b.getMap(); + + for(int i = 0; i < et.length; ++i) { + for(PlayerListEntry etr = et[i]; etr != null; etr = etr.c) { + if(etr.b != null) { + ((PlayerInstance)etr.b).b(entityplayer); + } + } + } + + this.a.remove(entityplayer); + } + + private boolean a(int i, int j, int k, int l) { + int i1 = i - k; + int j1 = j - l; + return i1 >= -10 && i1 <= 10 ? j1 >= -10 && j1 <= 10 : false; + } + + public void c(EntityPlayer entityplayer) { + int i = (int) entityplayer.locX >> 4; + int j = (int) entityplayer.locZ >> 4; + double d0 = entityplayer.d - entityplayer.locX; + double d1 = entityplayer.e - entityplayer.locZ; + double d2 = d0 * d0 + d1 * d1; + if (d2 >= 64.0D) { + int k = (int) entityplayer.d >> 4; + int l = (int) entityplayer.e >> 4; + int i1 = i - k; + int j1 = j - l; + if (!this.a(i, j, k, l)) { + this.a(i, j, true).a(entityplayer); + } + + if (!this.a(i - i1, j - j1, i, j)) { + PlayerInstance playerinstance = this.a(i - i1, j - j1, false); + if (playerinstance != null) { + playerinstance.b(entityplayer); + } + } + + if (i1 != 0 || j1 != 0) { + for (int k1 = i - 10; k1 <= i + 10; ++k1) { + for (int l1 = j - 10; l1 <= j + 10; ++l1) { + if (k1 != i || l1 != j) { + if (!this.a(k1, l1, k, l)) { + this.a(k1, l1, true).a(entityplayer); + } + + if (!this.a(k1 - i1, l1 - j1, i, j)) { + PlayerInstance playerinstance = this.a(k1 - i1, l1 - j1, false); + if (playerinstance != null) { + playerinstance.b(entityplayer); + } + } + } + } + } + + entityplayer.d = entityplayer.locX; + entityplayer.e = entityplayer.locZ; + } + } + + } + + public int b() { + return 144; + } + + static MinecraftServer a(PlayerManager playermanager) { + return playermanager.d; + } + + static PlayerList b(PlayerManager playermanager) { + return playermanager.b; + } + + static List c(PlayerManager playermanager) { + return playermanager.c; + } +} \ No newline at end of file diff --git a/bukkit/src/main/resources/default_eagler_config.yml b/bukkit/src/main/resources/default_eagler_config.yml new file mode 100644 index 0000000..e7276b6 --- /dev/null +++ b/bukkit/src/main/resources/default_eagler_config.yml @@ -0,0 +1,11 @@ +enable_password_logins: true +only_allow_registered_users_to_login: true +allow_passwords_without_expiration: true +allow_self_registration: false +allow_self_registration_without_expiration: false +allow_self_change_password: true +allow_self_renew_password: true +allow_self_change_password_expiration: false +allow_self_delete_password: false +default_password_expire_time_seconds: 604800 +maximum_password_expire_time_seconds: 1814400 \ No newline at end of file diff --git a/javascript/Singleplayer_Offline_Download.html b/javascript/Singleplayer_Offline_Download.html deleted file mode 100644 index b23c4d4..0000000 --- a/javascript/Singleplayer_Offline_Download.html +++ /dev/null @@ -1,10189 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -eaglercraft singleplayer test local - - - - - - - - - - - - - - - - - - - -
-

THIS IS AN EXPERIMENTAL SINGLEPLAYER BUILD OF EAGLERCRAFT!

-

EXPECT BUGS!

-

this build is from 5/27/2022

-

(Game will launch in 5)

-
- - - \ No newline at end of file diff --git a/lwjgl-rundir/resources/gui/gui.png b/lwjgl-rundir/resources/gui/gui.png index 81af329..d994eaa 100644 Binary files a/lwjgl-rundir/resources/gui/gui.png and b/lwjgl-rundir/resources/gui/gui.png differ diff --git a/lwjgl-rundir/resources/lang/en_US.lang b/lwjgl-rundir/resources/lang/en_US.lang index 9416a8d..fb53f3b 100644 --- a/lwjgl-rundir/resources/lang/en_US.lang +++ b/lwjgl-rundir/resources/lang/en_US.lang @@ -15,6 +15,12 @@ menu.quit=Quit Game menu.editProfile=Edit Profile menu.exitChat=Exit Chat +profile.title=Edit Profile +profile.screenname=Screenname +profile.playerSkin=Player Skin +profile.addSkin=Add Skin +profile.clearSkin=Clear List + selectWorld.title=Select World selectWorld.empty=empty selectWorld.world=World diff --git a/lwjgl-rundir/resources/misc/laxcape.png b/lwjgl-rundir/resources/misc/laxcape.png new file mode 100644 index 0000000..78ff899 Binary files /dev/null and b/lwjgl-rundir/resources/misc/laxcape.png differ diff --git a/lwjgl-rundir/resources/skins/01.default_steve.png b/lwjgl-rundir/resources/skins/01.default_steve.png new file mode 100644 index 0000000..d02b718 Binary files /dev/null and b/lwjgl-rundir/resources/skins/01.default_steve.png differ diff --git a/lwjgl-rundir/resources/skins/02.tennis_steve.png b/lwjgl-rundir/resources/skins/02.tennis_steve.png new file mode 100644 index 0000000..41576e6 Binary files /dev/null and b/lwjgl-rundir/resources/skins/02.tennis_steve.png differ diff --git a/lwjgl-rundir/resources/skins/03.tuxedo_steve.png b/lwjgl-rundir/resources/skins/03.tuxedo_steve.png new file mode 100644 index 0000000..b921f85 Binary files /dev/null and b/lwjgl-rundir/resources/skins/03.tuxedo_steve.png differ diff --git a/lwjgl-rundir/resources/skins/04.athlete_steve.png b/lwjgl-rundir/resources/skins/04.athlete_steve.png new file mode 100644 index 0000000..c7a3986 Binary files /dev/null and b/lwjgl-rundir/resources/skins/04.athlete_steve.png differ diff --git a/lwjgl-rundir/resources/skins/05.cyclist_steve.png b/lwjgl-rundir/resources/skins/05.cyclist_steve.png new file mode 100644 index 0000000..7da2003 Binary files /dev/null and b/lwjgl-rundir/resources/skins/05.cyclist_steve.png differ diff --git a/lwjgl-rundir/resources/skins/06.boxer_steve.png b/lwjgl-rundir/resources/skins/06.boxer_steve.png new file mode 100644 index 0000000..5018dc4 Binary files /dev/null and b/lwjgl-rundir/resources/skins/06.boxer_steve.png differ diff --git a/lwjgl-rundir/resources/skins/07.prisoner_steve.png b/lwjgl-rundir/resources/skins/07.prisoner_steve.png new file mode 100644 index 0000000..4cc80ac Binary files /dev/null and b/lwjgl-rundir/resources/skins/07.prisoner_steve.png differ diff --git a/lwjgl-rundir/resources/skins/08.scottish_steve.png b/lwjgl-rundir/resources/skins/08.scottish_steve.png new file mode 100644 index 0000000..25dcfec Binary files /dev/null and b/lwjgl-rundir/resources/skins/08.scottish_steve.png differ diff --git a/lwjgl-rundir/resources/skins/09.dev_steve.png b/lwjgl-rundir/resources/skins/09.dev_steve.png new file mode 100644 index 0000000..8daf1b3 Binary files /dev/null and b/lwjgl-rundir/resources/skins/09.dev_steve.png differ diff --git a/lwjgl-rundir/resources/skins/10.herobrine.png b/lwjgl-rundir/resources/skins/10.herobrine.png new file mode 100644 index 0000000..a449fc1 Binary files /dev/null and b/lwjgl-rundir/resources/skins/10.herobrine.png differ diff --git a/lwjgl-rundir/resources/skins/11.slime.png b/lwjgl-rundir/resources/skins/11.slime.png new file mode 100644 index 0000000..21fd5dd Binary files /dev/null and b/lwjgl-rundir/resources/skins/11.slime.png differ diff --git a/lwjgl-rundir/resources/skins/12.trump.png b/lwjgl-rundir/resources/skins/12.trump.png new file mode 100644 index 0000000..0e48b12 Binary files /dev/null and b/lwjgl-rundir/resources/skins/12.trump.png differ diff --git a/lwjgl-rundir/resources/skins/13.notch.png b/lwjgl-rundir/resources/skins/13.notch.png new file mode 100644 index 0000000..2c3abfa Binary files /dev/null and b/lwjgl-rundir/resources/skins/13.notch.png differ diff --git a/lwjgl-rundir/resources/skins/14.creeper.png b/lwjgl-rundir/resources/skins/14.creeper.png new file mode 100644 index 0000000..9bdeb9e Binary files /dev/null and b/lwjgl-rundir/resources/skins/14.creeper.png differ diff --git a/lwjgl-rundir/resources/skins/15.zombie.png b/lwjgl-rundir/resources/skins/15.zombie.png new file mode 100644 index 0000000..9c57fb0 Binary files /dev/null and b/lwjgl-rundir/resources/skins/15.zombie.png differ diff --git a/lwjgl-rundir/resources/skins/16.pig.png b/lwjgl-rundir/resources/skins/16.pig.png new file mode 100644 index 0000000..11213e9 Binary files /dev/null and b/lwjgl-rundir/resources/skins/16.pig.png differ diff --git a/lwjgl-rundir/resources/skins/17.squid.png b/lwjgl-rundir/resources/skins/17.squid.png new file mode 100644 index 0000000..9dd9dcd Binary files /dev/null and b/lwjgl-rundir/resources/skins/17.squid.png differ diff --git a/lwjgl-rundir/resources/skins/18.mooshroom.png b/lwjgl-rundir/resources/skins/18.mooshroom.png new file mode 100644 index 0000000..2e80e39 Binary files /dev/null and b/lwjgl-rundir/resources/skins/18.mooshroom.png differ diff --git a/src/lwjgl/java/net/lax1dude/eaglercraft/anvil/SaveFormatOld.java b/src/lwjgl/java/net/lax1dude/eaglercraft/anvil/SaveFormatOld.java index c081532..0c682ad 100644 --- a/src/lwjgl/java/net/lax1dude/eaglercraft/anvil/SaveFormatOld.java +++ b/src/lwjgl/java/net/lax1dude/eaglercraft/anvil/SaveFormatOld.java @@ -29,7 +29,7 @@ public class SaveFormatOld implements ISaveFormat { return "Old Format"; } - public List getWorldList() { + public List getWorldList(IProgressUpdate progress) { ArrayList arraylist = new ArrayList(); for (int i = 0; i < 5; i++) { String s = (new StringBuilder()).append("World").append(i + 1).toString(); diff --git a/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java b/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java index de107f7..868a69a 100644 --- a/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java +++ b/src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java @@ -4,7 +4,7 @@ public class ConfigConstants { public static boolean profanity = false; - public static final String version = "22w21a-SNAPSHOT"; + public static final String version = "22w22a"; public static final String mainMenuString = "eaglercraft beta-" + version; public static final String forkMe = "https://github.com/LAX1DUDE/eaglercraft"; diff --git a/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java b/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java new file mode 100644 index 0000000..c09213a --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java @@ -0,0 +1,389 @@ +package net.lax1dude.eaglercraft; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.minecraft.client.Minecraft; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.RenderEngine; + +public class EaglerProfile { + + public static class EaglerProfileSkin { + public String name; + public byte[] data; + public boolean slim; + public int glTex; + public EaglerProfileSkin(String name, byte[] data, boolean slim, int glTex) { + this.name = name; + this.data = data; + this.slim = slim; + this.glTex = glTex; + } + } + + public static String username; + public static int presetSkinId; + public static int customSkinId; + + public static String myChannel; + + public static final int SKIN_DATA_SIZE = 64*32*4; + public static ArrayList skins = new ArrayList(); + + public static final EaglercraftRandom rand; + + public static byte[] getSelfSkinPacket() { + if(presetSkinId == -1) { + byte[] d = skins.get(customSkinId).data; + byte[] d2 = new byte[1 + d.length]; + d2[0] = (byte) 1; + System.arraycopy(d, 0, d2, 1, d.length); + return d2; + }else { + return new byte[] { (byte)0, (byte)presetSkinId }; + } + } + + public static String[] concatArrays(String[] a, String[] b) { + String[] r = new String[a.length + b.length]; + System.arraycopy(a, 0, r, 0, a.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; + } + + public static int addSkin(String name, byte[] data, boolean slim) { + int i = -1; + for(int j = 0, l = skins.size(); j < l; ++j) { + if(skins.get(j).name.equalsIgnoreCase(name)) { + i = j; + break; + } + } + + if(data.length != SKIN_DATA_SIZE) { + return -1; + } + + int im = Minecraft.getMinecraft().renderEngine.allocateAndSetupTexture(data, 64, 32); + if(i == -1) { + i = skins.size(); + skins.add(new EaglerProfileSkin(name, data, slim, im)); + }else { + skins.get(i).glTex = im; + skins.get(i).data = data; + skins.get(i).slim = slim; + } + return i; + + } + + private static class CachedSkin { + + protected final String username; + protected UserSkin skin; + protected long age; + + protected CachedSkin(String username, UserSkin skin) { + this.username = username; + this.skin = skin; + this.age = System.currentTimeMillis(); + } + + } + + public static enum EnumSkinType { + PRESET, CUSTOM_LEGACY + } + + public static interface UserSkin { + + abstract EnumSkinType getSkinType(); + abstract int getSkin(); + abstract int getTexture(); + abstract void free(); + + } + + private static class UserPresetSkin implements UserSkin { + + protected final int skinType; + + protected UserPresetSkin(int skin) { + this.skinType = skin; + } + + @Override + public EnumSkinType getSkinType() { + return EnumSkinType.PRESET; + } + + @Override + public int getSkin() { + return skinType; + } + + @Override + public int getTexture() { + return (skinType >= defaultOptionsTextures.length || skinType < 0) ? -1 : defaultOptionsTextures[skinType].getTexturePointer(); + } + + @Override + public void free() { + } + + } + + private static class UserCustomSkin implements UserSkin { + + protected final byte[] data; + protected int glTexture; + + protected UserCustomSkin(byte[] data) { + this.data = data; + this.glTexture = -1; + } + + @Override + public EnumSkinType getSkinType() { + return EnumSkinType.CUSTOM_LEGACY; + } + + @Override + public int getSkin() { + return -1; + } + + @Override + public int getTexture() { + RenderEngine r = Minecraft.getMinecraft().renderEngine; + if(glTexture == -1) { + glTexture = r.allocateAndSetupTexture(data, 64, 32); + } + return glTexture; + } + + @Override + public void free() { + RenderEngine r = Minecraft.getMinecraft().renderEngine; + r.deleteTexture(glTexture); + glTexture = -1; + } + + } + + private static class WaitingSkin { + + protected final int cookie; + protected final String username; + protected final long requestStartTime; + + protected WaitingSkin(int cookie, String username) { + this.cookie = cookie; + this.username = username; + this.requestStartTime = System.currentTimeMillis(); + } + + } + + private static final Map multiplayerWaitingSkinCache = new HashMap(); + private static final Map multiplayerSkinCache = new HashMap(); + private static final long maxSkinAge = 1000l * 60l * 5l; + + private static final UserSkin defaultSkin = new UserPresetSkin(0); + + private static int skinRequestId = 0; + + public static int beginSkinRequest(String un) { + int ret = skinRequestId++; + if(skinRequestId >= 65536) { + skinRequestId = 0; + } + multiplayerWaitingSkinCache.put(ret, new WaitingSkin(ret, un)); + return ret; + } + + public static boolean skinRequestPending(String un) { + return multiplayerWaitingSkinCache.containsKey(un); + } + + public static UserSkin getUserSkin(String un) { + CachedSkin cs = multiplayerSkinCache.get(un); + if(cs == null) { + return null; + }else { + cs.age = System.currentTimeMillis(); + return cs.skin; + } + } + + public static void processSkinResponse(byte[] dat) { + if(dat.length >= 3) { + int cookie = (((int)dat[0] & 0xFF) << 8) | ((int)dat[1] & 0xFF); + WaitingSkin st = multiplayerWaitingSkinCache.remove(cookie); + if(st != null) { + int t = (int)dat[2] & 0xFF; + if(t == 0) { + if(dat.length == 4) { + multiplayerSkinCache.put(st.username, new CachedSkin(st.username, new UserPresetSkin((int)dat[3] & 0xFF))); + }else { + System.out.println("Recieved a PRESET skin of the wrong size (" + (dat.length - 3) + ") for player " + st + "."); + } + }else if(t == 1) { + if(dat.length == 3 + SKIN_DATA_SIZE) { + byte[] datt = new byte[SKIN_DATA_SIZE]; + System.arraycopy(dat, 3, datt, 0, SKIN_DATA_SIZE); + multiplayerSkinCache.put(st.username, new CachedSkin(st.username, new UserCustomSkin(datt))); + }else { + System.out.println("Recieved a CUSTOM_LEGACY skin of the wrong size (" + (dat.length - 3) + ") for player " + st + "."); + } + }else { + System.out.println("Unsupported skin type '" + t + "' was recieved from server for player " + st + "."); + } + } + } + } + + public static void freeSkins() { + long millis = System.currentTimeMillis(); + Iterator skns = multiplayerSkinCache.values().iterator(); + while(skns.hasNext()) { + CachedSkin cs = skns.next(); + if(millis - cs.age > maxSkinAge) { + cs.skin.free(); + skns.remove(); + } + } + Iterator skns2 = multiplayerWaitingSkinCache.values().iterator(); + while(skns2.hasNext()) { + WaitingSkin cs = skns2.next(); + if(millis - cs.requestStartTime > 10000l) { + skns2.remove(); + } + } + } + + public static void freeUserSkin(String un) { + CachedSkin cs = multiplayerSkinCache.remove(un); + if(cs != null) { + cs.skin.free(); + } + } + + public static void freeAllSkins() { + Iterator skns = multiplayerSkinCache.values().iterator(); + while(skns.hasNext()) { + skns.next().skin.free(); + } + multiplayerWaitingSkinCache.clear(); + multiplayerSkinCache.clear(); + } + + static { + String[] usernameDefaultWords = ConfigConstants.profanity ? new String[] { + "Eagler", + "Eagler", + "Bitch", + "Cock", + "Milf", + "Milf", + "Yeer", + "Groon", + "Eag", + "Deevis", + "Chode", + "Deev", + "Deev", + "Fucker", + "Fucking", + "Dumpster", + "Dumpster", + "Cum", + "Chad", + "Egg", + "Fudgler", + "Fudgli", + "Yee", + "Yee", + "Yee", + "Yeet", + "Flumpter", + "Darvy", + "Darver", + "Darver", + "Fuck", + "Fuck", + "Frick", + "Eagler", + "Vigg", + "Vigg", + "Cunt", + "Darvig" + } : new String[] { + "Yeeish", + "Yeeish", + "Yee", + "Yee", + "Yeer", + "Yeeler", + "Eagler", + "Eagl", + "Darver", + "Darvler", + "Vool", + "Vigg", + "Vigg", + "Deev", + "Yigg", + "Yeeg" + }; + + rand = new EaglercraftRandom(); + + do { + username = usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + (10 + rand.nextInt(90)); + }while(username.length() > 16); + + presetSkinId = rand.nextInt(GuiScreenEditProfile.defaultOptions.length); + myChannel = username + "_" + (100 + rand.nextInt(900)); + customSkinId = -1; + } + + public static void loadFromStorage() { + if(!LocalStorageManager.profileSettingsStorage.hasNoTags()) { + presetSkinId = LocalStorageManager.profileSettingsStorage.getInteger("ps"); + customSkinId = LocalStorageManager.profileSettingsStorage.getInteger("cs"); + username = LocalStorageManager.profileSettingsStorage.getString("name"); + myChannel = username + "_" + (100 + rand.nextInt(900)); + NBTTagCompound n = LocalStorageManager.profileSettingsStorage.getCompoundTag("skins"); + for(Object s : NBTTagCompound.getTagMap(n).keySet()) { + String s2 = (String)s; + addSkin(s2, n.getByteArray(s2), false); + } + } + } + + public static final TextureLocation[] defaultOptionsTextures = new TextureLocation[] { + new TextureLocation("/skins/01.default_steve.png"), + new TextureLocation("/skins/02.tennis_steve.png"), + new TextureLocation("/skins/03.tuxedo_steve.png"), + new TextureLocation("/skins/04.athlete_steve.png"), + new TextureLocation("/skins/05.cyclist_steve.png"), + new TextureLocation("/skins/06.boxer_steve.png"), + new TextureLocation("/skins/07.prisoner_steve.png"), + new TextureLocation("/skins/08.scottish_steve.png"), + new TextureLocation("/skins/09.dev_steve.png"), + new TextureLocation("/skins/10.herobrine.png"), + new TextureLocation("/skins/11.slime.png"), + new TextureLocation("/skins/12.trump.png"), + new TextureLocation("/skins/13.notch.png"), + new TextureLocation("/skins/14.creeper.png"), + new TextureLocation("/skins/15.zombie.png"), + new TextureLocation("/skins/16.pig.png"), + new TextureLocation("/skins/17.squid.png"), + new TextureLocation("/skins/18.mooshroom.png") + }; + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java new file mode 100644 index 0000000..87bdfee --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java @@ -0,0 +1,401 @@ +package net.lax1dude.eaglercraft; + +import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileSkin; +import net.minecraft.client.Minecraft; +import net.minecraft.src.GuiButton; +import net.minecraft.src.GuiScreen; +import net.minecraft.src.GuiTextField; +import net.minecraft.src.ModelBiped; +import net.minecraft.src.NBTTagCompound; +import net.minecraft.src.RenderHelper; +import net.minecraft.src.Session; +import net.minecraft.src.StringTranslate; + +public class GuiScreenEditProfile extends GuiScreen { + + private GuiScreen parent; + private GuiTextField username; + + private boolean dropDownOpen = false; + private String[] dropDownOptions; + private int slotsVisible = 0; + private int selectedSlot = 0; + private int scrollPos = -1; + private int skinsHeight = 0; + private boolean dragging = false; + private int mousex = 0; + private int mousey = 0; + + private static final TextureLocation gui = new TextureLocation("/gui/gui.png"); + + public static final String[] defaultOptions = new String[] { + "Default Steve", + "Tennis Steve", + "Tuxedo Steve", + "Athlete Steve", + "Cyclist Steve", + "Boxer Steve", + "Prisoner Steve", + "Scottish Steve", + "Developer Steve", + "Herobrine", + "Slime", + "Trump", + "Notch", + "Creeper", + "Zombie", + "Pig", + "Squid", + "Mooshroom" + }; + + public static final TextureLocation[] defaultOptionsTextures = new TextureLocation[] { + new TextureLocation("/skins/01.default_steve.png"), + new TextureLocation("/skins/02.tennis_steve.png"), + new TextureLocation("/skins/03.tuxedo_steve.png"), + new TextureLocation("/skins/04.athlete_steve.png"), + new TextureLocation("/skins/05.cyclist_steve.png"), + new TextureLocation("/skins/06.boxer_steve.png"), + new TextureLocation("/skins/07.prisoner_steve.png"), + new TextureLocation("/skins/08.scottish_steve.png"), + new TextureLocation("/skins/09.dev_steve.png"), + new TextureLocation("/skins/10.herobrine.png"), + new TextureLocation("/skins/11.slime.png"), + new TextureLocation("/skins/12.trump.png"), + new TextureLocation("/skins/13.notch.png"), + new TextureLocation("/skins/14.creeper.png"), + new TextureLocation("/skins/15.zombie.png"), + new TextureLocation("/skins/16.pig.png"), + new TextureLocation("/skins/17.squid.png"), + new TextureLocation("/skins/18.mooshroom.png") + }; + + protected String screenTitle = "Edit Profile"; + + public GuiScreenEditProfile(GuiScreen parent) { + this.parent = parent; + reconcatDD(); + } + + private void reconcatDD() { + String[] n = new String[EaglerProfile.skins.size()]; + for(int i = 0; i < n.length; ++i) { + n[i] = EaglerProfile.skins.get(i).name; + } + + this.dropDownOptions = EaglerProfile.concatArrays(n, defaultOptions); + } + + private GuiButton button0, button1, button2, button10, button11, button12; + + public void initGui() { + super.initGui(); + EaglerAdapter.enableRepeatEvents(true); + StringTranslate var1 = StringTranslate.getInstance(); + this.screenTitle = var1.translateKey("profile.title"); + this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20, EaglerProfile.username); + this.username.field_22081_b = true; + selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.skins.size()); + //this.buttonList.add(new GuiButton(0, this.width / 2 - 100, 140, "eeeee")); + this.controlList.add(button0 = new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done"))); + this.controlList.add(button1 = new GuiButton(2, this.width / 2 - 21, this.height / 6 + 110, 71, 20, var1.translateKey("profile.addSkin"))); + this.controlList.add(button2 = new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 110, 72, 20, var1.translateKey("profile.clearSkin"))); + //this.buttonList.add(new GuiButton(200, this.width / 2, this.height / 6 + 72, 150, 20, var1.translateKey("gui.done"))); + } + + private static ModelBiped playerModel = null; + + public void drawScreen(int mx, int my, float par3) { + StringTranslate var1 = StringTranslate.getInstance(); + this.drawDefaultBackground(); + this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215); + this.drawString(this.fontRenderer, var1.translateKey("profile.screenname"), this.width / 2 - 20, this.height / 6 + 8, 10526880); + this.drawString(this.fontRenderer, var1.translateKey("profile.playerSkin"), this.width / 2 - 20, this.height / 6 + 66, 10526880); + + mousex = mx; + mousey = my; + + int skinX = this.width / 2 - 120; + int skinY = this.height / 6 + 8; + int skinWidth = 80; + int skinHeight = 130; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, 0xff000015); + + this.username.drawTextBox(); + if(dropDownOpen) { + super.drawScreen(0, 0, par3); + }else { + super.drawScreen(mx, my, par3); + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 82; + skinWidth = 140; + skinHeight = 22; + + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 21, skinY + skinHeight - 1, -16777216); + drawRect(skinX + skinWidth - 20, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + + EaglerAdapter.glColor4f(1f, 1f, 1f, 1f); + gui.bindTexture(); + drawTexturedModalRect(skinX + skinWidth - 18, skinY + 3, 0, 240, 16, 16); + + this.fontRenderer.drawStringWithShadow(dropDownOptions[selectedSlot], skinX + 5, skinY + 7, 14737632); + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 103; + skinWidth = 140; + skinHeight = (this.height - skinY - 10); + slotsVisible = (skinHeight / 10); + if(slotsVisible > dropDownOptions.length) slotsVisible = dropDownOptions.length; + skinHeight = slotsVisible * 10 + 7; + skinsHeight = skinHeight; + if(scrollPos == -1) { + scrollPos = selectedSlot - 2; + } + if(scrollPos > (dropDownOptions.length - slotsVisible)) { + scrollPos = (dropDownOptions.length - slotsVisible); + } + if(scrollPos < 0) { + scrollPos = 0; + } + if(dropDownOpen) { + drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336); + drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216); + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + if(selectedSlot == i + scrollPos) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffffff); + }else if(mx >= skinX && mx < (skinX + skinWidth - 10) && my >= (skinY + i*10 + 5) && my < (skinY + i*10 + 15)) { + drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x55ffffff); + } + this.fontRenderer.drawStringWithShadow(dropDownOptions[i + scrollPos], skinX + 5, skinY + 5 + i*10, 14737632); + } + } + int scrollerSize = skinHeight * slotsVisible / dropDownOptions.length; + int scrollerPos = skinHeight * scrollPos / dropDownOptions.length; + drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888); + } + + int xx = this.width / 2 - 80; + int yy = this.height / 6 + 130; + skinX = this.width / 2 - 120; + skinY = this.height / 6 + 8; + skinWidth = 80; + skinHeight = 130; + + int id = selectedSlot - EaglerProfile.skins.size(); + + if(id < 0) { + Minecraft.getMinecraft().renderEngine.bindTexture(EaglerProfile.skins.get(selectedSlot).glTex); + }else { + defaultOptionsTextures[id].bindTexture(); + } + + EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D); + EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); + EaglerAdapter.glDisable(EaglerAdapter.GL_CULL_FACE); + EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + EaglerAdapter.glPushMatrix(); + EaglerAdapter.glTranslatef((float) xx, (float) (yy - 80), 100.0F); + EaglerAdapter.glScalef(50.0f, 50.0f, 50.0f); + EaglerAdapter.glRotatef(180.0f, 1.0f, 0.0f, 0.0f); + RenderHelper.enableStandardItemLighting(); + EaglerAdapter.glScalef(1.0F, -1.0F, 1.0F); + EaglerAdapter.glTranslatef(0.0F, 1.0F, 0.0F); + EaglerAdapter.glRotatef(((yy - my) * -0.06f), 1.0f, 0.0f, 0.0f); + EaglerAdapter.glRotatef(((xx - mx) * 0.06f), 0.0f, 1.0f, 0.0f); + EaglerAdapter.glTranslatef(0.0F, -1.0F, 0.0F); + + if(playerModel == null) { + playerModel = new ModelBiped(0.0f); + playerModel.blockTransparentSkins = true; + } + + playerModel.render(0.0f, 0.0f, (float)(System.currentTimeMillis() % 100000) / 50f, ((xx - mx) * 0.06f), ((yy - my) * -0.1f), 0.0625F); + + EaglerAdapter.glPopMatrix(); + EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND); + EaglerAdapter.glEnable(EaglerAdapter.GL_CULL_FACE); + + } + + public void handleMouseInput() { + super.handleMouseInput(); + if(dropDownOpen) { + int var1 = EaglerAdapter.mouseGetEventDWheel(); + if(var1 < 0) { + scrollPos += 3; + } + if(var1 > 0) { + scrollPos -= 3; + } + if(scrollPos < 0) { + scrollPos = 0; + } + if(scrollPos > defaultOptions.length + EaglerProfile.skins.size()) { + scrollPos = defaultOptions.length + EaglerProfile.skins.size(); + } + } + } + + private void save() { + EaglerProfile.username = this.username.getTextBoxText().length() == 0 ? "null" : this.username.getTextBoxText(); + mc.session = new Session(EaglerProfile.username, "-"); + EaglerProfile.presetSkinId = selectedSlot - EaglerProfile.skins.size(); + if(EaglerProfile.presetSkinId < 0) { + EaglerProfile.presetSkinId = -1; + EaglerProfile.customSkinId = selectedSlot; + }else { + EaglerProfile.customSkinId = -1; + } + + LocalStorageManager.profileSettingsStorage.setInteger("ps", EaglerProfile.presetSkinId); + LocalStorageManager.profileSettingsStorage.setInteger("cs", EaglerProfile.customSkinId); + LocalStorageManager.profileSettingsStorage.setString("name", EaglerProfile.username); + + NBTTagCompound skins = new NBTTagCompound(); + for(int i = 0, l = EaglerProfile.skins.size(); i < l; i++) { + skins.setByteArray(EaglerProfile.skins.get(i).name, EaglerProfile.skins.get(i).data); + } + LocalStorageManager.profileSettingsStorage.setCompoundTag("skins", skins); + + LocalStorageManager.saveStorageP(); + } + + protected void actionPerformed(GuiButton par1GuiButton) { + if(!dropDownOpen) { + if(par1GuiButton.id == 200) { + save(); + this.mc.displayGuiScreen((GuiScreen) parent); + }else if(par1GuiButton.id == 2) { + EaglerAdapter.openFileChooser("png", "image/png"); + }else if(par1GuiButton.id == 3) { + for(EaglerProfileSkin i : EaglerProfile.skins) { + this.mc.renderEngine.deleteTexture(i.glTex); + } + EaglerProfile.skins.clear(); + this.dropDownOptions = defaultOptions; + this.selectedSlot = 0; + save(); + } + } + } + + public void updateScreen() { + this.username.onUpdate(); + + if(dropDownOpen) { + if(EaglerAdapter.mouseIsButtonDown(0)) { + int skinX = this.width / 2 - 20; + int skinY = this.height / 6 + 103; + int skinWidth = 140; + if(mousex >= (skinX + skinWidth - 10) && mousex < (skinX + skinWidth) && mousey >= skinY && mousey < (skinY + skinsHeight)) { + dragging = true; + } + if(dragging) { + int scrollerSize = skinsHeight * slotsVisible / dropDownOptions.length; + scrollPos = (mousey - skinY - (scrollerSize / 2)) * dropDownOptions.length / skinsHeight; + } + }else { + dragging = false; + } + }else { + dragging = false; + } + + byte[] b; + if((b = EaglerAdapter.getFileChooserResult()) != null && b.length > 0) { + EaglerImage img = EaglerAdapter.loadPNG(b); + if(!((img.w == 64 && img.h == 32) || (img.w == 64 && img.h == 64) || (img.w == 128 && img.h == 64) || (img.w == 128 && img.h == 128))) return; + byte[] rawSkin = new byte[img.data.length * 4]; + for(int i = 0; i < img.data.length; i++) { + int i2 = i * 4; int i3 = img.data[i]; + rawSkin[i2] = (byte)(i3 >> 16); + rawSkin[i2 + 1] = (byte)(i3 >> 8); + rawSkin[i2 + 2] = (byte)(i3); + rawSkin[i2 + 3] = (byte)(i3 >> 24); + } + String name = EaglerAdapter.getFileChooserResultName(); + if(name.length() > 32) { + name = name.substring(0, 32); + } + int k; + if((k = EaglerProfile.addSkin(name, rawSkin, false)) != -1) { + selectedSlot = k; + reconcatDD(); + save(); + } + } + } + + public void onGuiClosed() { + EaglerAdapter.enableRepeatEvents(false); + } + + + protected void keyTyped(char par1, int par2) { + this.username.handleKeyboardInput(par1, par2); + + String text = username.getTextBoxText(); + if(text.length() > 16) text = text.substring(0, 16); + text = text.replaceAll("[^A-Za-z0-9\\-_]", "_"); + this.username.setTextBoxText(text); + + if(par2 == 200 && selectedSlot > 0) { + --selectedSlot; + scrollPos = selectedSlot - 2; + } + if(par2 == 208 && selectedSlot < (dropDownOptions.length - 1)) { + ++selectedSlot; + scrollPos = selectedSlot - 2; + } + } + + protected void mouseClicked(int par1, int par2, int par3) { + super.mouseClicked(par1, par2, par3); + this.username.handleMouseInput(par1, par2, par3); + + if (par3 == 0) { + int skinX = this.width / 2 + 140 - 40; + int skinY = this.height / 6 + 82; + + if(par1 >= skinX && par1 < (skinX + 20) && par2 >= skinY && par2 < (skinY + 22)) { + dropDownOpen = !dropDownOpen; + } + + skinX = this.width / 2 - 20; + skinY = this.height / 6 + 82; + int skinWidth = 140; + int skinHeight = skinsHeight; + + if(!(par1 >= skinX && par1 < (skinX + skinWidth) && par2 >= skinY && par2 < (skinY + skinHeight + 22))) { + dropDownOpen = false; + dragging = false; + } + + skinY += 21; + + if(dropDownOpen && !dragging) { + for(int i = 0; i < slotsVisible; i++) { + if(i + scrollPos < dropDownOptions.length) { + if(selectedSlot != i + scrollPos) { + if(par1 >= skinX && par1 < (skinX + skinWidth - 10) && par2 >= (skinY + i*10 + 5) && par2 < (skinY + i*10 + 15) && selectedSlot != i + scrollPos) { + selectedSlot = i + scrollPos; + dropDownOpen = false; + dragging = false; + } + } + } + } + } + + } + } + + + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java b/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java index a04ee9b..c8481bc 100644 --- a/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java +++ b/src/main/java/net/lax1dude/eaglercraft/TextureLocation.java @@ -22,7 +22,7 @@ public class TextureLocation { } } - public void bindTexture() { + public int getTexturePointer() { RenderEngine r = Minecraft.getMinecraft().renderEngine; if (glObject == -1) { glObject = r.getTexture(path); @@ -30,7 +30,15 @@ public class TextureLocation { System.err.println("could not load: " + path); } } - r.bindTexture(glObject); + return glObject; + } + + public void bindTexture() { + RenderEngine r = Minecraft.getMinecraft().renderEngine; + int i = getTexturePointer(); + if(i != -1) { + r.bindTexture(i); + } } private static final ArrayList locations = new ArrayList(); diff --git a/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java b/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java index c62545b..9deff54 100644 --- a/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/WebsocketNetworkManager.java @@ -140,4 +140,8 @@ public class WebsocketNetworkManager { return this.serverURI; } + public boolean isSocketOpen() { + return EaglerAdapter.connectionOpen(); + } + } diff --git a/src/main/java/net/lax1dude/eaglercraft/beta/EaglercraftSaveManager.java b/src/main/java/net/lax1dude/eaglercraft/beta/EaglercraftSaveManager.java index f011170..8b4d54a 100644 --- a/src/main/java/net/lax1dude/eaglercraft/beta/EaglercraftSaveManager.java +++ b/src/main/java/net/lax1dude/eaglercraft/beta/EaglercraftSaveManager.java @@ -39,7 +39,8 @@ public class EaglercraftSaveManager implements ISaveFormat { } @Override - public List getWorldList() { + public List getWorldList(IProgressUpdate progress) { + progress.displayLoadingString("Loading Worlds...", "just wait a moment"); ArrayList lst = new ArrayList<>(); EaglerAdapter.listFilesAndDirectories(directory).forEach(new Consumer() { @Override diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java index c31fb69..ae63fcc 100644 --- a/src/main/java/net/minecraft/client/Minecraft.java +++ b/src/main/java/net/minecraft/client/Minecraft.java @@ -5,7 +5,9 @@ package net.minecraft.client; import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.EaglerProfile; import net.lax1dude.eaglercraft.GuiMultiplayer; +import net.lax1dude.eaglercraft.GuiScreenEditProfile; import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.adapter.Tessellator; import net.lax1dude.eaglercraft.beta.EaglercraftSaveManager; @@ -91,15 +93,18 @@ public abstract class Minecraft implements Runnable { EaglerAdapter.glViewport(0, 0, displayWidth, displayHeight); effectRenderer = new EffectRenderer(theWorld, renderEngine); checkGLError("Post startup"); - + + EaglerProfile.loadFromStorage(); + session = new Session(EaglerProfile.username, "-"); + while(EaglerAdapter.keysNext()); while(EaglerAdapter.mouseNext()); ingameGUI = new GuiIngame(this); String srv = EaglerAdapter.getServerToJoinOnLaunch(); if (srv != null && srv.length() > 0) { - displayGuiScreen(new GuiMultiplayer(new GuiMainMenu(), srv)); + displayGuiScreen(new GuiScreenEditProfile(new GuiMultiplayer(new GuiMainMenu(), srv))); } else { - displayGuiScreen(new GuiMainMenu()); + displayGuiScreen(new GuiScreenEditProfile(new GuiMainMenu())); } } @@ -551,8 +556,18 @@ public abstract class Minecraft implements Runnable { playerController.updateController(); if(++holdStillTimer == 150) { if (thePlayer != null) { - ingameGUI.addChatMessage("Note, the game can lag when chunks are generated"); - ingameGUI.addChatMessage("hold still for a few moments and the lag will stop"); + if(isMultiplayerWorld()) { + //ingameGUI.addChatMessage("Known Multiplayer Bugs:"); + //ingameGUI.addChatMessage(" - chunks may not show until you move around"); + //ingameGUI.addChatMessage(" - block crack animation is fucked up"); + }else { + ingameGUI.addChatMessage("Note, the game can lag when chunks are generated"); + ingameGUI.addChatMessage("hold still for a few moments and the lag will stop"); + } + } + }else if(holdStillTimer == 10) { + if(isMultiplayerWorld()) { + renderGlobal.loadRenderers(); // dammit } } } @@ -705,6 +720,7 @@ public abstract class Minecraft implements Runnable { theWorld.difficultySetting = 3; } if (!isWorldLoaded) { + EaglerProfile.freeSkins(); entityRenderer.updateRenderer(); } if (!isWorldLoaded) { @@ -749,7 +765,6 @@ public abstract class Minecraft implements Runnable { } public void startWorld(String s, String s1, long l) { - holdStillTimer = 0; changeWorld1(null); System.gc(); if (field_22008_V.worldNeedsConvert_maybe(s)) { @@ -802,6 +817,7 @@ public abstract class Minecraft implements Runnable { } public void changeWorld2(World world, String s) { + holdStillTimer = 0; changeWorld(world, s, null); } @@ -859,6 +875,7 @@ public abstract class Minecraft implements Runnable { field_22009_h = thePlayer; mouseHelper.grabMouse(); } else { + EaglerProfile.freeAllSkins(); ungrabMouseCursor(); thePlayer = null; } diff --git a/src/main/java/net/minecraft/src/EntityOtherPlayerMP.java b/src/main/java/net/minecraft/src/EntityOtherPlayerMP.java index bebacf1..4efc6e2 100644 --- a/src/main/java/net/minecraft/src/EntityOtherPlayerMP.java +++ b/src/main/java/net/minecraft/src/EntityOtherPlayerMP.java @@ -16,6 +16,7 @@ public class EntityOtherPlayerMP extends EntityPlayer { skinUrl = (new StringBuilder()).append("http://s3.amazonaws.com/MinecraftSkins/").append(s).append(".png") .toString(); } + skinUrl = "MPSkin" + s; noClip = true; field_22062_y = 0.25F; renderDistanceWeight = 10D; diff --git a/src/main/java/net/minecraft/src/EntityPlayer.java b/src/main/java/net/minecraft/src/EntityPlayer.java index 9814003..1d9044c 100644 --- a/src/main/java/net/minecraft/src/EntityPlayer.java +++ b/src/main/java/net/minecraft/src/EntityPlayer.java @@ -28,6 +28,7 @@ public abstract class EntityPlayer extends EntityLiving { field_9351_C = "humanoid"; field_9353_B = 180F; fireResistance = 20; + skinUrl = "SPSkin"; //texture = "/mob/char.png"; } diff --git a/src/main/java/net/minecraft/src/EntityPlayerSP.java b/src/main/java/net/minecraft/src/EntityPlayerSP.java index 9137a69..c7c44b3 100644 --- a/src/main/java/net/minecraft/src/EntityPlayerSP.java +++ b/src/main/java/net/minecraft/src/EntityPlayerSP.java @@ -18,10 +18,6 @@ public class EntityPlayerSP extends EntityPlayer { field_21902_bL = new MouseFilter(); mc = minecraft; dimension = i; - if (session != null && session.username != null && session.username.length() > 0) { - skinUrl = (new StringBuilder()).append("http://s3.amazonaws.com/MinecraftSkins/").append(session.username) - .append(".png").toString(); - } username = session.username; } diff --git a/src/main/java/net/minecraft/src/EntityRenderer.java b/src/main/java/net/minecraft/src/EntityRenderer.java index d98d40e..a789d98 100644 --- a/src/main/java/net/minecraft/src/EntityRenderer.java +++ b/src/main/java/net/minecraft/src/EntityRenderer.java @@ -349,7 +349,9 @@ public class EntityRenderer { f3 = field_22235_l.func_22386_a(f3, 0.05F * f2); f4 = field_22234_m.func_22386_a(f4, 0.05F * f2); } - mc.thePlayer.func_346_d(f3, f4 * (float) l); + if(mc.thePlayer != null) { + mc.thePlayer.func_346_d(f3, f4 * (float) l); + } } if (mc.field_6307_v) { return; diff --git a/src/main/java/net/minecraft/src/GuiConnecting.java b/src/main/java/net/minecraft/src/GuiConnecting.java index dc41164..13af604 100644 --- a/src/main/java/net/minecraft/src/GuiConnecting.java +++ b/src/main/java/net/minecraft/src/GuiConnecting.java @@ -4,6 +4,7 @@ package net.minecraft.src; import java.io.IOException; import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.EaglerProfile; // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) braces deadcode @@ -61,6 +62,7 @@ public class GuiConnecting extends GuiScreen { this.clientHandler = new NetClientHandler(mc, uri, 0); this.clientHandler.addToSendQueue(new Packet2Handshake(mc.session.username)); + this.clientHandler.addToSendQueue(new Packet69EaglercraftData("EAG|MySkin", EaglerProfile.getSelfSkinPacket())); } catch (IOException e) { try { this.clientHandler.disconnect(); diff --git a/src/main/java/net/minecraft/src/GuiMainMenu.java b/src/main/java/net/minecraft/src/GuiMainMenu.java index 5f4c2f3..e75df31 100644 --- a/src/main/java/net/minecraft/src/GuiMainMenu.java +++ b/src/main/java/net/minecraft/src/GuiMainMenu.java @@ -9,6 +9,7 @@ import net.lax1dude.eaglercraft.ConfigConstants; import net.lax1dude.eaglercraft.EaglerAdapter; import net.lax1dude.eaglercraft.EaglercraftRandom; import net.lax1dude.eaglercraft.GuiMultiplayer; +import net.lax1dude.eaglercraft.GuiScreenEditProfile; import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.adapter.Tessellator; import net.lax1dude.eaglercraft.beta.GuiNoMultiplayer; @@ -72,8 +73,8 @@ public class GuiMainMenu extends GuiScreen { // mc.displayGuiScreen(new GuiTexturePacks(this)); //} if (guibutton.id == 4) { - mc.displayGuiScreen(new GuiNoMultiplayer(this)); - //mc.displayGuiScreen(new GuiMultiplayer(this)); + //mc.displayGuiScreen(new GuiNoMultiplayer(this)); + mc.displayGuiScreen(new GuiScreenEditProfile(this)); } } @@ -98,6 +99,7 @@ public class GuiMainMenu extends GuiScreen { drawString(fontRenderer, s, width - fontRenderer.getStringWidth(s) - 2, height - 10, 0xffffff); drawString(fontRenderer, ConfigConstants.mainMenuString, 2, height - 10, 0xffffff); + /* EaglerAdapter.glPushMatrix(); float ff = 0.75f; EaglerAdapter.glScalef(ff, ff, ff); @@ -107,6 +109,7 @@ public class GuiMainMenu extends GuiScreen { drawString(fontRenderer, str, (int)(((width / ff) - w) / 2), (int)((height / 4 + 102) / ff), 0xffeeee); EaglerAdapter.glPopMatrix(); + */ super.drawScreen(i, j, f); } diff --git a/src/main/java/net/minecraft/src/GuiSelectWorld.java b/src/main/java/net/minecraft/src/GuiSelectWorld.java index b5d19e1..ea4d34c 100644 --- a/src/main/java/net/minecraft/src/GuiSelectWorld.java +++ b/src/main/java/net/minecraft/src/GuiSelectWorld.java @@ -35,7 +35,7 @@ public class GuiSelectWorld extends GuiScreen { private void func_22084_k() { ISaveFormat isaveformat = mc.func_22004_c(); - field_22100_m = isaveformat.getWorldList(); + field_22100_m = isaveformat.getWorldList(mc.loadingScreen); Collections.sort(field_22100_m); field_22101_l = -1; } diff --git a/src/main/java/net/minecraft/src/ISaveFormat.java b/src/main/java/net/minecraft/src/ISaveFormat.java index 324fe93..441f280 100644 --- a/src/main/java/net/minecraft/src/ISaveFormat.java +++ b/src/main/java/net/minecraft/src/ISaveFormat.java @@ -12,7 +12,7 @@ public interface ISaveFormat { public abstract ISaveHandler loadWorldHandler(String s, boolean flag); - public abstract List getWorldList(); + public abstract List getWorldList(IProgressUpdate progress); public abstract void flushCache(); diff --git a/src/main/java/net/minecraft/src/ItemRenderer.java b/src/main/java/net/minecraft/src/ItemRenderer.java index 0b38a55..3b3ebab 100644 --- a/src/main/java/net/minecraft/src/ItemRenderer.java +++ b/src/main/java/net/minecraft/src/ItemRenderer.java @@ -2,6 +2,7 @@ package net.minecraft.src; // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.EaglerProfile; import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.adapter.Tessellator; @@ -185,8 +186,13 @@ public class ItemRenderer { f10 = MathHelper.sin(MathHelper.sqrt_float(f6) * 3.141593F); EaglerAdapter.glRotatef(f10 * 70F, 0.0F, 1.0F, 0.0F); EaglerAdapter.glRotatef(-f8 * 20F, 0.0F, 0.0F, 1.0F); - EaglerAdapter.glBindTexture(3553 /* GL_TEXTURE_2D */, mc.renderEngine - .getTextureForDownloadableImage(mc.thePlayer.skinUrl, mc.thePlayer.getEntityTexture())); +// EaglerAdapter.glBindTexture(3553 /* GL_TEXTURE_2D */, mc.renderEngine +// .getTextureForDownloadableImage(mc.thePlayer.skinUrl, mc.thePlayer.getEntityTexture())); + if(EaglerProfile.presetSkinId < 0) { + mc.renderEngine.bindTexture(EaglerProfile.skins.get(EaglerProfile.customSkinId).glTex); + }else { + EaglerProfile.defaultOptionsTextures[EaglerProfile.presetSkinId].bindTexture(); + } EaglerAdapter.glTranslatef(-1F, 3.6F, 3.5F); EaglerAdapter.glRotatef(120F, 0.0F, 0.0F, 1.0F); EaglerAdapter.glRotatef(200F, 1.0F, 0.0F, 0.0F); diff --git a/src/main/java/net/minecraft/src/ModelBiped.java b/src/main/java/net/minecraft/src/ModelBiped.java index d1d0554..17a3e37 100644 --- a/src/main/java/net/minecraft/src/ModelBiped.java +++ b/src/main/java/net/minecraft/src/ModelBiped.java @@ -1,4 +1,7 @@ package net.minecraft.src; + +import net.lax1dude.eaglercraft.EaglerAdapter; + // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html @@ -50,7 +53,17 @@ public class ModelBiped extends ModelBase { public void render(float f, float f1, float f2, float f3, float f4, float f5) { setRotationAngles(f, f1, f2, f3, f4, f5); bipedHead.render(f5); + + if(blockTransparentSkins) { + EaglerAdapter.glDisable(EaglerAdapter.GL_ALPHA_TEST); + } + bipedBody.render(f5); + + if(blockTransparentSkins) { + EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST); + } + bipedRightArm.render(f5); bipedLeftArm.render(f5); bipedRightLeg.render(f5); @@ -156,4 +169,6 @@ public class ModelBiped extends ModelBase { public boolean field_1279_h; public boolean field_1278_i; public boolean isSneak; + public boolean blockTransparentSkins = false; + } diff --git a/src/main/java/net/minecraft/src/NBTTagCompound.java b/src/main/java/net/minecraft/src/NBTTagCompound.java index 69e4e0a..7421bdf 100644 --- a/src/main/java/net/minecraft/src/NBTTagCompound.java +++ b/src/main/java/net/minecraft/src/NBTTagCompound.java @@ -175,4 +175,12 @@ public class NBTTagCompound extends NBTBase { } private Map tagMap; + + public NBTBase getTag(String s) { + return (NBTBase) tagMap.get(s); + } + + public static Map getTagMap(NBTTagCompound nb) { + return nb.tagMap; + } } diff --git a/src/main/java/net/minecraft/src/NetClientHandler.java b/src/main/java/net/minecraft/src/NetClientHandler.java index 5f00b4a..a6b3fc1 100644 --- a/src/main/java/net/minecraft/src/NetClientHandler.java +++ b/src/main/java/net/minecraft/src/NetClientHandler.java @@ -6,6 +6,7 @@ package net.minecraft.src; import java.io.*; +import net.lax1dude.eaglercraft.EaglerProfile; import net.lax1dude.eaglercraft.EaglercraftRandom; import net.lax1dude.eaglercraft.GuiMultiplayer; import net.lax1dude.eaglercraft.WebsocketNetworkManager; @@ -23,9 +24,14 @@ public class NetClientHandler extends NetHandler { public void processReadPackets() { if (disconnected) { + if(mc.theWorld != null) { + mc.changeWorld1(null); + mc.displayGuiScreen(new GuiConnectFailed("disconnect.disconnected", "disconnect.endOfStream", new Object[0])); + } return; } else { netManager.processReadPackets(); + disconnected = !netManager.isSocketOpen(); return; } } @@ -336,14 +342,19 @@ public class NetClientHandler extends NetHandler { } public void handleHandshake(Packet2Handshake packet2handshake) { - if(packet2handshake.username.length() < 26 || mc.gameSettings.lastPasswordLength <= 0) { + if(packet2handshake.username.length() < 24 || mc.gameSettings.lastPasswordLength <= 0) { addToSendQueue(new Packet1Login(mc.session.username, "NULL", 9)); }else { - String hsh = GuiMultiplayer.makeLoginHash(mc.gameSettings.lastPasswordHash, packet2handshake.username); + String hsh = (mc.gameSettings.lastPasswordHash == null || mc.gameSettings.lastPasswordHash.length() == 0 || mc.gameSettings.lastPasswordHash.equalsIgnoreCase("null")) ? + null : GuiMultiplayer.makeLoginHash(mc.gameSettings.lastPasswordHash, packet2handshake.username); if(hsh != null) { addToSendQueue(new Packet1Login(mc.session.username, hsh, 9)); }else { - addToSendQueue(new Packet1Login(mc.session.username, "NULL", 9)); + disconnected = true; + netManager.networkShutdown("disconnect.closed", new Object[0]); + mc.changeWorld1(null); + mc.displayGuiScreen(new GuiConnectFailed("disconnect.disconnected", "disconnect.genericReason", + new Object[] { "A password is required to join this server!" })); } } } @@ -522,6 +533,12 @@ public class NetClientHandler extends NetHandler { packet54.pitch); } + public void handleEaglercraftData(Packet69EaglercraftData packet) { + if(packet.type.equals("EAG|PlayerSkin")) { + EaglerProfile.processSkinResponse(packet.data); + } + } + private boolean disconnected; private WebsocketNetworkManager netManager; public String field_1209_a; diff --git a/src/main/java/net/minecraft/src/NetHandler.java b/src/main/java/net/minecraft/src/NetHandler.java index b8d43f4..a2df1e7 100644 --- a/src/main/java/net/minecraft/src/NetHandler.java +++ b/src/main/java/net/minecraft/src/NetHandler.java @@ -191,4 +191,8 @@ public class NetHandler { public void func_22185_a(Packet27 packet27) { } + + public void handleEaglercraftData(Packet69EaglercraftData packet) { + registerPacket(packet); + } } diff --git a/src/main/java/net/minecraft/src/Packet.java b/src/main/java/net/minecraft/src/Packet.java index b96ebd2..ad794b1 100644 --- a/src/main/java/net/minecraft/src/Packet.java +++ b/src/main/java/net/minecraft/src/Packet.java @@ -151,6 +151,7 @@ public abstract class Packet { addIdClassMapping(53, Packet53BlockChange.class); addIdClassMapping(54, Packet54.class); addIdClassMapping(60, Packet60.class); + addIdClassMapping(69, Packet69EaglercraftData.class); addIdClassMapping(100, Packet100.class); addIdClassMapping(101, Packet101.class); addIdClassMapping(102, Packet102.class); diff --git a/src/main/java/net/minecraft/src/Packet69EaglercraftData.java b/src/main/java/net/minecraft/src/Packet69EaglercraftData.java new file mode 100644 index 0000000..2004f90 --- /dev/null +++ b/src/main/java/net/minecraft/src/Packet69EaglercraftData.java @@ -0,0 +1,47 @@ +package net.minecraft.src; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Packet69EaglercraftData extends Packet { + + public String type; + public byte[] data; + + public Packet69EaglercraftData() { + } + + public Packet69EaglercraftData(String type, byte[] data) { + if(data.length > 65535) { + throw new IllegalArgumentException("Packet69EaglercraftData may at most carry a 65535 byte payload"); + } + this.type = type; + this.data = data; + } + + @Override + public void readPacketData(DataInputStream datainputstream) throws IOException { + type = datainputstream.readUTF(); + data = new byte[datainputstream.readUnsignedShort()]; + datainputstream.read(data); + } + + @Override + public void writePacketData(DataOutputStream dataoutputstream) throws IOException { + dataoutputstream.writeUTF(type); + dataoutputstream.writeShort(data.length); + dataoutputstream.write(data); + } + + @Override + public void processPacket(NetHandler nethandler) { + nethandler.handleEaglercraftData(this); + } + + @Override + public int getPacketSize() { + return 2 + type.length() + 2 + data.length; + } + +} diff --git a/src/main/java/net/minecraft/src/RenderEngine.java b/src/main/java/net/minecraft/src/RenderEngine.java index 9f8399d..6bef9f0 100644 --- a/src/main/java/net/minecraft/src/RenderEngine.java +++ b/src/main/java/net/minecraft/src/RenderEngine.java @@ -78,9 +78,24 @@ public class RenderEngine { textureNameToImageMap.put(Integer.valueOf(i), bufferedimage); return i; } + + public int allocateAndSetupTexture(byte[] data, int w, int h) { + int i = EaglerAdapter.glGenTextures(); + bindTexture(i); + EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10241 /* GL_TEXTURE_MIN_FILTER */, 9729 /* GL_LINEAR */); + EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10240 /* GL_TEXTURE_MAG_FILTER */, 9728 /* GL_NEAREST */); + EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10242 /* GL_TEXTURE_WRAP_S */, 10497 /* GL_REPEAT */); + EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10243 /* GL_TEXTURE_WRAP_T */, 10497 /* GL_REPEAT */); + imageDataB1.clear(); + imageDataB1.put(data); + imageDataB1.position(0).limit(data.length); + EaglerAdapter.glTexImage2D(3553 /* GL_TEXTURE_2D */, 0, 6408 /* GL_RGBA */, w, h, 0, 6408 /* GL_RGBA */, + 5121 /* GL_UNSIGNED_BYTE */, imageDataB1); + return i; + } public void setupTexture(EaglerImage bufferedimage, int i) { - EaglerAdapter.glBindTexture(3553 /* GL_TEXTURE_2D */, i); + bindTexture(i); if (useMipmaps) { EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10241 /* GL_TEXTURE_MIN_FILTER */, EaglerAdapter.GL_NEAREST_MIPMAP_LINEAR); EaglerAdapter.glTexParameteri(3553 /* GL_TEXTURE_2D */, 10240 /* GL_TEXTURE_MAG_FILTER */, EaglerAdapter.GL_NEAREST /* GL_LINEAR */); @@ -343,11 +358,11 @@ public class RenderEngine { TextureFX texturefx = (TextureFX) textureList.get(i); texturefx.anaglyphEnabled = options.anaglyph; texturefx.onTick(); + texturefx.bindImage(this); int tileSize = 16 * 16 * 4; imageDataB1.clear(); imageDataB1.put(texturefx.imageData); imageDataB1.position(0).limit(tileSize); - texturefx.bindImage(this); EaglerAdapter.glTexSubImage2D(3553 /* GL_TEXTURE_2D */, 0, (texturefx.iconIndex % 16) * 16, (texturefx.iconIndex / 16) * 16, 16, 16, 6408 /* GL_RGBA */, 5121 /* GL_UNSIGNED_BYTE */, imageDataB1); } diff --git a/src/main/java/net/minecraft/src/RenderFallingSand.java b/src/main/java/net/minecraft/src/RenderFallingSand.java index 862a18e..1cea601 100644 --- a/src/main/java/net/minecraft/src/RenderFallingSand.java +++ b/src/main/java/net/minecraft/src/RenderFallingSand.java @@ -25,6 +25,7 @@ public class RenderFallingSand extends Render { Block block = Block.blocksList[entityfallingsand.blockID]; World world = entityfallingsand.func_465_i(); EaglerAdapter.glDisable(2896 /* GL_LIGHTING */); + EaglerAdapter.glColor4f(1f, 1f, 1f, 1f); field_197_d.renderBlockFallingSand(block, world, MathHelper.floor_double(entityfallingsand.posX), MathHelper.floor_double(entityfallingsand.posY), MathHelper.floor_double(entityfallingsand.posZ)); EaglerAdapter.glEnable(2896 /* GL_LIGHTING */); diff --git a/src/main/java/net/minecraft/src/RenderGlobal.java b/src/main/java/net/minecraft/src/RenderGlobal.java index acabc86..0e2fd2d 100644 --- a/src/main/java/net/minecraft/src/RenderGlobal.java +++ b/src/main/java/net/minecraft/src/RenderGlobal.java @@ -835,33 +835,28 @@ public class RenderGlobal implements IWorldAccess { } public boolean updateRenderers(EntityLiving entityliving, boolean flag) { - boolean flag1 = false; - if (flag1) { - Collections.sort(worldRenderersToUpdate, new RenderSorter(entityliving)); - int i = worldRenderersToUpdate.size() - 1; - int j = worldRenderersToUpdate.size(); - for (int k = 0; k < j; k++) { - WorldRenderer worldrenderer = (WorldRenderer) worldRenderersToUpdate.get(i - k); - if (!flag) { - if (worldrenderer.distanceToEntity(entityliving) > 1024F) { - if (worldrenderer.isInFrustum) { - if (k >= 3) { - return false; - } - } else if (k >= 1) { - return false; - } + //boolean flag1 = false; + //if (flag1) { + int t = worldRenderersToUpdate.size(); + if(t > 0) { + Collections.sort(worldRenderersToUpdate, new RenderSorter(entityliving)); + boolean b = false; + for(int i = t - 1; i >= 0; --i) { + WorldRenderer worldrenderer = (WorldRenderer) worldRenderersToUpdate.get(i); + if(worldrenderer.isInFrustum || worldrenderer.distanceToEntity(entityliving) < 1024F) { + b = true; + worldrenderer.updateRenderer(); + worldRenderersToUpdate.remove(i); + break; } - } else if (!worldrenderer.isInFrustum) { - continue; } - worldrenderer.updateRenderer(); - worldRenderersToUpdate.remove(worldrenderer); - worldrenderer.needsUpdate = false; + if(!b) { + ((WorldRenderer)worldRenderersToUpdate.remove(t - 1)).updateRenderer(); + } } - return worldRenderersToUpdate.size() == 0; - } + //} + /* RenderSorter rendersorter = new RenderSorter(entityliving); WorldRenderer aworldrenderer[] = new WorldRenderer[3]; ArrayList arraylist = null; @@ -941,6 +936,7 @@ public class RenderGlobal implements IWorldAccess { worldRenderersToUpdate.remove(j2); } return l == i1 + l1; + */ } private static final TextureLocation terrainTexture = new TextureLocation("/terrain.png"); diff --git a/src/main/java/net/minecraft/src/RenderPlayer.java b/src/main/java/net/minecraft/src/RenderPlayer.java index 67b71e9..d3c5dad 100644 --- a/src/main/java/net/minecraft/src/RenderPlayer.java +++ b/src/main/java/net/minecraft/src/RenderPlayer.java @@ -1,7 +1,14 @@ package net.minecraft.src; // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + import net.lax1dude.eaglercraft.EaglerAdapter; +import net.lax1dude.eaglercraft.EaglerProfile; +import net.lax1dude.eaglercraft.EaglerProfile.EnumSkinType; +import net.lax1dude.eaglercraft.EaglerProfile.UserSkin; import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.adapter.Tessellator; @@ -25,6 +32,7 @@ public class RenderPlayer extends RenderLiving { public RenderPlayer() { super(new ModelBiped(0.0F), 0.5F); modelBipedMain = (ModelBiped) mainModel; + modelBipedMain.blockTransparentSkins = true; modelArmorChestplate = new ModelBiped(1.0F); modelArmor = new ModelBiped(0.5F); } @@ -298,7 +306,47 @@ public class RenderPlayer extends RenderLiving { @Override protected boolean loadDownloadableImageTexture(String s, String s1) { - defaultPlayerSkin.bindTexture(); + RenderEngine re = Minecraft.getMinecraft().renderEngine; + if(s == null) { + defaultPlayerSkin.bindTexture(); + }else if(s.equals("SPSkin")) { + if(EaglerProfile.presetSkinId < 0) { + re.bindTexture(EaglerProfile.skins.get(EaglerProfile.customSkinId).glTex); + }else { + EaglerProfile.defaultOptionsTextures[EaglerProfile.presetSkinId].bindTexture(); + } + }else if(s.startsWith("MPSkin")) { + String un = s.substring(6); + UserSkin us = EaglerProfile.getUserSkin(un); + if(us == null) { + if(!EaglerProfile.skinRequestPending(un)) { + World w = Minecraft.getMinecraft().theWorld; + if(w != null && (w instanceof WorldClient)) { + try { + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + DataOutputStream dao = new DataOutputStream(bao); + dao.writeShort(EaglerProfile.beginSkinRequest(un)); + dao.writeUTF(un); + ((WorldClient)w).sendPacket(new Packet69EaglercraftData("EAG|RequestPlayerSkin", bao.toByteArray())); + }catch(IOException exx) { + // ? + } + } + } + defaultPlayerSkin.bindTexture(); + }else { + EnumSkinType st = us.getSkinType(); + if(st == EnumSkinType.PRESET) { + EaglerProfile.defaultOptionsTextures[us.getSkin()].bindTexture(); + }else if(st == EnumSkinType.CUSTOM_LEGACY){ + re.bindTexture(us.getTexture()); + }else { + defaultPlayerSkin.bindTexture(); + } + } + }else { + defaultPlayerSkin.bindTexture(); + } return true; } diff --git a/src/main/java/net/minecraft/src/WorldClient.java b/src/main/java/net/minecraft/src/WorldClient.java index b15399e..246e643 100644 --- a/src/main/java/net/minecraft/src/WorldClient.java +++ b/src/main/java/net/minecraft/src/WorldClient.java @@ -6,6 +6,8 @@ package net.minecraft.src; import java.util.*; +import net.lax1dude.eaglercraft.EaglerProfile; + public class WorldClient extends World { public WorldClient(NetClientHandler netclienthandler, long l, int i) { @@ -102,6 +104,9 @@ public class WorldClient extends World { } public void setEntityDead(Entity entity) { + if(entity instanceof EntityOtherPlayerMP) { + EaglerProfile.freeUserSkin(((EntityOtherPlayerMP)entity).username); + } super.setEntityDead(entity); field_20914_E.remove(entity); } @@ -192,6 +197,10 @@ public class WorldClient extends World { public void sendQuittingDisconnectingPacket() { sendQueue.addToSendQueue(new Packet255KickDisconnect("Quitting")); } + + public void sendPacket(Packet p) { + sendQueue.addToSendQueue(p); + } private LinkedList field_1057_z; private NetClientHandler sendQueue; diff --git a/src/teavm/java/net/lax1dude/eaglercraft/Client.java b/src/teavm/java/net/lax1dude/eaglercraft/Client.java index 1d70325..f62cf90 100644 --- a/src/teavm/java/net/lax1dude/eaglercraft/Client.java +++ b/src/teavm/java/net/lax1dude/eaglercraft/Client.java @@ -36,13 +36,20 @@ public class Client { registerErrorHandler(); String[] e = getOpts(); try { - EaglerAdapterImpl2.initializeContext(rootElement = Window.current().getDocument().getElementById(e[0]), e[1]); - }catch(AbortedLaunchException ex) { + try { + EaglerAdapterImpl2.initializeContext(rootElement = Window.current().getDocument().getElementById(e[0]), e[1]); + }catch(AbortedLaunchException ex) { + return; + } + }catch(Throwable ex2) { + StringWriter s = new StringWriter(); + ex2.printStackTrace(new PrintWriter(s)); + showCrashScreen(s.toString()); return; } LocalStorageManager.loadStorage(); if(e.length > 2) { - EaglerAdapterImpl2.setServerToJoinOnLaunch(e[3]); + EaglerAdapterImpl2.setServerToJoinOnLaunch(e[2]); } run0(); }