From 1d3013838665a9f8de3b5f86e1936a2170e9888e Mon Sep 17 00:00:00 2001 From: Christopher Johns Date: Fri, 8 Jun 2018 22:01:54 -0700 Subject: [PATCH] finished fixing beds --- src/minicraft/core/Renderer.java | 11 +++++--- src/minicraft/entity/furniture/Bed.java | 24 ++++++++++++++++++ src/minicraft/entity/mob/Mob.java | 4 +-- src/minicraft/entity/mob/Player.java | 2 +- src/minicraft/entity/mob/RemotePlayer.java | 11 +++++++- src/minicraft/gfx/FontStyle.java | 22 ++++++++++------ src/minicraft/network/MinicraftClient.java | 8 +++--- src/minicraft/network/MinicraftServer.java | 25 +++++++++++++------ .../network/MinicraftServerThread.java | 4 +-- src/minicraft/saveload/Load.java | 4 +-- 10 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/minicraft/core/Renderer.java b/src/minicraft/core/Renderer.java index bb1248ddf..2332f65c8 100644 --- a/src/minicraft/core/Renderer.java +++ b/src/minicraft/core/Renderer.java @@ -170,13 +170,16 @@ private static void renderGui() { if (Updater.saving) permStatus.add("Saving... " + Math.round(LoadingDisplay.getPercentage()) + "%"); if (Bed.sleeping()) permStatus.add("Sleeping..."); else if (!Game.isValidServer() && Bed.inBed(Game.player)) { - permStatus.add(Bed.getPlayersAwake() + " players still awake"); - permStatus.add(""); - permStatus.add("Press "+input.getMapping("exit")+" to stop trying to sleep"); + int numAwake = Bed.getPlayersAwake(); + permStatus.add(numAwake + " player"+(numAwake==1?"":"s")+" still awake"); + permStatus.add(" "); + permStatus.add("Press "+input.getMapping("exit")+" to cancel"); } if(permStatus.size() > 0) { - FontStyle style = new FontStyle(Color.WHITE).setYPos(Screen.h / 2 - 20, false).setRelTextPos(RelPos.TOP).setShadowType(Color.DARK_GRAY, false); + // FIXME this is left-aligned for some reason, when it should be center-aligned. + FontStyle style = new FontStyle(Color.WHITE).setYPos(Screen.h / 2 - 20, false).setRelTextPos(RelPos.TOP, false).setShadowType(Color.DARK_GRAY, false); + Font.drawParagraph(permStatus.toArray(new String[permStatus.size()]), screen, style, 1); } diff --git a/src/minicraft/entity/furniture/Bed.java b/src/minicraft/entity/furniture/Bed.java index ea7003c75..9bf5dbbac 100644 --- a/src/minicraft/entity/furniture/Bed.java +++ b/src/minicraft/entity/furniture/Bed.java @@ -87,6 +87,12 @@ else if(player instanceof RemotePlayer) public static boolean sleeping() { return playersAwake == 0; } public static boolean inBed(Player player) { return sleepingPlayers.containsKey(player); } + public static Level getBedLevel(Player player) { + Bed bed = sleepingPlayers.get(player); + if(bed == null) + return null; + return bed.getLevel(); + } // get the player "out of bed"; used on the client only. public static void removePlayer(Player player) { @@ -95,6 +101,24 @@ public static void removePlayer(Player player) { public static void removePlayers() { sleepingPlayers.clear(); } + // client should not call this. + public static void restorePlayer(Player player) { + Bed bed = sleepingPlayers.remove(player); + if(bed != null) { + if(bed.getLevel() == null) + Game.levels[Game.currentLevel].add(player); + else + bed.getLevel().add(player); + + if(!Game.ISONLINE) + playersAwake = 1; + else if(Game.isValidServer()) { + int total = Game.server.getNumPlayers(); + playersAwake = total - sleepingPlayers.size(); + Game.server.updateGameVars(); + } + } + } // client should not call this. public static void restorePlayers() { for(Player p: sleepingPlayers.keySet()) { diff --git a/src/minicraft/entity/mob/Mob.java b/src/minicraft/entity/mob/Mob.java index 820a739ec..ce02aaa95 100644 --- a/src/minicraft/entity/mob/Mob.java +++ b/src/minicraft/entity/mob/Mob.java @@ -75,7 +75,7 @@ public boolean move(int xa, int ya) { // Move the mob, overrides from Entity boolean checkPlayers = Game.isValidServer() && (xa != 0 || ya != 0); List prevPlayers = null; - if(checkPlayers) prevPlayers = MinicraftServer.getPlayersInRange(this, true); + if(checkPlayers) prevPlayers = Game.server.getPlayersInRange(this, true); if(!(Game.isValidServer() && this instanceof RemotePlayer)) { // this will be the case when the client has sent a move packet to the server. In this case, we DO want to always move. // these should return true b/c the mob is still technically moving; these are just to make it move *slower*. @@ -103,7 +103,7 @@ public boolean move(int xa, int ya) { // Move the mob, overrides from Entity } if(checkPlayers) { - List activePlayers = MinicraftServer.getPlayersInRange(this, true); + List activePlayers = Game.server.getPlayersInRange(this, true); for(int i = 0; i < prevPlayers.size(); i++) { if(activePlayers.contains(prevPlayers.get(i))) { activePlayers.remove(prevPlayers.remove(i)); diff --git a/src/minicraft/entity/mob/Player.java b/src/minicraft/entity/mob/Player.java index 4fda7cae8..effca51b1 100644 --- a/src/minicraft/entity/mob/Player.java +++ b/src/minicraft/entity/mob/Player.java @@ -923,7 +923,7 @@ protected boolean updateField(String field, String val) { return false; } - public String getPlayerData() { + public final String getPlayerData() { List datalist = new ArrayList<>(); StringBuilder playerdata = new StringBuilder(); playerdata.append(Game.VERSION).append("\n"); diff --git a/src/minicraft/entity/mob/RemotePlayer.java b/src/minicraft/entity/mob/RemotePlayer.java index cf438a9ed..f35814cc6 100644 --- a/src/minicraft/entity/mob/RemotePlayer.java +++ b/src/minicraft/entity/mob/RemotePlayer.java @@ -7,6 +7,7 @@ import minicraft.core.io.InputHandler; import minicraft.entity.Direction; import minicraft.entity.Entity; +import minicraft.entity.furniture.Bed; import minicraft.gfx.Color; import minicraft.gfx.Font; import minicraft.gfx.FontStyle; @@ -100,7 +101,15 @@ public boolean shouldTrack(int xt, int yt, Level level) { return shouldSync(level, xt, yt, entityTrackingBuffer); /// this means that there is one tile past the syncRadii in all directions, which marks the distance at which entities are added or removed. } private boolean shouldSync(Level level, int xt, int yt, int offset) { // IDEA make this isWithin(). Decided not to b/c different x and y radii. - if(level == null || level != getLevel()) + if(level == null) + return false; + if(getLevel() == null) { + if(!Bed.inBed(this)) + return false; // no excuse + if(level != Bed.getBedLevel(this)) + return false; + } + else if(level != getLevel()) return false; int px = x >> 4, py = y >> 4; diff --git a/src/minicraft/gfx/FontStyle.java b/src/minicraft/gfx/FontStyle.java index 02a625947..8baf3a4e1 100644 --- a/src/minicraft/gfx/FontStyle.java +++ b/src/minicraft/gfx/FontStyle.java @@ -2,6 +2,8 @@ import java.util.Arrays; +import minicraft.core.Game; +import minicraft.core.Network; import minicraft.screen.RelPos; public class FontStyle { @@ -60,7 +62,7 @@ shadow false (norm shadow) private int shadowColor; private String shadowType; //private int anchorMinX, anchorMaxX, anchorMinY, anchorMaxY; // specifies the anchor pos as the center of the two bounds, while also specifying paragraph dimensions. - private Point anchor; + private Point anchor, lineAnchor; //private int xPosition = -1, yPosition = -1; private RelPos relTextPos = RelPos.CENTER; // aligns the complete block of text with the anchor. private RelPos relLinePos = RelPos.CENTER; // when setup for a paragraph with multiple lines, this determines the alignment of each line within the bounds of the paragraph. @@ -105,14 +107,14 @@ public void draw(String msg, Screen screen) { Dimension size = new Dimension(Font.textWidth(msg), Font.textHeight()); - Rectangle textBounds = relTextPos.positionRect(size, anchor, new Rectangle()); + Rectangle textBounds = relTextPos.positionRect(size, lineAnchor, new Rectangle()); if(padX != 0 || padY != 0) { size.width += padX; size.height += padY; - Rectangle textBox = relTextPos.positionRect(size, anchor, new Rectangle()); + Rectangle textBox = relTextPos.positionRect(size, lineAnchor, new Rectangle()); - relLinePos.positionRect(size, textBox, textBounds); + relLinePos.positionRect(textBounds.getSize(), textBox, textBounds); } // account for anchor @@ -151,7 +153,8 @@ public void configureForParagraph(String[] para, int spacing) { // either way, the draw method needs to use a different position. Dimension size = new Dimension(Font.textWidth(para), para.length*(Font.textHeight()+spacing)); - paraBounds = relLinePos.positionRect(size, anchor, new Rectangle()); + paraBounds = relTextPos.positionRect(size, anchor, new Rectangle()); + /* if(yPosition == -1) { // yPosition is auto-centered int centerYDouble = anchorMinY + anchorMaxY; @@ -174,9 +177,12 @@ public void setupParagraphLine(String[] para, int line, int spacing) { configureForParagraph(para, spacing); //setYPos(paraMinY + line*Font.textHeight() + line*spacing); - Rectangle textArea = new Rectangle(paraBounds.getLeft(), paraBounds.getTop() + line*(Font.textHeight()+spacing), paraBounds.getWidth(), Font.textHeight()+spacing, Rectangle.CORNER_DIMS); + Rectangle textArea = new Rectangle(paraBounds); + textArea.setSize(textArea.getWidth(), Font.textHeight()+spacing, RelPos.TOP_LEFT); + textArea.translate(0, line*textArea.getHeight()); + //Rectangle textArea = new Rectangle(paraBounds.getLeft(), paraBounds.getTop() + line*(Font.textHeight()+spacing), paraBounds.getWidth(), Font.textHeight()+spacing, Rectangle.CORNER_DIMS); - anchor = textArea.getPosition(relTextPos); + lineAnchor = textArea.getPosition(relTextPos); padX = paraBounds.getWidth() - Font.textWidth(para[line]); padY = spacing; @@ -201,6 +207,7 @@ public FontStyle setColor(int col) { public FontStyle setXPos(int pos) { return setXPos(pos, true); } public FontStyle setXPos(int pos, boolean resetAlignment) { anchor.x = pos; + lineAnchor = new Point(anchor); if(resetAlignment) { relTextPos = RelPos.getPos(RelPos.RIGHT.xIndex, relTextPos.yIndex); relLinePos = RelPos.getPos(RelPos.LEFT.xIndex, relLinePos.yIndex); @@ -211,6 +218,7 @@ public FontStyle setXPos(int pos, boolean resetAlignment) { public FontStyle setYPos(int pos) { return setYPos(pos, true); } public FontStyle setYPos(int pos, boolean resetAlignment) { anchor.y = pos; + lineAnchor = new Point(anchor); if(resetAlignment) { relTextPos = RelPos.getPos(relTextPos.xIndex, RelPos.BOTTOM.yIndex); // relLinePos = RelPos.getPos(relLinePos.xIndex, RelPos.BOTTOM.yIndex); diff --git a/src/minicraft/network/MinicraftClient.java b/src/minicraft/network/MinicraftClient.java index 929e086e1..8c3b54773 100644 --- a/src/minicraft/network/MinicraftClient.java +++ b/src/minicraft/network/MinicraftClient.java @@ -164,7 +164,7 @@ private void login(String username) { //return null; } - private static String getPlayerData(Player player) { + /*static String getPlayerData(Player player) { StringBuilder playerdata = new StringBuilder(); List sdata = new ArrayList<>(); Save.writePlayer(player, sdata); @@ -178,7 +178,7 @@ private static String getPlayerData(Player player) { playerdata.append(String.join(",", sdata.toArray(new String[0]))); return playerdata.toString(); - } + }*/ /** This method is responsible for parsing all data received by the socket. */ public boolean parsePacket(InputType inType, String alldata) { @@ -424,7 +424,7 @@ else if(!((RemotePlayer)Game.player).shouldTrack(entity.x >> 4, entity.y >> 4, e if (Game.debug) System.out.println("CLIENT: received save request"); // send back the player data. if (Game.debug) System.out.println("CLIENT: sending save data"); - sendData(InputType.SAVE, getPlayerData(Game.player)); + sendData(InputType.SAVE, Game.player.getPlayerData()); return true; case NOTIFY: @@ -598,7 +598,7 @@ public boolean checkConnection() { public void endConnection() { if(isConnected() && curState == State.PLAY) - sendData(InputType.SAVE, getPlayerData(Game.player)); // try to make sure that the player's info is saved before they leave. + sendData(InputType.SAVE, Game.player.getPlayerData()); // try to make sure that the player's info is saved before they leave. pingTimeout.stop(); diff --git a/src/minicraft/network/MinicraftServer.java b/src/minicraft/network/MinicraftServer.java index 1c74351d2..bedc27def 100644 --- a/src/minicraft/network/MinicraftServer.java +++ b/src/minicraft/network/MinicraftServer.java @@ -142,19 +142,20 @@ public String[] getClientInfo() { return playerStrings.toArray(new String[0]); } - public static List getPlayersInRange(Entity e, boolean useTrackRange) { + public List getPlayersInRange(Entity e, boolean useTrackRange) { if(e == null || e.getLevel() == null) return new ArrayList<>(); int xt = e.x >> 4, yt = e.y >> 4; return getPlayersInRange(e.getLevel(), xt, yt, useTrackRange); // NOTE if "e" is a RemotePlayer, the list returned *will* contain "e". } - public static List getPlayersInRange(Level level, int xt, int yt, boolean useTrackRange) { + public List getPlayersInRange(Level level, int xt, int yt, boolean useTrackRange) { List players = new ArrayList<>(); //if(e == null || e.getLevel() == null) return players; /// screen is 18 tiles hori, 14 tiles vert. So, rect is 20x16 tiles. //List entities = level.getEntitiesInTiles(xt - RemotePlayer.xSyncRadius, yt - RemotePlayer.ySyncRadius, xt + RemotePlayer.xSyncRadius, yt + RemotePlayer.ySyncRadius); - for(Entity e: level.getEntitiesOfClass(RemotePlayer.class)) { - if(e.isRemoved()) continue; - RemotePlayer rp = (RemotePlayer)e; + for(MinicraftServerThread thread: getThreads()) { + RemotePlayer rp = thread.getClient(); + //if(p.isRemoved()) continue; + //RemotePlayer rp = (RemotePlayer)e; if(useTrackRange && rp.shouldTrack(xt, yt, level) || !useTrackRange && rp.shouldSync(xt, yt, level)) players.add(rp); } @@ -280,8 +281,13 @@ public void broadcastEntityAddition(Entity e, boolean addSelf) { List players = getPlayersInRange(e, true); if(!addSelf) players.remove(getIfPlayer(e)); // if "e" is a player, this removes it from the list. - for(MinicraftServerThread thread: getAssociatedThreads(players)) + int cnt = 0; + if(Game.debug && e instanceof Player) System.out.println("SERVER: broadcasting player addition of "+e); + for(MinicraftServerThread thread: getAssociatedThreads(players)) { thread.sendEntityAddition(e); + cnt++; + } + if(Game.debug && e instanceof Player) System.out.println("SERVER: broadcasted player addition of "+e+" to "+cnt+" clients"); } //public void sendEntityAddition(Entity e, RemotePlayer sender) { sendEntityAddition(e, sender, false); } @@ -459,7 +465,7 @@ boolean parsePacket(MinicraftServerThread serverThread, InputType inType, String if(Game.player != null) { // save the player, and then remove it. It is leftover from when this was a single player world. - playerdata = Game.VERSION+"\n"+Game.player.getPlayerData(); + playerdata = Game.player.getPlayerData(); //if (Game.debug) System.out.println("SERVER: setting main player as remote from login."); Game.player.remove(); // all the important data has been saved. Game.player = null; @@ -493,6 +499,8 @@ boolean parsePacket(MinicraftServerThread serverThread, InputType inType, String clientPlayer.findStartPos(World.levels[World.lvlIdx(0)]); // find a new start pos // this is a new player. playerdata = clientPlayer.getPlayerData(); + // save the new player once, immediately. + serverThread.writeClientSave(playerdata); } serverThread.sendData(InputType.PLAYER, playerdata); @@ -775,7 +783,8 @@ boolean parsePacket(MinicraftServerThread serverThread, InputType inType, String } else { if(Bed.sleeping()) return false; // can't quit once everyone is in bed - + // else, get the player out of bed + Bed.restorePlayer(clientPlayer); } // if(Bed.inBed(clientPlayer) || !Bed.checkCanSleep(clientPlayer)) // return false; diff --git a/src/minicraft/network/MinicraftServerThread.java b/src/minicraft/network/MinicraftServerThread.java index 99ceaf4d3..ccc286ee5 100644 --- a/src/minicraft/network/MinicraftServerThread.java +++ b/src/minicraft/network/MinicraftServerThread.java @@ -170,7 +170,7 @@ public void sendEntityUpdate(Entity e, String updateString) { } public void sendEntityAddition(Entity e) { - if(Game.debug && e instanceof Player) System.out.println(""); + if(Game.debug && e instanceof Player) System.out.println("SERVER: sending addition of player "+e+" to client through "+this); if(Game.debug && e.eid == client.eid) System.out.println("SERVER: sending addition of player to itself"); String edata = Save.writeEntity(e, false); if(edata.length() == 0) @@ -288,7 +288,7 @@ protected void writeClientSave(String playerdata) { filename = "RemotePlayer"+numFiles+Save.extension; } - String filedata = String.join("\n", client.getUsername(), Game.VERSION, playerdata); + String filedata = String.join("\n", client.getUsername(), playerdata); String filepath = serverInstance.getWorldPath()+"/"+filename; try { diff --git a/src/minicraft/saveload/Load.java b/src/minicraft/saveload/Load.java index 05df24430..cc6e189fd 100644 --- a/src/minicraft/saveload/Load.java +++ b/src/minicraft/saveload/Load.java @@ -367,7 +367,7 @@ public void loadPlayer(Player player, List origData) { Game.currentLevel = Integer.parseInt(data.remove(0)); Level level = World.levels[Game.currentLevel]; if(!player.isRemoved()) player.remove(); // removes the user player from the level, in case they would be added twice. - if(level != null) + if(level != null && !(Game.isValidServer() && player == Game.player)) level.add(player); else if(Game.debug) System.out.println(Network.onlinePrefix()+"game level to add player " + player + " to is null."); //Tile spawnTile = level.getTile(player.spawnx >> 4, player.spawny >> 4); @@ -534,7 +534,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL if(Game.isValidClient()) { if(eid == Game.player.eid) - return Game.player; + return Game.player; // don't reload the main player via an entity addition, though do add it to the level (will be done elsewhere) if(Game.player instanceof RemotePlayer && !((RemotePlayer)Game.player).shouldTrack(x >> 4, y >> 4, World.levels[entityLevel]) ) {