mirror of
https://git.krews.org/morningstar/Arcturus-Community.git
synced 2024-11-27 00:40:52 +01:00
Merge branch '178-pathfinder-crashing' into 'dev'
Resolve "Pathfinder crashing." See merge request morningstar/Arcturus-Community!44
This commit is contained in:
commit
2c22b0c8e3
@ -11,10 +11,10 @@ TheGeneral's own words were "dont like it then dont use it". We did not like wha
|
|||||||
Arcturus Morningstar is released under the [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.txt).
|
Arcturus Morningstar is released under the [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.txt).
|
||||||
|
|
||||||
## Versions ##
|
## Versions ##
|
||||||
![image](https://img.shields.io/badge/VERSION-2.1.0-orange.svg?style=for-the-badge&logo=appveyor)
|
![image](https://img.shields.io/badge/VERSION-2.0.0-success.svg?style=for-the-badge&logo=appveyor)
|
||||||
![image](https://img.shields.io/badge/STATUS-unstable-critical.svg?style=for-the-badge&logo=appveyor)
|
![image](https://img.shields.io/badge/STATUS-STABLE-blue.svg?style=for-the-badge&logo=appveyor)
|
||||||
|
|
||||||
Compiled Download: Has not yet reached a Release Candidate.
|
Compiled Download: https://git.krews.org/morningstar/Arcturus-Community/releases
|
||||||
|
|
||||||
Client build: **PRODUCTION-201611291003-338511768**
|
Client build: **PRODUCTION-201611291003-338511768**
|
||||||
|
|
||||||
|
@ -97,12 +97,6 @@ public final class Emulator {
|
|||||||
|
|
||||||
Emulator.runtime = Runtime.getRuntime();
|
Emulator.runtime = Runtime.getRuntime();
|
||||||
Emulator.config = new ConfigurationManager("config.ini");
|
Emulator.config = new ConfigurationManager("config.ini");
|
||||||
|
|
||||||
if (Emulator.getConfig().getValue("username").isEmpty()) {
|
|
||||||
Emulator.getLogging().logErrorLine("Please make sure you enter your forum login details!");
|
|
||||||
Thread.sleep(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
Emulator.database = new Database(Emulator.getConfig());
|
Emulator.database = new Database(Emulator.getConfig());
|
||||||
Emulator.config.loaded = true;
|
Emulator.config.loaded = true;
|
||||||
Emulator.config.loadFromDatabase();
|
Emulator.config.loadFromDatabase();
|
||||||
@ -123,12 +117,6 @@ public final class Emulator {
|
|||||||
Emulator.rconServer.initializePipeline();
|
Emulator.rconServer.initializePipeline();
|
||||||
Emulator.rconServer.connect();
|
Emulator.rconServer.connect();
|
||||||
Emulator.badgeImager = new BadgeImager();
|
Emulator.badgeImager = new BadgeImager();
|
||||||
// Removed Wesleys Camera Server lol.
|
|
||||||
/* if (Emulator.getConfig().getBoolean("camera.enabled"))
|
|
||||||
{
|
|
||||||
Emulator.getThreading().run(new CameraClientAutoReconnect());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
Emulator.getLogging().logStart("Habbo Hotel Emulator has succesfully loaded.");
|
Emulator.getLogging().logStart("Habbo Hotel Emulator has succesfully loaded.");
|
||||||
Emulator.getLogging().logStart("You're running: " + Emulator.version);
|
Emulator.getLogging().logStart("You're running: " + Emulator.version);
|
||||||
Emulator.getLogging().logStart("System launched in: " + (System.nanoTime() - startTime) / 1e6 + "ms. Using: " + (Runtime.getRuntime().availableProcessors() * 2) + " threads!");
|
Emulator.getLogging().logStart("System launched in: " + (System.nanoTime() - startTime) / 1e6 + "ms. Using: " + (Runtime.getRuntime().availableProcessors() * 2) + " threads!");
|
||||||
|
@ -253,42 +253,29 @@ public class RoomLayout {
|
|||||||
return this.roomTiles[x][y].state == RoomTileState.INVALID;
|
return this.roomTiles[x][y].state == RoomTileState.INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoomTileState getStateAt(short x, short y) {
|
|
||||||
return this.roomTiles[x][y].state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRelativeMap() {
|
public String getRelativeMap() {
|
||||||
return this.heightmap.replace("\r\n", "\r");
|
return this.heightmap.replace("\r\n", "\r");
|
||||||
}
|
}//re
|
||||||
|
|
||||||
|
/// Pathfinder Reworked By Quadral, thanks buddy!! You Saved Morningstar <3
|
||||||
public final Deque<RoomTile> findPath(RoomTile oldTile, RoomTile newTile, RoomTile goalLocation, RoomUnit roomUnit) {
|
public final Deque<RoomTile> findPath(RoomTile oldTile, RoomTile newTile, RoomTile goalLocation, RoomUnit roomUnit) {
|
||||||
LinkedList<RoomTile> openList = new LinkedList<>();
|
|
||||||
try {
|
|
||||||
if (this.room == null || !this.room.isLoaded() || oldTile == null || newTile == null || oldTile.equals(newTile) || newTile.state == RoomTileState.INVALID)
|
if (this.room == null || !this.room.isLoaded() || oldTile == null || newTile == null || oldTile.equals(newTile) || newTile.state == RoomTileState.INVALID)
|
||||||
return openList;
|
|
||||||
|
|
||||||
List<RoomTile> closedList = new LinkedList<>();
|
|
||||||
|
|
||||||
openList.add(oldTile.copy());
|
|
||||||
|
|
||||||
long startMillis = System.currentTimeMillis();
|
|
||||||
while (true) {
|
|
||||||
if (System.currentTimeMillis() - startMillis > 50) {
|
|
||||||
return new LinkedList<>();
|
return new LinkedList<>();
|
||||||
}
|
LinkedList<RoomTile> openList = new LinkedList<>();
|
||||||
|
List<RoomTile> closedList = new LinkedList<>();
|
||||||
RoomTile current = this.lowestFInOpen(openList);
|
RoomTile current;
|
||||||
openList.remove(current);
|
openList.add(oldTile.copy());
|
||||||
|
while (!openList.isEmpty()) {
|
||||||
|
current = this.lowestFInOpen(openList);
|
||||||
if ((current.x == newTile.x) && (current.y == newTile.y)) {
|
if ((current.x == newTile.x) && (current.y == newTile.y)) {
|
||||||
return this.calcPath(this.findTile(openList, oldTile.x, oldTile.y), current);
|
return this.calcPath(this.findTile(openList, oldTile.x, oldTile.y), current);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
closedList.add(current);
|
||||||
|
openList.remove(current);
|
||||||
List<RoomTile> adjacentNodes = this.getAdjacent(openList, current, newTile);
|
List<RoomTile> adjacentNodes = this.getAdjacent(openList, current, newTile);
|
||||||
|
|
||||||
for (RoomTile currentAdj : adjacentNodes) {
|
for (RoomTile currentAdj : adjacentNodes) {
|
||||||
if (closedList.contains(currentAdj)) continue;
|
if (closedList.contains(currentAdj)) continue;
|
||||||
|
|
||||||
if (roomUnit.canOverrideTile(currentAdj) || (currentAdj.state != RoomTileState.BLOCKED && currentAdj.x == doorX && currentAdj.y == doorY)) {
|
if (roomUnit.canOverrideTile(currentAdj) || (currentAdj.state != RoomTileState.BLOCKED && currentAdj.x == doorX && currentAdj.y == doorY)) {
|
||||||
currentAdj.setPrevious(current);
|
currentAdj.setPrevious(current);
|
||||||
currentAdj.sethCosts(this.findTile(openList, newTile.x, newTile.y));
|
currentAdj.sethCosts(this.findTile(openList, newTile.x, newTile.y));
|
||||||
@ -296,33 +283,19 @@ public class RoomLayout {
|
|||||||
openList.add(currentAdj);
|
openList.add(currentAdj);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if ((currentAdj.state == RoomTileState.BLOCKED) || ((currentAdj.state == RoomTileState.SIT || currentAdj.state == RoomTileState.LAY) && !currentAdj.equals(goalLocation))) {
|
||||||
//If the tile is sitable or layable and its not our goal tile, we cannot walk over it.
|
|
||||||
if (!currentAdj.equals(goalLocation) && (currentAdj.state == RoomTileState.BLOCKED || currentAdj.state == RoomTileState.SIT || currentAdj.state == RoomTileState.LAY)) {
|
|
||||||
closedList.add(currentAdj);
|
closedList.add(currentAdj);
|
||||||
openList.remove(currentAdj);
|
openList.remove(currentAdj);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
////if (!room.getLayout().tileWalkable((short) currentAdj.x, (short) currentAdj.y)) continue;
|
|
||||||
|
|
||||||
//Height difference.
|
|
||||||
double height = currentAdj.getStackHeight() - current.getStackHeight();
|
double height = currentAdj.getStackHeight() - current.getStackHeight();
|
||||||
|
|
||||||
//If we are not allowed to fall and the height difference is bigger than the maximum stepheight, continue.
|
|
||||||
if (!ALLOW_FALLING && height < -MAXIMUM_STEP_HEIGHT) continue;
|
if (!ALLOW_FALLING && height < -MAXIMUM_STEP_HEIGHT) continue;
|
||||||
|
|
||||||
//If the step difference is bigger than the maximum step height, continue.
|
|
||||||
if (currentAdj.state == RoomTileState.OPEN && height > MAXIMUM_STEP_HEIGHT) continue;
|
if (currentAdj.state == RoomTileState.OPEN && height > MAXIMUM_STEP_HEIGHT) continue;
|
||||||
|
|
||||||
//Check if the tile has habbos.
|
|
||||||
if (currentAdj.hasUnits() && (!this.room.isAllowWalkthrough() || currentAdj.equals(goalLocation))) {
|
if (currentAdj.hasUnits() && (!this.room.isAllowWalkthrough() || currentAdj.equals(goalLocation))) {
|
||||||
closedList.add(currentAdj);
|
closedList.add(currentAdj);
|
||||||
openList.remove(currentAdj);
|
openList.remove(currentAdj);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (room.hasPetsAt(currentAdj.x, currentAdj.y)) continue;
|
|
||||||
|
|
||||||
if (!openList.contains(currentAdj)) {
|
if (!openList.contains(currentAdj)) {
|
||||||
currentAdj.setPrevious(current);
|
currentAdj.setPrevious(current);
|
||||||
currentAdj.sethCosts(this.findTile(openList, newTile.x, newTile.y));
|
currentAdj.sethCosts(this.findTile(openList, newTile.x, newTile.y));
|
||||||
@ -333,13 +306,8 @@ public class RoomLayout {
|
|||||||
currentAdj.setgCosts(current);
|
currentAdj.setgCosts(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (openList.isEmpty()) {
|
|
||||||
return new LinkedList<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Emulator.getLogging().logErrorLine(e);
|
|
||||||
}
|
}
|
||||||
|
// System.out.println("Invalid Path.");
|
||||||
return new LinkedList<>();
|
return new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,8 +573,6 @@ public class RoomLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean fitsOnMap(RoomTile tile, int width, int length, int rotation) {
|
public boolean fitsOnMap(RoomTile tile, int width, int length, int rotation) {
|
||||||
THashSet<RoomTile> pointList = new THashSet<>(width * length, 0.1f);
|
|
||||||
|
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
if (rotation == 0 || rotation == 4) {
|
if (rotation == 0 || rotation == 4) {
|
||||||
for (short i = tile.x; i <= (tile.x + (width - 1)); i++) {
|
for (short i = tile.x; i <= (tile.x + (width - 1)); i++) {
|
||||||
|
@ -47,6 +47,20 @@ public class RoomTile {
|
|||||||
this.units = tile.units;
|
this.units = tile.units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RoomTile()
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
z = 0;
|
||||||
|
this.stackHeight = 0;
|
||||||
|
this.state = RoomTileState.INVALID;
|
||||||
|
this.allowStack = false;
|
||||||
|
this.diagonally = false;
|
||||||
|
this.gCosts = 0;
|
||||||
|
this.hCosts = 0;
|
||||||
|
this.units = null;
|
||||||
|
}
|
||||||
|
|
||||||
public double getStackHeight() {
|
public double getStackHeight() {
|
||||||
return this.stackHeight;
|
return this.stackHeight;
|
||||||
}
|
}
|
||||||
|
@ -227,17 +227,15 @@ public class RoomUnit {
|
|||||||
|
|
||||||
//if(!(this.path.size() == 0 && canSitNextTile))
|
//if(!(this.path.size() == 0 && canSitNextTile))
|
||||||
{
|
{
|
||||||
if (!room.tileWalkable(next.x, next.y) && !overrideChecks) {
|
if (!room.tileWalkable(next)) {
|
||||||
this.room = room;
|
this.room = room;
|
||||||
this.findPath();
|
this.findPath();
|
||||||
|
|
||||||
if (!this.path.isEmpty()) {
|
if (this.path.isEmpty()) {
|
||||||
next = this.path.pop();
|
|
||||||
item = room.getTopItemAt(next.x, next.y);
|
|
||||||
} else {
|
|
||||||
this.status.remove(RoomUnitStatus.MOVE);
|
this.status.remove(RoomUnitStatus.MOVE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
next = (RoomTile)this.path.pop();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,14 +463,15 @@ public class RoomUnit {
|
|||||||
|
|
||||||
public void setGoalLocation(RoomTile goalLocation) {
|
public void setGoalLocation(RoomTile goalLocation) {
|
||||||
if (goalLocation != null) {
|
if (goalLocation != null) {
|
||||||
if (goalLocation.state != RoomTileState.INVALID) {
|
// if (goalLocation.state != RoomTileState.INVALID) {
|
||||||
this.setGoalLocation(goalLocation, false);
|
this.setGoalLocation(goalLocation, false);
|
||||||
}
|
}
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGoalLocation(RoomTile goalLocation, boolean noReset) {
|
public void setGoalLocation(RoomTile goalLocation, boolean noReset) {
|
||||||
if (Emulator.getPluginManager().isRegistered(RoomUnitSetGoalEvent.class, false)) {
|
if (Emulator.getPluginManager().isRegistered(RoomUnitSetGoalEvent.class, false))
|
||||||
|
{
|
||||||
Event event = new RoomUnitSetGoalEvent(this.room, this, goalLocation);
|
Event event = new RoomUnitSetGoalEvent(this.room, this, goalLocation);
|
||||||
Emulator.getPluginManager().fireEvent(event);
|
Emulator.getPluginManager().fireEvent(event);
|
||||||
|
|
||||||
@ -480,16 +479,18 @@ public class RoomUnit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set start location
|
||||||
this.startLocation = this.currentLocation;
|
this.startLocation = this.currentLocation;
|
||||||
|
|
||||||
if (goalLocation != null && !noReset) {
|
if (goalLocation != null && !noReset) {
|
||||||
this.goalLocation = goalLocation;
|
this.goalLocation = goalLocation;
|
||||||
this.findPath();
|
this.findPath(); ///< Quadral: this is where we start formulating a path
|
||||||
if (!this.path.isEmpty()) {
|
if (!this.path.isEmpty()) {
|
||||||
this.tilesWalked = 0;
|
this.tilesWalked = 0;
|
||||||
this.cmdSit = false;
|
this.cmdSit = false;
|
||||||
} else {
|
} else {
|
||||||
this.goalLocation = this.currentLocation;
|
this.goalLocation = this.currentLocation;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,8 +525,11 @@ public class RoomUnit {
|
|||||||
this.room = room;
|
this.room = room;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void findPath() {
|
public void findPath()
|
||||||
if (this.room != null && this.room.getLayout() != null && this.goalLocation != null && (this.goalLocation.isWalkable() || this.room.canSitOrLayAt(this.goalLocation.x, this.goalLocation.y) || this.canOverrideTile(this.goalLocation))) {
|
{
|
||||||
|
if (this.room != null && this.room.getLayout() != null && this.goalLocation != null && (this.goalLocation.isWalkable() || this.room.canSitOrLayAt(this.goalLocation.x, this.goalLocation.y) || this.canOverrideTile(this.goalLocation)))
|
||||||
|
{
|
||||||
|
|
||||||
this.path = this.room.getLayout().findPath(this.currentLocation, this.goalLocation, this.goalLocation, this);
|
this.path = this.room.getLayout().findPath(this.currentLocation, this.goalLocation, this.goalLocation, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,20 +15,28 @@ import gnu.trove.set.hash.THashSet;
|
|||||||
|
|
||||||
public class RoomUserWalkEvent extends MessageHandler {
|
public class RoomUserWalkEvent extends MessageHandler {
|
||||||
@Override
|
@Override
|
||||||
public void handle() throws Exception {
|
public void handle() throws Exception
|
||||||
if (this.client.getHabbo().getHabboInfo().getCurrentRoom() != null) {
|
{
|
||||||
int x = this.packet.readInt();
|
if (this.client.getHabbo().getHabboInfo().getCurrentRoom() != null)
|
||||||
int y = this.packet.readInt();
|
{
|
||||||
|
int x = this.packet.readInt(); ///< Position X
|
||||||
|
int y = this.packet.readInt(); ///<Position Y
|
||||||
|
|
||||||
|
/// Get Habbo object
|
||||||
Habbo habbo = this.client.getHabbo();
|
Habbo habbo = this.client.getHabbo();
|
||||||
|
|
||||||
|
/// Get Room Habbo object (Unique GUID?)
|
||||||
RoomUnit roomUnit = this.client.getHabbo().getRoomUnit();
|
RoomUnit roomUnit = this.client.getHabbo().getRoomUnit();
|
||||||
|
|
||||||
|
/// If habbo is teleporting, dont calculate a new path
|
||||||
if (roomUnit.isTeleporting)
|
if (roomUnit.isTeleporting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/// If habbo is being kicked dont calculate a new path
|
||||||
if (roomUnit.isKicked)
|
if (roomUnit.isKicked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/// If habbo has control (im assuming admin, do something else, but we dont care about this part here)
|
||||||
if (roomUnit.getCacheable().get("control") != null) {
|
if (roomUnit.getCacheable().get("control") != null) {
|
||||||
habbo = (Habbo) roomUnit.getCacheable().get("control");
|
habbo = (Habbo) roomUnit.getCacheable().get("control");
|
||||||
|
|
||||||
@ -39,22 +47,34 @@ public class RoomUserWalkEvent extends MessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get room unit?
|
||||||
roomUnit = habbo.getRoomUnit();
|
roomUnit = habbo.getRoomUnit();
|
||||||
|
|
||||||
|
/// Get the room the habbo is in
|
||||||
Room room = habbo.getHabboInfo().getCurrentRoom();
|
Room room = habbo.getHabboInfo().getCurrentRoom();
|
||||||
|
|
||||||
try {
|
try
|
||||||
if (roomUnit != null && roomUnit.isInRoom() && roomUnit.canWalk()) {
|
{
|
||||||
if (!roomUnit.cmdTeleport) {
|
/// If our room unit is not nullptr and we are in a room and we can walk, then calculate a new path
|
||||||
|
if (roomUnit != null && roomUnit.isInRoom() && roomUnit.canWalk())
|
||||||
|
{
|
||||||
|
/// If we are not teleporting calcualte a new path
|
||||||
|
if (!roomUnit.cmdTeleport)
|
||||||
|
{
|
||||||
|
/// Don't calculate a new path if we are on a horse
|
||||||
if (habbo.getHabboInfo().getRiding() != null && habbo.getHabboInfo().getRiding().getTask() != null && habbo.getHabboInfo().getRiding().getTask().equals(PetTasks.JUMP))
|
if (habbo.getHabboInfo().getRiding() != null && habbo.getHabboInfo().getRiding().getTask() != null && habbo.getHabboInfo().getRiding().getTask().equals(PetTasks.JUMP))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/// Don't calulcate a new path if are already at the end position
|
||||||
if (x == roomUnit.getX() && y == roomUnit.getY())
|
if (x == roomUnit.getX() && y == roomUnit.getY())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (room == null || room.getLayout() == null)
|
if (room == null || room.getLayout() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (roomUnit.isIdle()) {
|
/// Reset idle status
|
||||||
|
if (roomUnit.isIdle())
|
||||||
|
{
|
||||||
UserIdleEvent event = new UserIdleEvent(habbo, UserIdleEvent.IdleReason.WALKED, false);
|
UserIdleEvent event = new UserIdleEvent(habbo, UserIdleEvent.IdleReason.WALKED, false);
|
||||||
Emulator.getPluginManager().fireEvent(event);
|
Emulator.getPluginManager().fireEvent(event);
|
||||||
|
|
||||||
@ -66,12 +86,15 @@ public class RoomUserWalkEvent extends MessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get room height map
|
||||||
RoomTile tile = room.getLayout().getTile((short) x, (short) y);
|
RoomTile tile = room.getLayout().getTile((short) x, (short) y);
|
||||||
|
|
||||||
|
/// this should never happen, if it does it would be a design flaw
|
||||||
if (tile == null) {
|
if (tile == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Don't care
|
||||||
if (habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY)) {
|
if (habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY)) {
|
||||||
if (room.getLayout().getTilesInFront(habbo.getRoomUnit().getCurrentLocation(), habbo.getRoomUnit().getBodyRotation().getValue(), 2).contains(tile))
|
if (room.getLayout().getTilesInFront(habbo.getRoomUnit().getCurrentLocation(), habbo.getRoomUnit().getBodyRotation().getValue(), 2).contains(tile))
|
||||||
return;
|
return;
|
||||||
@ -98,6 +121,8 @@ public class RoomUserWalkEvent extends MessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is where we set the end location and begin finding a path
|
||||||
if (tile.isWalkable() || room.canSitOrLayAt(tile.x, tile.y)) {
|
if (tile.isWalkable() || room.canSitOrLayAt(tile.x, tile.y)) {
|
||||||
roomUnit.setGoalLocation(tile);
|
roomUnit.setGoalLocation(tile);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user