Package games.stendhal.server.script

Source Code of games.stendhal.server.script.ZoneCollisionCheck

/* $Id: ZoneCollisionCheck.java,v 1.6 2010/09/19 02:36:26 nhnb Exp $ */
/***************************************************************************
*                   (C) Copyright 2003-2010 - Stendhal                    *
***************************************************************************
***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/
package games.stendhal.server.script;

import java.util.LinkedList;
import java.util.List;

import marauroa.common.game.IRPZone;

import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.core.engine.StendhalRPWorld;
import games.stendhal.server.core.engine.StendhalRPZone;
import games.stendhal.server.core.scripting.ScriptImpl;
import games.stendhal.server.entity.Entity;
import games.stendhal.server.entity.player.Player;

/**
* Searches for inconsistencies in zone collisions. For every square
* that there is an open way out, should be also an open square in
* the neighbouring zone.
* <p>
* No attention paid to performance. There should be no reason to run
* this on anything but a test server.
*/
public class ZoneCollisionCheck extends ScriptImpl {
  private static enum Border {
    NORTH {
      @Override
      public Border opposite() {
        return SOUTH;
      }
    },
    EAST {
      @Override
      public Border opposite() {
        return WEST;
      }
    },
    SOUTH {
      @Override
      public Border opposite() {
        return NORTH;
      }
    },
    WEST {
      @Override
      public Border opposite() {
        return EAST;
      }
    };
   
   
    public abstract Border opposite();
  }
 
  private Entity entity;
  private Player admin;
  private int badnessThreshold = 1;
 
  @Override
  public void execute(final Player admin, final List<String> args) {
    StendhalRPWorld world = SingletonRepository.getRPWorld();
    this.admin = admin;
   
    entity = new Entity() {
      // anon subclass to allow instantiation.
    };
   
    if (args.size() > 1) {
      usage();
      return;
    } else if (args.size() == 1) {
      String arg = args.get(0);
      try {
        badnessThreshold = Integer.parseInt(arg);
      } catch (NumberFormatException e) {
        admin.sendPrivateText("Invalid number: " + arg);
        usage();
        return;
      }
    }
   
    for (IRPZone izone : world) {
      StendhalRPZone zone = (StendhalRPZone) izone;
      checkZone(zone);
    }
  }
 
  private void usage() {
    admin.sendPrivateText("Usage: /script ZoneCollisionCheck.class [badness]\n\tBadness parameter is the minimum number of failing checks next to each other");
  }
 
  private void checkZone(StendhalRPZone zone) {
    for (Border border : Border.values()) {
      report(checkBorder(zone, border));
    }
  }
 
  /**
   * Check a border
   * @param zone the to check
   * @param border the border to check
   * @return list of the found problems
   */
  private List<String> checkBorder(StendhalRPZone zone, Border border) {
    LinkedList<String> problems = new LinkedList<String>();
   
    // the coordinates to check in zone
    int zoneX = 0;
    int zoneY = 0;
   
    // walking direction
    int dx = 0;
    int dy = 0;
   
    // for finding the neighbour
    int tmpx = zone.getX();
    int tmpy = zone.getY();
    switch (border) {
    case NORTH:
      tmpy--;
      dx = 1;
      break;
    case EAST:
      tmpx += zone.getWidth();
      zoneX = zone.getWidth() - 1;
      dy = 1;
      break;
    case SOUTH:
      tmpy += zone.getHeight();
      zoneY = zone.getHeight() - 1;
      dx = 1;
      break;
    case WEST:
      dy = 1;
      tmpx--;
    }
   
    final StendhalRPZone neighbour = SingletonRepository.getRPWorld().getZoneAt(
        zone.getLevel(), tmpx, tmpy, entity);
    if (neighbour != null) {
      // find the starting coordinates for neighbour
      int neighbourX = 0;
      int neighbourY = 0;
     
      switch (border.opposite()) {
      case NORTH:
        neighbourX = zone.getX() - neighbour.getX();
        neighbourY = 0;
        break;
      case EAST:
        neighbourX = neighbour.getWidth() - 1;
        neighbourY = zone.getY() - neighbour.getY();
        break;
      case SOUTH:
        neighbourX = zone.getX() - neighbour.getX();
        neighbourY = neighbour.getHeight() - 1;
        break;
      case WEST:
        neighbourX = 0;
        neighbourY = zone.getY() - neighbour.getY();
      }
 
      // Walk through the border and check do the collisions match
      int badness = 0;
      while ((zoneX < zone.getWidth()) && (zoneY < zone.getHeight())) {
        if ((neighbourX < 0) || (neighbourY < 0)) {
          // haven't yet reached the point where to start checking
          continue;
        }
        if ((neighbourX >= neighbour.getWidth()) || (neighbourY >= neighbour.getHeight())) {
          // done checking all of the border
          break;
        }
       
        boolean zCollides = zone.collides(zoneX, zoneY);
        boolean nCollides = neighbour.collides(neighbourX, neighbourY);
       
        if (zCollides != nCollides) {
          badness++;
          if (badness >= badnessThreshold) {
            problems.add(collidesMessage(zone.getName(), zoneX, zoneY, zCollides)
                + " but " +
                collidesMessage(neighbour.getName(), neighbourX, neighbourY, nCollides));
          }
        } else {
          badness = 0;
        }
       
        zoneX += dx;
        zoneY += dy;
        neighbourX += dx;
        neighbourY += dy;
      }
    }
   
    return problems;
  }
 
  private String collidesMessage(String zone, int x, int y, boolean collides) {
    if (collides) {
      return zone + " has collision at [" + x + "," + y + "]";
    } else {
      return zone + " does not have collision at [" + x + "," + y + "]";
    }
  }
 
  /**
   * Send a problem report to the admin.
   *
   * @param problems the problems to include in this report
   */
  private void report(List<String> problems) {
    if (!problems.isEmpty()) {
      StringBuilder msg = new StringBuilder();
      for (String problem : problems) {
        msg.append(problem);
        msg.append("\n");
      }
     
      admin.sendPrivateText(msg.toString());
    }
  }
}
TOP

Related Classes of games.stendhal.server.script.ZoneCollisionCheck

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.