/* * IDK Game Server by Steve Winfield * https://github.com/WinfieldSteve */ package org.stevewinfield.suja.idk.game.rooms; import org.apache.log4j.Logger; import org.magicwerk.brownies.collections.GapList; import org.stevewinfield.suja.idk.Bootloader; import org.stevewinfield.suja.idk.IDK; import org.stevewinfield.suja.idk.communication.MessageWriter; import org.stevewinfield.suja.idk.communication.QueuedMessageWriter; import org.stevewinfield.suja.idk.communication.global.writers.GenericErrorWriter; import org.stevewinfield.suja.idk.communication.room.writers.*; import org.stevewinfield.suja.idk.communication.trading.writers.TradeAbortedWriter; import org.stevewinfield.suja.idk.game.bots.BotInstance; import org.stevewinfield.suja.idk.game.bots.BotKeywordReaction; import org.stevewinfield.suja.idk.game.furnitures.FurnitureInteractor; import org.stevewinfield.suja.idk.game.furnitures.FurnitureType; import org.stevewinfield.suja.idk.game.messenger.MessengerBuddy; import org.stevewinfield.suja.idk.game.miscellaneous.ChatMessage; import org.stevewinfield.suja.idk.game.miscellaneous.ChatType; import org.stevewinfield.suja.idk.game.navigator.NavigatorList; import org.stevewinfield.suja.idk.game.rooms.coordination.*; import org.stevewinfield.suja.idk.game.rooms.tasks.RoomTask; import org.stevewinfield.suja.idk.game.rooms.wired.WiredHandler; import org.stevewinfield.suja.idk.game.rooms.wired.WiredManager; import org.stevewinfield.suja.idk.game.trading.Trade; import org.stevewinfield.suja.idk.game.trading.TradeManager; import org.stevewinfield.suja.idk.network.sessions.Session; import org.stevewinfield.suja.idk.threadpools.WorkerTasks; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; public class RoomInstance { private static final Logger logger = Logger.getLogger(RoomInstance.class); public RoomInformation getInformation() { return information; } public GapList<Integer> getVotes() { return votes; } public RoomItem getMoodlight() { return moodLight; } public RoomTask getRoomTask() { return roomTask; } public ConcurrentHashMap<Integer, RoomPlayer> getRoomPlayers() { return roomPlayers; } public ConcurrentHashMap<Integer, RoomItem> getRoomItems() { return roomItems; } public GapList<Integer> getRights() { return rights; } public Gamemap getGamemap() { return gameMap; } public WiredHandler getWiredHandler() { return wiredHandler; } public TradeManager getTradeManager() { return tradeManager; } public boolean guestStickysAreAllowed() { return guestStickysAllowed; } public RoomInstance() { this.information = new RoomInformation(); this.votes = new GapList<>(); this.roomTask = new RoomTask(this); this.roomPlayers = new ConcurrentHashMap<>(); this.roomItems = new ConcurrentHashMap<>(); this.topRoomItems = new ConcurrentHashMap<>(); this.rights = new GapList<>(); this.itemsToRemove = new GapList<>(); this.itemsToAdd = new GapList<>(); this.itemsToUpdate = new GapList<>(); this.tradeManager = new TradeManager(); this.wiredHandler = new WiredHandler(this); this.topRoomPlayers = new ConcurrentHashMap<>(); /** * Add room task to Thread Pool **/ this.roomTask.setScheduledFuture(WorkerTasks.addTask(this.roomTask, 0, 500, WorkerTasks.getRoomExecutor())); } public boolean hasRights(final Session session, final boolean ownerRights) { final boolean isOwner = session.getPlayerInstance().hasRight("any_room_owner") || session.getPlayerInstance().getInformation().getId() == this.information.getOwnerId(); return ownerRights ? isOwner : (isOwner || session.getPlayerInstance().hasRight("any_room_rights") || this.rights.contains(session.getPlayerInstance().getInformation().getId())); } public boolean hasRights(final Session session) { return hasRights(session, false); } public double getAltitude(final Vector2 position) { return this.gameMap.getHeight(position.getX(), position.getY()); } public RoomItem getTopItem(final int x, final int y) { final int key = x + (y * this.information.getModel().getHeightMap().getSizeX()); return this.topRoomItems.containsKey(key) && this.topRoomItems.get(key).size() > 0 ? this.topRoomItems.get(key).getLast() : null; } public void load(final ResultSet set) { this.information = new RoomInformation(); try { for (final NavigatorList list : Bootloader.getGame().getNavigatorListManager().getNavigatorLists().values()) { final RoomInformation info = list.getInformationEntry(set.getInt("id")); if (info != null) { this.information = info; break; } } this.information.set(set); ResultSet row = Bootloader.getStorage().queryParams("SELECT player_id FROM room_votes WHERE room_id=" + information.getId()).executeQuery(); while (row.next()) { this.votes.add(row.getInt("player_id")); } row.close(); this.information.setScore(this.votes.size()); row = Bootloader.getStorage().queryParams("SELECT * FROM room_items, items WHERE room_id = " + this.information.getId() + " AND items.id=room_items.item_id").executeQuery(); while (row.next()) { final RoomItem item = new RoomItem(this); item.set(row); this.roomItems.put(row.getInt("room_items.item_id"), item); if (item.getBase().getInteractor() == FurnitureInteractor.MOODLIGHT && this.moodLight == null) { this.moodLight = item; } if (WiredManager.isWiredItem(item.getBase())) { this.wiredHandler.addItem(item.getPosition().getVector2(), WiredManager.getInstance(item, this, item.getTermFlags())); } item.getInteractor().onLoaded(this, item); } row.close(); this.gameMap = new Gamemap(this.information.getModel(), this.information.getModel().getHeightMap(), this.roomItems.values()); for (int y = 0; y < this.information.getModel().getHeightMap().getSizeY(); y++) { for (int x = 0; x < this.information.getModel().getHeightMap().getSizeX(); x++) { final GapList<RoomItem> items = new GapList<>(); for (final RoomItem item : this.roomItems.values()) { if (item == null) { continue; } final List<Vector2> affectedTiles = item.getAffectedTiles(); boolean containsPosition = false; for (final Vector2 affectedTile : affectedTiles) { if (affectedTile.getX() == x && affectedTile.getY() == y) { containsPosition = true; break; } } if (containsPosition) { items.add(item); } } Collections.sort(items, new Comparator<RoomItem>() { @Override public int compare(final RoomItem arg0, final RoomItem arg1) { return ((Double) (arg0.getPosition().getAltitude())).compareTo((arg1.getPosition().getAltitude())); } }); this.topRoomItems.put(x + (y * this.information.getModel().getHeightMap().getSizeX()), items); } } this.roomItemsInitialized = true; row = Bootloader.getStorage().queryParams("SELECT * FROM room_rights WHERE room_id=" + information.getId()).executeQuery(); while (row.next()) { this.rights.add(row.getInt("player_id")); } row.close(); } catch (final SQLException e) { logger.error("SQL Exception", e); } for (final BotInstance bot : Bootloader.getGame().getBotManager().getBotsByRoomId(this.information.getId())) { final RoomPlayer player = new RoomPlayer(virtualPlayerId++, bot, this.information.getId(), this, bot.getStartPosition(), bot.getStartRotation()); this.roomPlayers.put(player.getVirtualId(), player); if (player.getBotInstance().getInteractor() != null) { player.getBotInstance().getInteractor().onLoaded(this, player); } } } public void onPlayerLeaves(final RoomPlayer player) { if (player.getCurrentTileState() != -1) { this.gameMap.updateTile(player.getPosition().getVector2(), player.getCurrentTileState()); } if (player.getFloorItem() != null) { player.getFloorItem().onPlayerWalksOff(player, true); } if (player.getEffectId() > 0) { final GameTeam team = this.roomTask.getBanzaiTask().getTeam(player.getEffectId()); if (team != null && team.getGate() != null) { int oldTeamPlayers = team.getGate().getFlagsState(); team.removePlayer(player); team.getGate().setFlags(--oldTeamPlayers + ""); team.getGate().update(false, true); } } Trade trade; if ((trade = this.tradeManager.getTrade(player.getPlayerInformation().getId())) != null) { tradeManager.stopTrade(player.getPlayerInformation().getId()); Session targetSession = null; final int targetId = player.getPlayerInformation().getId() == trade.getPlayerOne() ? trade.getPlayerTwo() : trade.getPlayerOne(); for (final RoomPlayer target : this.getRoomPlayers().values()) { if (target.getSession() != null && target.getSession().getPlayerInstance().getInformation().getId() == targetId) { targetSession = target.getSession(); } } if (targetSession != null && targetSession.getRoomPlayer() != null) { targetSession.writeMessage(new TradeAbortedWriter(player.getPlayerInformation().getId())); targetSession.getRoomPlayer().removeStatus("trd"); targetSession.getRoomPlayer().update(); } } this.writeMessage(new RoomPlayerRemovedWriter(player.getVirtualId()), null); this.getInformation().totalPlayers--; for (final MessengerBuddy buddy : player.getSession().getPlayerMessenger().getOnlineBuddies().values()) { buddy.getSession().getPlayerMessenger().onStatusChanged(player.getSession().getPlayerInstance().getInformation().getId()); } } public MessageWriter getStatusUpdates(final boolean all) { final List<RoomPlayer> updatedPlayers = new GapList<>(); for (final RoomPlayer player : this.roomPlayers.values()) { if (!all) { if (!player.needsUpdate()) { continue; } player.setUpdateNeeded(false); } updatedPlayers.add(player); } if (updatedPlayers.size() == 0) { return null; } return new RoomPlayerStatusListWriter(updatedPlayers); } public boolean giveRights(final RoomPlayer player) { if (player.isBot() || this.rights.contains(player.getPlayerInformation().getId())) { return true; // TODO: Should be false?? } this.rights.add(player.getPlayerInformation().getId()); player.addStatus("flatctrl", ""); player.update(); player.getSession().writeMessage(new RoomRightsWriter()); Bootloader.getStorage().executeQuery("INSERT INTO room_rights (room_id, player_id) VALUES (" + this.information.getId() + ", " + player.getPlayerInformation().getId() + ")"); return true; } public boolean takeRights(final int playerId) { if (!this.rights.contains(playerId)) { return false; } this.rights.remove(new Integer(playerId)); final Session playerSession = Bootloader.getSessionManager().getAuthenticatedSession(playerId); if (playerSession != null && playerSession.isInRoom() && playerSession.getRoomId() == this.information.getId()) { playerSession.getRoomPlayer().removeStatus("flatctrl"); playerSession.getRoomPlayer().update(); playerSession.writeMessage(new RoomRightsRemovedWriter()); } Bootloader.getStorage().executeQuery("DELETE FROM room_rights WHERE player_id=" + playerId + " AND room_id=" + this.information.getId()); return true; } public void onPlayerEnters(final RoomPlayer player) { final List<RoomPlayer> playersToDisplay = new GapList<>(); final QueuedMessageWriter queue = new QueuedMessageWriter(); if (this.hasRights(player.getSession())) { player.addStatus("flatctrl", this.hasRights(player.getSession(), true) ? "useradmin" : ""); } player.getSession().setRoomJoined(true); player.getSession().setRoomPlayer(player); if (player.getSession().isTeleporting()) { if (this.getRoomItems().containsKey(player.getSession().getTargetTeleporter())) { final RoomItem targetTeleporter = this.getRoomItems().get(player.getSession().getTargetTeleporter()); if (!targetTeleporter.getInteractingPlayers().containsKey(2)) { player.setWalkingBlocked(true); player.setPosition(targetTeleporter.getPosition()); player.setRotation(targetTeleporter.getRotation()); targetTeleporter.getInteractingPlayers().put(2, player.getVirtualId()); targetTeleporter.setFlags(2); targetTeleporter.update(); targetTeleporter.requestCycles(2); } } player.getSession().setTargetTeleporterId(0); } for (final RoomPlayer disp : this.roomPlayers.values()) { playersToDisplay.add(disp); } queue.push(new RoomPlayerObjectListWriter(playersToDisplay)); queue.push(new RoomWallsStatusWriter(information.wallsHidden(), information.getWallThickness(), information.getFloorThickness())); queue.push( new RoomInfoRightsWriter( (information.getRoomType() == RoomType.PRIVATE), information.getId(), information.getOwnerId() == player.getSession().getPlayerInstance().getInformation().getId() || player.getSession().getPlayerInstance().hasRight("any_room_owner"), "" ) ); queue.push(new RoomInfoWriter(this)); final MessageWriter updates = this.getStatusUpdates(true); if (updates != null) { queue.push(updates); } for (final RoomPlayer disp : this.roomPlayers.values()) { if (disp.getEffectId() > 0) { queue.push(new RoomPlayerEffectWriter(disp.getVirtualId(), disp.getEffectId())); } if (disp.getDanceId() > 0) { queue.push(new RoomPlayerDanceWriter(disp.getVirtualId(), disp.getDanceId())); } if (disp.getHanditemId() > 0) { queue.push(new RoomPlayerCarryItemWriter(disp.getVirtualId(), disp.getHanditemId())); } } this.writeMessage(new RoomPlayerObjectListWriter(player), null); this.getInformation().totalPlayers++; player.getSession().writeMessage(queue); player.update(); this.wiredHandler.onPlayerEnters(player); for (final MessengerBuddy buddy : player.getSession().getPlayerMessenger().getOnlineBuddies().values()) { buddy.getSession().getPlayerMessenger().onStatusChanged(player.getSession().getPlayerInstance().getInformation().getId()); } } public void onPlayerChat(final ChatMessage message) { if (message == null || message.getSender() == null) { return; } if (this.wiredHandler.onPlayerSays(message.getSender(), message.getMessage())) { return; } final MessageWriter chatWriter = new RoomChatWriter(message.getSender().getVirtualId(), message.getMessage(), 0, message.getChatType()); this.writeMessage(chatWriter, null); if (!message.getSender().isBot()) { for (final RoomPlayer player : this.roomPlayers.values()) { if (player.isBot() && player.getBotInstance().getInteractor() != null && Heightmap.getDistance( message.getSender().getPosition().getX(), message.getSender().getPosition().getY(), player.getPosition().getX(), player.getPosition().getY() ) < 10) { if (message.getChatType() == ChatType.SHOUT && new Random().nextInt(10) % 2 == 0) { player.chat(IDK.BOTS_SHOUT_RESPONSES[new Random().nextInt(IDK.BOTS_SHOUT_RESPONSES.length)], ChatType.SHOUT); continue; } final String[] words = message.getMessage().replace("?", "").replace("!", "").replace(".", "").split(" "); for (String word : words) { word = word.toLowerCase(); if (player.getBotInstance().getKeywordReactions().containsKey(word)) { final BotKeywordReaction reaction = player.getBotInstance().getKeywordReactions().get(word); if (reaction.getResponses().length > 0) { final String response = reaction.getResponses()[new Random().nextInt(reaction.getResponses().length)]; if (reaction.getChatType() == ChatType.WHISPER) { player.whisper(message.getSender().getSession(), player.getVirtualId(), response); } else { player.chat(response, reaction.getChatType()); } } if (reaction.getDrinks().length > 0) { message.getSender().handleVending(reaction.getDrinks()[new Random().nextInt(reaction.getDrinks().length)]); } break; } } player.getBotInstance().getInteractor().onPlayerSays(message.getSender(), player, message); } } } message.dispose(); } public void addPlayerToRoom(final Session session) { if (this.roomTask.isCanceled()) { this.roomTask.setCanceled(false); } this.roomTask.offerRoomPlayerAdd( new RoomPlayer( virtualPlayerId++, session, this.information.getId(), this, this.information.getModel().getDoorPosition(), this.information.getModel().getDoorRotation() ) ); session.setLoadingRoomId(information.getId()); session.setRoomJoined(true); } public void removePlayerFromRoom(final Session session, final boolean notifyClient, final boolean kickNotification) { if (kickNotification) { session.writeMessage(new GenericErrorWriter(4008)); } if (notifyClient) { session.writeMessage(new RoomKickedWriter()); } final RoomPlayer player = session.getRoomPlayer(); this.roomTask.offerRoomPlayerRemove(player); session.setLoadingRoomId(0); session.setRoomJoined(false); session.setRoomPlayer(null); this.writeMessage(new RoomPlayerRemovedWriter(player.getVirtualId()), null); } public void writeMessage(final MessageWriter writer, final Session sender) { if (sender != null) { sender.writeMessage(writer); writer.setSender(sender.getId()); } this.roomTask.offerRoomMessageWriter(writer); } public void queueModelData(final QueuedMessageWriter queue) { queue.push(this.information.getModel().getHeightmapWriter()); queue.push(this.getGamemap().getRelativeMap()); } public void removeItem(final RoomItem item, final Session session) { final boolean isFloorItem = !item.getBase().getType().equals(FurnitureType.WALL); final GapList<RoomPlayer> toUpdate = new GapList<>(); if (isFloorItem) { for (final Vector2 posAct : item.getAffectedTiles()) { RoomItem oldHighest = null; for (final RoomItem yitem : this.getRoomItemsForTile(posAct)) { if (yitem.getItemId() != item.getItemId() && (oldHighest == null || yitem.getAbsoluteHeight() > oldHighest.getAbsoluteHeight())) { oldHighest = yitem; } } RoomItem checkItem; int oldState; double oldAltitude; if (oldHighest != null) { oldState = oldHighest.getState(); oldAltitude = oldHighest.getBase().isLayable() || oldHighest.getBase().isSitable() ? oldHighest.getPosition().getAltitude() : oldHighest.getAbsoluteHeight(); checkItem = oldHighest; } else { oldState = this.information.getModel().getHeightMap().getTileState(posAct.getX(), posAct.getY()); oldAltitude = this.information.getModel().getHeightMap().getFloorHeight(posAct.getX(), posAct.getY()); checkItem = item; } final GapList<RoomItem> items = this.topRoomItems.get(posAct.getX() + (posAct.getY() * this.information.getModel().getHeightMap().getSizeX())); for (int i = 0; i < items.size(); ++i) { if (items.get(i).getItemId() == item.getItemId()) { this.topRoomItems.get(posAct.getX() + (posAct.getY() * this.information.getModel().getHeightMap().getSizeX())).remove(i); break; } } this.gameMap.updateTile(posAct, oldState); this.gameMap.setHeight(posAct, oldAltitude); final GapList<RoomPlayer> players = this.getRoomPlayersForTile(posAct); if (players.size() > 0) { for (final RoomPlayer player : players) { if (player.getPosition().getAltitude() >= checkItem.getPosition().getAltitude()) { if (!toUpdate.contains(player)) { toUpdate.add(player); } } } } } this.wiredHandler.onFloorItemRemoved(item); } if (item.getBase().getInteractor() == FurnitureInteractor.MOODLIGHT && this.moodLight != null) { this.moodLight = null; } if (this.itemsToAdd.contains(item.getItemId())) { this.itemsToAdd.remove(new Integer(item.getItemId())); } if (this.itemsToUpdate.contains(item.getItemId())) { this.itemsToUpdate.remove(new Integer(item.getItemId())); } if (item.getBase().isWiredItem()) { this.wiredHandler.removeItem(item, item.getPosition().getVector2()); } this.roomItems.remove(item.getItemId()); this.itemsToRemove.add(item.getItemId()); this.writeMessage(isFloorItem ? new RoomFloorItemRemovedWriter(item.getItemId()) : new RoomWallItemRemovedWriter(item.getItemId()), session); if (isFloorItem) { this.updateRoomPlayers(toUpdate); } item.getInteractor().onRemove(session.getRoomPlayer(), item); } public boolean setFloorItem(final Session session, final RoomItem item, final Vector2 position, final int rotation) { return this.setFloorItem(session, item, position, rotation, false, -1); } public boolean setFloorItem(final Session session, final RoomItem item, final Vector2 position, final int rotation, final boolean update) { return this.setFloorItem(session, item, position, rotation, update, -1); } public boolean setWallItem(final Session session, final RoomItem item, final String data[], final boolean setUpdate) { final boolean newItem = !this.roomItems.containsKey(item.getItemId()); if (data.length != 3 || !data[0].startsWith(":w=") || !data[1].startsWith("l=") || (!data[2].equals("r") && !data[2].equals("l"))) { return false; } final String wBit = data[0].substring(3, data[0].length()); final String lBit = data[1].substring(2, data[1].length()); if (!wBit.contains(",") || !lBit.contains(",")) { return false; } final int w1 = Integer.valueOf(wBit.split(",")[0]); final int w2 = Integer.valueOf(wBit.split(",")[1]); final int l1 = Integer.valueOf(lBit.split(",")[0]); final int l2 = Integer.valueOf(lBit.split(",")[1]); if (!session.getPlayerInstance().hasRight("hotel_admin") && (w1 < 0 || w2 < 0 || l1 < 0 || l2 < 0 || w1 > 200 || w2 > 200 || l1 > 200 || l2 > 200)) { return false; } item.setWallPosition(":w=" + w1 + "," + w2 + " l=" + l1 + "," + l2 + " " + data[2]); if (newItem) { if (item.getBase().getInteractor() == FurnitureInteractor.MOODLIGHT) { if (this.moodLight != null) { return false; } this.moodLight = item; } this.roomItems.put(item.getItemId(), item); if (itemsToRemove.contains(item.getItemId())) { itemsToRemove.remove(new Integer(item.getItemId())); } itemsToAdd.add(item.getItemId()); if (setUpdate) { itemsToUpdate.add(item.getItemId()); } this.writeMessage(new RoomWallItemPlacedWriter(item), session); item.getInteractor().onLoaded(this, item); } else { if (!itemsToAdd.contains(item.getItemId()) && !itemsToRemove.contains(item.getItemId())) { itemsToAdd.add(item.getItemId()); } final MessageWriter update = new RoomWallItemMovedWriter(item); session.writeMessage(update); this.writeMessage(update, session); } return true; } public boolean setFloorItem(final Session session, final RoomItem item, final Vector2 position, final int rotation, final boolean setUpdate, final int rollerId) { return setFloorItem(session, item, position, rotation, setUpdate, rollerId, 0); } public boolean setFloorItem(final Session session, final RoomItem item, final Vector2 position, final int rotation, final boolean setUpdate, final int rollerId, final double rollerItemAltitude) { if (rotation != 2 && rotation != 0 && rotation != 6 && rotation != 4) { return false; } boolean onlyChangeRot = false; final boolean newItem = !this.roomItems.containsKey(item.getItemId()); if (!newItem) { if (item.getPosition().getX() == position.getX() && item.getPosition().getY() == position.getY()) { if (item.getRotation() == rotation) { return false; } onlyChangeRot = true; } } if (!onlyChangeRot) { if (this.gameMap.getTileState(position.getX(), position.getY()) == TileState.CLOSED || ((item.getBase().getWidth() > 1 || item.getBase().getHeight() > 1 || !item.getBase().isWalkable() || item.getBase().getHeight() > 0.2) && this.getInformation().getModel().getDoorPosition().getX() == position.getX() && this.getInformation().getModel().getDoorPosition().getY() == position.getY())) { return false; } } double newAltitude = this.information.getModel().getHeightMap().getFloorHeight(position.getX(), position.getY()); final int oldX = item.getPosition().getX(); final int oldY = item.getPosition().getY(); final int oldRot = item.getRotation(); final double oldAlt = item.getPosition().getAltitude(); final GapList<RoomPlayer> toUpdate = new GapList<>(); RoomItem setItem = null; item.setPosition(new Vector3(position.getX(), position.getY(), 0), rotation); final List<Vector2> newPos = item.getAffectedTiles(); item.setPosition(new Vector3(oldX, oldY, oldAlt), oldRot); for (final Vector2 posAct : newPos) { if (posAct.getX() > information.getModel().getHeightMap().getSizeX() || posAct.getY() > information.getModel().getHeightMap().getSizeY() || gameMap.getTileState(posAct.getX(), posAct.getY()) == TileState.CLOSED) { return false; } final GapList<RoomPlayer> players = this.getRoomPlayersForTile(posAct); if (players.size() > 0) { if (onlyChangeRot && (item.getState() == TileState.SITABLE || item.getState() == (TileState.SITABLE | TileState.PLAYER) || item.getState() == (TileState.SITABLE | TileState.BLOCKED))) { for (final RoomPlayer player : players) { if (!toUpdate.contains(player)) { toUpdate.add(player); } } } else { return false; } } final GapList<RoomItem> items = this.getRoomItemsForTile(posAct); for (final RoomItem xitem : items) { if (xitem.getItemId() != item.getItemId()) { if (rollerId < 0) { if (!xitem.getBase().isStackable() || (item.getInteractorId() == FurnitureInteractor.ROLLER && onlyChangeRot && xitem.getPosition().getAltitude() >= item.getPosition().getAltitude())) { return false; } if (setItem == null || xitem.getAbsoluteHeight() > setItem.getAbsoluteHeight()) { setItem = xitem; } } else if (xitem.getPosition().getAltitude() <= rollerItemAltitude && (setItem == null || xitem.getPosition().getAltitude() >= setItem.getPosition().getAltitude())) { setItem = xitem; } } } if (rollerId > -1 && setItem != null && (setItem.getPosition().getAltitude() == rollerItemAltitude)) { return false; } } if (!newItem) { for (final Vector2 posAct : item.getAffectedTiles()) { RoomItem oldHighest = null; for (final RoomItem yitem : this.getRoomItemsForTile(posAct)) { if (yitem.getItemId() != item.getItemId() && (oldHighest == null || yitem.getAbsoluteHeight() > oldHighest.getAbsoluteHeight())) { oldHighest = yitem; } } RoomItem checkItem; int oldState; double oldAltitude; if (oldHighest != null) { oldState = oldHighest.getState(); oldAltitude = oldHighest.getBase().isLayable() || oldHighest.getBase().isSitable() ? oldHighest.getPosition().getAltitude() : oldHighest.getAbsoluteHeight(); checkItem = oldHighest; } else { oldState = this.information.getModel().getHeightMap().getTileState(posAct.getX(), posAct.getY()); oldAltitude = this.information.getModel().getHeightMap().getFloorHeight(posAct.getX(), posAct.getY()); checkItem = item; } this.gameMap.updateTile(posAct, oldState); this.gameMap.setHeight(posAct, oldAltitude); final GapList<RoomItem> items = this.topRoomItems.get(posAct.getX() + (posAct.getY() * this.information.getModel().getHeightMap().getSizeX())); for (int i = 0; i < items.size(); ++i) { if (items.get(i).getItemId() == item.getItemId()) { this.topRoomItems.get(posAct.getX() + (posAct.getY() * this.information.getModel().getHeightMap().getSizeX())).remove(i); break; } } final GapList<RoomPlayer> players = this.getRoomPlayersForTile(posAct); if (players.size() > 0) { for (final RoomPlayer player : players) { if (player.getPosition().getAltitude() >= checkItem.getPosition().getAltitude()) { if (!toUpdate.contains(player)) { toUpdate.add(player); } } } } } } if (setItem != null) { newAltitude = (rollerId > -1 && setItem.getInteractorId() != FurnitureInteractor.ROLLER && setItem.getAbsoluteHeight() > rollerItemAltitude) ? setItem.getPosition().getAltitude() : setItem.getAbsoluteHeight(); } if (onlyChangeRot && newAltitude < oldAlt) { newAltitude = oldAlt; } final int state = item.getState(); for (final Vector2 posAct : newPos) { this.gameMap.updateTile(posAct, state); if (item.getState() == TileState.SITABLE || item.getState() == TileState.LAYABLE) { this.gameMap.setHeight(posAct, newAltitude); } else { this.gameMap.setHeight(posAct, newAltitude + item.getBase().getHeight()); } this.topRoomItems.get(posAct.getX() + (posAct.getY() * this.information.getModel().getHeightMap().getSizeX())).add(item); } item.setPosition(new Vector3(position.getX(), position.getY(), newAltitude), rotation); if (!newItem) { if (!itemsToAdd.contains(item.getItemId()) && !itemsToRemove.contains(item.getItemId())) { itemsToAdd.add(item.getItemId()); } if (rollerId > -1) { this.writeMessage(new RollerEventWriter(new Vector3(oldX, oldY, oldAlt), item.getPosition(), 0, rollerId, item.getItemId(), true), null); } else { this.writeMessage(new RoomItemUpdatedWriter(item), session); } this.updateRoomPlayers(toUpdate); } else { this.roomItems.put(item.getItemId(), item); if (itemsToRemove.contains(item.getItemId())) { itemsToRemove.remove(new Integer(item.getItemId())); } itemsToAdd.add(item.getItemId()); if (setUpdate) { itemsToUpdate.add(item.getItemId()); } this.writeMessage(new RoomFloorItemPlacedWriter(item), session); item.getInteractor().onLoaded(this, item); } if (!item.getBase().isWiredItem()) { item.getInteractor().onPlace(session != null ? session.getRoomPlayer() : null, item); } else if (!newItem) { this.wiredHandler.moveWired(item, new Vector2(oldX, oldY)); } else { this.wiredHandler.addItem(item.getPosition().getVector2(), WiredManager.getInstance(item, this, item.getTermFlags())); } return true; } public GapList<RoomItem> getRoomItemsForTile(final Vector2 pos) { return this.topRoomItems.get(pos.getX() + (pos.getY() * this.information.getModel().getHeightMap().getSizeX())); } public boolean roomItemsInitialized() { return this.roomItemsInitialized; } public void updateRoomPlayers(final GapList<RoomPlayer> players) { for (final RoomPlayer player : players) { final int state = this.gameMap.getTileState(player.getPosition().getX(), player.getPosition().getY()); player.setPosition(new Vector3(player.getPosition().getX(), player.getPosition().getY(), this.gameMap.getHeight(player.getPosition().getX(), player.getPosition().getY()))); this.getGamemap().updateTile(player.getPosition().getVector2(), this.getInformation().blockingDisabled() ? TileState.PLAYER : TileState.BLOCKED); player.setFloorItem(null); player.setCurrentTileState(state); player.removeStatus("sit"); player.removeStatus("lay"); if (player.getEffectId() > 0) { player.applyEffect(0); player.applyEffect(player.getEffectCache() > 0 ? player.getEffectCache() : 0); if (player.getEffectCache() > 0) { player.setEffectCache(0); } } RoomItem highestItem = this.getTopItem(player.getPosition().getX(), player.getPosition().getY()); if (highestItem != null) { if (state == TileState.SITABLE || state == (TileState.SITABLE | TileState.PLAYER) || state == (TileState.SITABLE | TileState.BLOCKED)) { for (final RoomItem item : this.getRoomItemsForTile(player.getPosition().getVector2())) { if ((item.getAbsoluteHeight() > highestItem.getAbsoluteHeight()) && item.getBase().isSitable()) { highestItem = item; } } player.setRotation(highestItem.getRotation()); player.addStatus("sit", String.valueOf(highestItem.getBase().getHeight())); } final boolean oxi = state == TileState.SITABLE || state == TileState.LAYABLE; this.getGamemap().updateTile( player.getPosition().getVector2(), this.getInformation().blockingDisabled() ? (TileState.PLAYER | (oxi ? state : 0)) : (TileState.BLOCKED | (oxi ? state : 0)) ); player.setFloorItem(highestItem); highestItem.onPlayerWalksOn(player, true); } player.update(); } } public GapList<RoomPlayer> getRoomPlayersForTile(final Vector2 pos) { final GapList<RoomPlayer> players = new GapList<>(); for (final RoomPlayer player : roomPlayers.values()) { if (player.getPosition().getX() == pos.getX() && player.getPosition().getY() == pos.getY() || (player.stepIsSetted() && player.getSettedPosition().getX() == pos.getX() && player.getSettedPosition().getY() == pos.getY())) { players.add(player); } } return players; } public GapList<RoomPlayer> getRoomPlayersList() { return (GapList<RoomPlayer>) roomPlayers.values(); } public void queueItemCycle(final RoomItem item) { this.roomTask.offerItemCycle(item); } public void save() { final StringBuilder removeQuery = new StringBuilder(); for (final Integer removeItem : this.itemsToRemove) { removeQuery.append(" OR item_id=").append(removeItem); } if (removeQuery.length() > 0) { Bootloader.getStorage().executeQuery("DELETE FROM room_items WHERE " + removeQuery.toString().substring(4)); } this.itemsToRemove.clear(); final StringBuilder insertQuery = new StringBuilder(); for (final Integer addItem : this.itemsToAdd) { if (this.roomItems.get(addItem).getBase().getInteractor() == FurnitureInteractor.TELEPORTER) { Bootloader.getGame().getRoomManager().getTeleporterCache().remove(addItem); } insertQuery.append(" ,(") .append(addItem).append(", ").append(this.information.getId()).append(", ") .append(this.roomItems.get(addItem).getPosition().getX()).append(", ") .append(this.roomItems.get(addItem).getPosition().getY()).append(", ") .append(this.roomItems.get(addItem).getRotation()).append(", ") .append(String.valueOf(this.roomItems.get(addItem).getPosition().getAltitude())) .append(", ").append("'").append(this.roomItems.get(addItem).getWallPosition()).append("')"); } final StringBuilder updateQuery = new StringBuilder(); List<String> flagList = new GapList<>(); for (final Integer updateItem : this.itemsToUpdate) { if (!this.roomItems.containsKey(updateItem)) { continue; } updateQuery.append(" ,(").append(updateItem).append(", ?)"); String flags = this.roomItems.get(updateItem).getFlags(); if (this.roomItems.get(updateItem).getTermFlags() != null) { flags = ""; for (final String tFlag : this.roomItems.get(updateItem).getTermFlags()) { flags += tFlag + (char) 10; } } flagList.add(flags); } if (insertQuery.length() > 0) { Bootloader.getStorage().executeQuery("REPLACE INTO room_items (item_id, room_id, position_x, position_y, rotation, position_altitude, wall_position) " + "VALUES " + insertQuery.toString().substring(2)); } if (updateQuery.length() > 0) { final PreparedStatement pn = Bootloader.getStorage().queryParams("REPLACE INTO item_flags (item_id, flag) VALUES " + updateQuery.toString().substring(2)); try { for (int i = 0; i < flagList.size(); i++) { pn.setString(i + 1, flagList.get(i)); } pn.execute(); } catch (final SQLException ex) { logger.error("SQL Exception", ex); } flagList.clear(); } this.itemsToAdd.clear(); this.itemsToUpdate.clear(); } public void addItemToUpdate(final Integer itemId) { this.itemsToUpdate.add(itemId); } public boolean itemHasToUpdate(final Integer item) { return this.itemsToUpdate.contains(item); } public void refresh() { this.roomTask.setCanceled(true); this.save(); } public GapList<RoomItem> getFloorItems() { final GapList<RoomItem> items = new GapList<>(); for (final RoomItem item : this.roomItems.values()) { if (item != null && !item.getBase().getType().equals(FurnitureType.WALL)) { items.add(item); } } return items; } public GapList<RoomItem> getWallItems() { final GapList<RoomItem> items = new GapList<>(); for (final RoomItem item : this.roomItems.values()) { if (item != null && item.getBase().getType().equals(FurnitureType.WALL)) { items.add(item); } } return items; } public void setGuestStickysAllowed(final boolean allowed) { this.guestStickysAllowed = allowed; } private RoomInformation information; private Gamemap gameMap; private final RoomTask roomTask; private final WiredHandler wiredHandler; private final TradeManager tradeManager; private final GapList<Integer> votes; private final GapList<Integer> rights; private final ConcurrentHashMap<Integer, RoomPlayer> roomPlayers; private final ConcurrentHashMap<Integer, RoomItem> roomItems; private final ConcurrentHashMap<Integer, GapList<RoomItem>> topRoomItems; private final ConcurrentHashMap<Integer, GapList<RoomPlayer>> topRoomPlayers; private RoomItem moodLight; private int virtualPlayerId; private boolean guestStickysAllowed; private boolean roomItemsInitialized; // sql queues private final GapList<Integer> itemsToAdd; private final GapList<Integer> itemsToRemove; private final GapList<Integer> itemsToUpdate; }