src/org/matheusdev/ror/map/FringeLayer.java
public class FringeLayer {

	private class FringeTile implements Comparable<FringeTile> {
		TiledMapTileLayer.Cell cell;
		int x, y;
		float yoffset;

		FringeTile(TiledMapTileLayer.Cell cell, int x, int y, float yoffset) {
			this.cell = cell;
			this.x = x;
			this.y = y;
			this.yoffset = yoffset;
		}

		float height() {
			return y + yoffset;
		}

		@Override
		public int compareTo(FringeTile o) {
			if (o.height() > height()) {
				return 1;
			} else if (o.height() < height()) {
				return -1;
			} else {
				return 0;
			}
		}
	}

	private final TiledMap map;
	private final TiledMapTileLayer layer;
	private final List<FringeTile> tiles;

	private int currentInd;

	public FringeLayer(TiledMap map, TiledMapTileLayer fringeLayer) {
		this.map = map;
		this.layer = fringeLayer;
		this.tiles = new ArrayList<>();

		for (int x = 0; x < layer.getWidth(); x++) {
			for (int y = 0; y < layer.getHeight(); y++) {
				TiledMapTileLayer.Cell cell = layer.getCell(x, y);
				if (cell == null) continue;
				String yoffsetStr = cell.getTile().getProperties().get("yoffset", String.class);

				if (yoffsetStr == null || yoffsetStr.isEmpty()) {
					System.out.println("Warning - Fringe tile at [" + x + ", " + y + "] missing property <yoffset>");
				} else {
					try {
						tiles.add(new FringeTile(
								cell,
								x, y,
								Float.parseFloat(yoffsetStr)));
					} catch (NumberFormatException e) {
						System.err.println("Can't parse \"" + yoffsetStr + "\" as float: " + e);
					}
				}
			}
		}
		Collections.sort(tiles);
	}

	public void begin() {
		currentInd = 0;
	}

	public void renderTill(SpriteBatch batch, float y) {
		for (int i = currentInd; i < tiles.size(); i++) {
			FringeTile tile = tiles.get(i);
			currentInd = i;
			if (tile.height() < y) {
				return;
			}
			batch.draw(tile.cell.getTile().getTextureRegion(), tile.x, tile.y, 1f, 1f);
		}
		// Only if all tiles were drawn (see return; above)
		currentInd++;
	}

	public void end(SpriteBatch batch) {
		for (int i = currentInd; i < tiles.size(); i++) {
			FringeTile tile = tiles.get(i);
			batch.draw(tile.cell.getTile().getTextureRegion(), tile.x, tile.y, 1f, 1f);
		}
	}

}
src/org/matheusdev/ror/view/EntityViews.java
public final class EntityViews {

	private final Map<String, EntityViewFactory> factories = new HashMap<>();

	public EntityViews() {
		addFactory(ViewWalking.Factory.get());
	}

	public void addFactory(EntityViewFactory factory) {
		factories.put(factory.getName(), factory);
	}

	public EntityView createView(String name, ResourceLoader res, JsonObject conf) {
		EntityViewFactory factory = factories.get(name);
		if (factory == null) throw new UnkownViewException("Unkown view: " + name);

		return factory.make(res, conf);
	}

}
src/org/matheusdev/ror/EntityParser.java
public final class EntityParser {

	private EntityParser() {
	}

	private static JsonObject getJsonObject(JsonObject json, String name) {
		JsonObject jsonObject = null;
		if (json.elements.get(name) instanceof JsonObject) {
			jsonObject = (JsonObject) json.elements.get(name);
		} else {
			throw new MissingJSONContentException("Missing \"" + name + ": { ... }\" tag in entity");
		}
		return jsonObject;
	}

	private static JsonArray getJsonArray(JsonObject json, String name) {
		JsonArray jsonArray = null;
		if (json.elements.get(name) instanceof JsonArray) {
			jsonArray = (JsonArray) json.elements.get(name);
		} else {
			throw new MissingJSONContentException("Missing \"" + name + ": [ ... ]\" tag in entity");
		}
		return jsonArray;
	}

	public static EntityController createController(EntityControllers controllers, Entity e, JsonObject json) {
		JsonObject jsonControllerConf = getJsonObject(json, "controller-conf");

		return controllers.createController(json.values.get("controller"), e, jsonControllerConf);
	}

	public static EntityView createView(EntityViews views, ResourceLoader res, JsonObject json) {
		JsonObject jsonViewConf = getJsonObject(json, "view-conf");
		return views.createView(json.values.get("view"), res, jsonViewConf);
	}

	public static Entity createEntity(Physics physics, String type, JsonObject json, int id, int belongsTo) {
		JsonObject jsonBodyObject = getJsonObject(json, "body");
		JsonArray jsonFixturesList = getJsonArray(json, "fixtures");

		Body body = createBody(physics, jsonBodyObject);
		// Attach fixtures to body:
		parseFixtures(body, jsonFixturesList);

		return new Entity(body, type, id, belongsTo);
	}

	public static Body createBody(Physics physics, JsonObject bodyJson) {
		BodyDef def = new BodyDef();
		def.position.set(parseVector(bodyJson.values.get("position")));
		def.linearVelocity.set(parseVector(bodyJson.values.get("linearVelocity")));
		def.type = 				BodyType.valueOf(bodyJson.values.get("type"));
		def.angle = 			Float.parseFloat(bodyJson.values.get("angle"));
		def.angularVelocity = 	Float.parseFloat(bodyJson.values.get("angularVelocity"));
		def.linearDamping = 	Float.parseFloat(bodyJson.values.get("linearDamping"));
		def.angularDamping = 	Float.parseFloat(bodyJson.values.get("angularDamping"));
		def.allowSleep = 		Boolean.parseBoolean(bodyJson.values.get("allowSleep"));
		def.awake = 			Boolean.parseBoolean(bodyJson.values.get("awake"));
		def.fixedRotation = 	Boolean.parseBoolean(bodyJson.values.get("fixedRotation"));
		def.bullet = 			Boolean.parseBoolean(bodyJson.values.get("bullet"));
		def.active = 			Boolean.parseBoolean(bodyJson.values.get("active"));
		def.gravityScale = 		Float.parseFloat(bodyJson.values.get("gravityScale"));
		return physics.getWorld().createBody(def);
	}

	public static void parseFixtures(Body body, JsonArray fixtureArray) {
		for (JsonObject obj : fixtureArray.elements) {
			JsonElement shapeElem = obj.elements.get("shape");
			Shape shape = null;
			if (shapeElem instanceof JsonObject) {
				shape = parseShape((JsonObject) shapeElem);
			} else {
				throw new MissingJSONContentException("Missing \"shape: { ... }\" tag in fixture list of entity");
			}
			FixtureDef fixDef = new FixtureDef();
			fixDef.shape = shape;
			fixDef.friction = Float.parseFloat(obj.values.get("friction"));
			fixDef.restitution = Float.parseFloat(obj.values.get("restitution"));
			fixDef.density = Float.parseFloat(obj.values.get("density"));
			fixDef.isSensor = Boolean.parseBoolean(obj.values.get("isSensor"));
			body.createFixture(fixDef);
		}
	}

	public static Shape parseShape(JsonObject shapeDef) {
		Shape finalshape = null;
		switch (shapeDef.values.get("type")) {
		case "circle":
			CircleShape circleShape = new CircleShape();
			circleShape.setPosition(parseVector(shapeDef.values.get("position")));
			circleShape.setRadius(Float.parseFloat(shapeDef.values.get("radius")));
			finalshape = circleShape;
			break;
		case "rectangle":
		case "rect":
			PolygonShape rectShape = new PolygonShape();
			Vector2 pos = parseVector(shapeDef.values.get("position"));
			Vector2 size = parseVector(shapeDef.values.get("size"));
			rectShape.setAsBox(size.x, size.y);
			Vector2[] rectVertices = new Vector2[rectShape.getVertexCount()];
			for (int i = 0; i < rectShape.getVertexCount(); i++) {
				rectVertices[i] = new Vector2();
				rectShape.getVertex(i, rectVertices[i]);
				rectVertices[i].add(pos);
			}
			rectShape.set(rectVertices);
			finalshape = rectShape;
			break;
		case "polygon":
		case "poly":
			PolygonShape polyShape = new PolygonShape();
			if (!(shapeDef.elements.get("vertices") instanceof JsonArray))
				throw new MissingJSONContentException("Missing \"vertices: [ { v: ... }, ... ]\" array");
			JsonArray polyVertArray = (JsonArray) shapeDef.elements.get("vertices");
			Vector2[] polyVertices = new Vector2[polyVertArray.elements.size()];
			for (int i = 0; i < polyVertArray.elements.size(); i++) {
				JsonObject o = polyVertArray.elements.get(i);
				if (!o.values.containsKey("v"))
					throw new MissingJSONContentException("Need vertex data in Polygon definition: \"vertices: [ { v: \"0,0\" }, ... ]\"");
				polyVertices[i] = parseVector(o.values.get("v"));
			}
			polyShape.set(polyVertices);
			finalshape = polyShape;
			break;
		}
		return finalshape;
	}

	public static Vector2 parseVector(String str) {
		String[] dims = str.split(",");
		return new Vector2(Float.parseFloat(dims[0]), Float.parseFloat(dims[1]));
	}

}
src/org/matheusdev/ror/ResourceLoader.java
public class ResourceLoader implements Disposable {

	private boolean disposed;

	private final ObjectMap<String, TextureRegion> regions;
	private final ObjectMap<String, SpriteAnimation> anims;
	private final ObjectMap<String, Skin> skins;
	private final FileLocation fileLocation;

	public ResourceLoader(FileLocation fileLocation, FileHandle resourceXml) throws IOException {
		this.fileLocation = fileLocation;
		regions = new ObjectMap<>();
		anims = new ObjectMap<>();
		skins = new ObjectMap<>();

		Element resources = new XmlReader().parse(resourceXml);
		readResourcesTag(resources);
	}

	/// RUNTIME API:
	/// ===========

	public TextureRegion getRegion(String name) {
		return regions.get(name);
	}

	public SpriteAnimation getAnimation(String name) {
		// SpriteAnimation has a state. It !has! to be copied first:
		return new SpriteAnimation(anims.get(name));
	}

	public Skin getSkin(String name) {
		return skins.get(name);
	}

	public FileLocation getFileLocation() {
		return fileLocation;
	}

	/// RESOURCE LOADING:
	/// ================

	private void readResourcesTag(Element resources) throws RuntimeException {
		for (int i = 0; i < resources.getChildCount(); i++) {
			Element child = resources.getChild(i);

			switch (child.getName()) {
			case "images":
				readImagesTag(child);
				break;
			case "skins":
				readSkinsTag(child);
				break;
			default:
				throw new RuntimeException("Expected <images> or <skins> tag");
			}
		}
	}

	private void readImagesTag(Element images) throws RuntimeException {
		for (int i = 0; i < images.getChildCount(); i++) {
			Element child = images.getChild(i);

			switch (child.getName()) {
			case "image":
				readImageTag(child);
				break;
			default:
				throw new RuntimeException("Expected <image> tag");
			}
		}
	}

	private void readImageTag(Element image) throws RuntimeException {
		if (!image.getAttributes().containsKey("file"))
			throw new RuntimeException("need file=\"...\" attribute");

		Texture tex = new Texture(fileLocation.getFile(image.get("file")));

		for (int i = 0; i < image.getChildCount(); i++) {
			Element child = image.getChild(i);

			switch (child.getName()) {
			case "region":
				readRegionTag(tex, child);
				break;
			case "animation":
				readAnimationTag(tex, child);
				break;
			default:
				throw new RuntimeException("Expected <region> or <animation> tag");
			}
		}
	}

	private void readRegionTag(Texture tex, Element region) throws RuntimeException {
		if (!region.getAttributes().containsKey("name")
				|| !region.getAttributes().containsKey("bounds"))
			throw new RuntimeException("need name=\"...\" and bounds=\"...\" properties");
		regions.put(region.get("name"), XmlUtils.getTexReg(tex, region.get("bounds")));
	}

	private void readAnimationTag(Texture tex, Element anim) throws RuntimeException {
		if (!anim.getAttributes().containsKey("name"))
			throw new RuntimeException("need name=\"...\" property");
		anims.put(anim.get("name"), new SpriteAnimation(tex, anim));
	}

	private void readSkinsTag(Element resources) {
		for (int i = 0; i < resources.getChildCount(); i++) {
			Element child = resources.getChild(i);

			switch (child.getName()) {
			case "skin":
				readSkinTag(child);
				break;
			default:
				throw new RuntimeException("Expected <skin /> tag");
			}
		}
	}

	private void readSkinTag(Element skin) {
		if (!skin.getAttributes().containsKey("name")
				|| !skin.getAttributes().containsKey("file"))
			throw new RuntimeException("need name=\"...\" and file=\"...\" properties");
		skins.put(skin.get("name"), new Skin(fileLocation.getFile(skin.get("file"))));
	}

	@Override
	public void dispose() {
		if (!disposed) {
			disposed = true;
			for (Entry<String, TextureRegion> entry : regions.entries()) {
				entry.value.getTexture().dispose();
			}
			for (Entry<String, SpriteAnimation> entry : anims.entries()) {
				entry.value.dispose();
			}
			for (Entry<String, Skin> skin : skins.entries()) {
				skin.value.dispose();
			}
		}
	}

}
src/org/matheusdev/util/Config.java
public class Config {

	public static final String configfile = "keyconfig.json";

	public static Config instance;

	public static Config get() {
		if (instance == null) {
			try {
				instance = read();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return instance;
	}

	public OrderedMap<String, Integer> keys = new OrderedMap<>();
	{
		keys.put("up", Input.Keys.W);
		keys.put("down", Input.Keys.S);
		keys.put("left", Input.Keys.A);
		keys.put("right", Input.Keys.D);
		keys.put("debugDraw", Input.Keys.F8);
		keys.put("escape", Input.Keys.ESCAPE);
		keys.put("chat", Input.Keys.ENTER);
	}
	public int resolutionX = 800;
	public int resolutionY = 600;
	public boolean enableGamepad = true;
	public String gamepad = "...";
	public int gamepadX = 99;
	public int gamepadY = 100;
	public boolean bloom = true;
	public float baseintensity = 1f;
	public float basesaturation = .85f;
	public float bloomtreshold = 0.6f;//0.577f;
	public float bloomintensity = 2.0f;
	public float bloomsaturation = .85f;
	public float blurammount = 2f;

	private Config() {
		Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
			@Override
			public void run() {
				get().write();
				System.out.println("Config written.");
			}
		}));
	}

	public Config setRes(int resX, int resY) {
		resolutionX = resX;
		resolutionY = resY;
		return this;
	}

	public int key(String name) {
		Integer key = keys.get(name);
		if (key != null) return key;
		throw new InvalidConfigException("Missing key in configuration File (keyconfig.json): " + name);
	}

	public void key(String name, int value) {
		System.out.println("Putting key " + name + " = " + KeysUtil.forVal(value));
		keys.put(name, value);
	}

	public static Config read() throws IOException {
		System.out.println("Reading config.");
		File config = new File(configfile);

		if (config.exists()) {
			JsonDOM dom = new Json().fromJson(JsonDOM.class, new FileReader(config));

			if (dom != null) return new Config().fromJsonDOM(dom);
		}
		return new Config();
	}

	public void write() {
		FileWriter writer = null;
		try {
			Json json = new Json();
			json.setIgnoreUnknownFields(false);
			json.setUsePrototypes(false);
			json.setOutputType(OutputType.javascript);
			writer = new FileWriter(new File(configfile));
			writer.write(json.prettyPrint(toJsonDOM(), 100));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (writer != null) writer.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public Config fromJsonDOM(JsonDOM dom) {
		JsonDOM.JsonObject root = dom.getRoot();
		gamepad = root.getValue("gamepad", "...");

		gamepadX = root.getIntValue("gamepadX", 0);
		gamepadY = root.getIntValue("gamepadY", 1);

		enableGamepad = root.getBoolValue("enableGamepad", false);

		baseintensity = root.getFloatValue("baseintensity", 1f);
		basesaturation = root.getFloatValue("basesaturation", 0.85f);
		bloomintensity = root.getFloatValue("bloomintensity", 2f);
		bloomsaturation = root.getFloatValue("bloomsaturation", 0.85f);
		bloomtreshold = root.getFloatValue("bloomtreshold", 0.6f);
		blurammount = root.getFloatValue("blurammount", 2f);

		resolutionX = root.getIntValue("resolutionX", 800);
		resolutionY = root.getIntValue("resolutionY", 600);

		bloom = root.getBoolValue("bloom", true);

		if (root.elements.containsKey("keys")) {
			JsonDOM.JsonElement keysElem = root.elements.get("keys");

			if (keysElem != null && keysElem instanceof JsonDOM.JsonArray) {
				JsonDOM.JsonArray keyArray = (JsonDOM.JsonArray) keysElem;

				for (JsonDOM.JsonObject obj : keyArray.elements) {
					for (Entry<String, String> key : obj.values.entries()) {
						keys.put(key.key, KeysUtil.forName(key.value));
					}
				}
			}
		}
		return this;
	}

	public JsonDOM toJsonDOM() {
		JsonDOM dom = new JsonDOM();
		JsonDOM.JsonObject root = dom.getRoot();
		root.values.put("gamepad", gamepad);
		root.values.put("gamepadX", "" + gamepadX);
		root.values.put("gamepadY", "" + gamepadY);
		root.values.put("enableGamepad", "" + enableGamepad);
		root.values.put("baseintensity", "" + baseintensity);
		root.values.put("basesaturation", "" + basesaturation);
		root.values.put("bloomintensity", "" + bloomintensity);
		root.values.put("bloomsaturation", "" + bloomsaturation);
		root.values.put("bloomtreshold", "" + bloomtreshold);
		root.values.put("blurammount", "" + blurammount);
		root.values.put("resolutionX", "" + resolutionX);
		root.values.put("resolutionY", "" + resolutionY);
		root.values.put("bloom", "" + bloom);

		JsonDOM.JsonArray keyArray = new JsonDOM.JsonArray();
		for (Entry<String, Integer> entry : keys.entries()) {
			JsonDOM.JsonObject obj = new JsonDOM.JsonObject();
			obj.values.put(entry.key, KeysUtil.forVal(entry.value));
			System.out.println("Saving " + entry.key + " = " + KeysUtil.forVal(entry.value));
			keyArray.elements.add(obj);
		}
		root.elements.put("keys", keyArray);

		return dom;
	}

}
src/org/matheusdev/util/PingPongEq.java
public class PingPongEq<E> {

	private final E e0;
	private final E e1;

	private int recent;

	public PingPongEq(E e0, E e1) {
		this.e0 = e0;
		this.e1 = e1;
		this.recent = 0;
	}

	public void swap() {
		if (recent == 1) recent = 0;
		else recent = 1;
	}

	public E get() {
		return recent == 0 ? e0 : e1;
	}

	public boolean needUpdate() {
		return !e0.equals(e1);
	}

}
src/org/matheusdev/ror/Master.java
public class Master {

	private final ObjectMap<String, JsonObject> entityTypePool = new ObjectMap<>();
	private final String basePath;

	public Master(String entityBasePath) {
		this.basePath = entityBasePath;
	}

	protected JsonObject getEntityJson(String type) {
		JsonObject json = entityTypePool.get(type);
		if (json == null) {
			try {
				JsonDOM dom = (RuinsOfRevenge.fileLocation == FileLocation.CLASSPATH) ?
						new Json().fromJson(JsonDOM.class,
								Thread.currentThread().getContextClassLoader().getResourceAsStream(basePath + type + ".json"))
						:
						new Json().fromJson(JsonDOM.class, new FileHandle(new File(basePath + type + ".json")));
				json = dom.getRoot();
				entityTypePool.put(type, json);
			} catch (Exception ex) {
				System.err.println(new UnkownEntityTypeException("Couldn't load entity named \"" + type + "\" from " + basePath + type + ".json: " + ex));
				throw ex;
			}
		}
		return json;
	}

}
src/org/matheusdev/ror/view/EntityView.java
public abstract class EntityView {

	public abstract void draw(SpriteBatch batch, Entity e, float delta);

	public void draw(SpriteBatch batch, Entity e, Sprite sprite, float width, float xoffset, float yoffset) {
		Body body = e.getBody();
		// Super-Duper important Box2D-Magic code:
		// This should be / is in almost every Box2D project
		// It takes the Body and the associated sprite and
		// renders the sprite properly, using the body's
		// position, rotation and origin.
		final float worldToSprite = sprite.getWidth() / width;
		final float spriteToWorld = width / sprite.getWidth();
		// Get body position:
		final float bodyX = e.getX();
		final float bodyY = e.getY();
		// Get body center:
		final Vector2 center = body.getLocalCenter();
		final Vector2 massCenter = body.getMassData().center;
		center.sub(massCenter).add(xoffset, yoffset);
		// Compute sprite-space center:
		final Vector2 spriteCenter = new Vector2(sprite.getWidth()/2, sprite.getHeight()/2).sub((center.cpy().scl(worldToSprite)));
		// Upload to sprite:
		sprite.setScale(1f * spriteToWorld);
		sprite.setRotation(e.getRotation() * MathUtils.radiansToDegrees);
		sprite.setOrigin(spriteCenter.x, spriteCenter.y);
		sprite.setPosition(
				bodyX - spriteCenter.x,
				bodyY - spriteCenter.y);
		// Draw Sprite:
		sprite.draw(batch);
	}

}
src/org/matheusdev/ror/collision/Physics.java
public class Physics implements ContactListener, Disposable {

	protected final World world;
	public float timescale = 1f;

	public Physics(Vector2 gravity, boolean sleep) {
		world = new World(gravity, sleep);
		world.setContactListener(this);
	}

	public World getWorld() {
		return world;
	}

	public void step(float delta) {
		world.step(Math.min(delta, 0.02f) * timescale, 4, 4);
	}

	public void step() {
		step(Gdx.graphics.getDeltaTime());
	}

	@Override
	public void dispose() {
		world.dispose();
	}

	public Body createBox(BodyType type, float width, float height, float density) {
		BodyDef def = new BodyDef();
		def.type = type;
		Body body = world.createBody(def);

		PolygonShape shape = new PolygonShape();
		shape.setAsBox(width, height);
		body.createFixture(shape, density);
		shape.dispose();

		return body;
	}

	public Body createCircle(BodyType type, float radius, float density) {
		BodyDef def = new BodyDef();
		def.type = type;
		Body body = world.createBody(def);

		CircleShape shape = new CircleShape();
		shape.setRadius(radius);
		body.createFixture(shape, density);
		shape.dispose();
		MassData mass = new MassData();
		mass.mass = 1000f;
		body.setMassData(mass);

		return body;
	}

	public Body createEdge(BodyType type, float x0, float y0, float x1, float y1, float density) {
		BodyDef def = new BodyDef();
		def.type = type;
		Body body = world.createBody(def);

		EdgeShape shape = new EdgeShape();
		shape.set(new Vector2(0, 0), new Vector2(x1 - x0, y1 -y0));
		FixtureDef fdef = new FixtureDef();
		fdef.shape = shape;
		fdef.friction = 1;
		fdef.density = density;
		body.createFixture(fdef);
		body.setTransform(x0, y0, 0);
		shape.dispose();

		return body;
	}

	public Body createPolygon(BodyType type, float x, float y, Vector2[] vertices, float density) {
		BodyDef def = new BodyDef();
		def.type = type;
		Body body = world.createBody(def);

		PolygonShape shape = new PolygonShape();
		shape.set(vertices);
		FixtureDef fdef = new FixtureDef();
		fdef.shape = shape;
		fdef.friction = 1;
		fdef.density = density;
		body.createFixture(fdef);
		body.setTransform(x, y, 0f);
		shape.dispose();

		return body;
	}

	/* (non-Javadoc)
	 * @see com.badlogic.gdx.physics.box2d.ContactListener#beginContact(com.badlogic.gdx.physics.box2d.Contact)
	 */
	@Override
	public void beginContact(Contact c) {
	}

	/* (non-Javadoc)
	 * @see com.badlogic.gdx.physics.box2d.ContactListener#endContact(com.badlogic.gdx.physics.box2d.Contact)
	 */
	@Override
	public void endContact(Contact c) {
	}

	/* (non-Javadoc)
	 * @see com.badlogic.gdx.physics.box2d.ContactListener#postSolve(com.badlogic.gdx.physics.box2d.Contact, com.badlogic.gdx.physics.box2d.ContactImpulse)
	 */
	@Override
	public void postSolve(Contact c, ContactImpulse ci) {
	}

	/* (non-Javadoc)
	 * @see com.badlogic.gdx.physics.box2d.ContactListener#preSolve(com.badlogic.gdx.physics.box2d.Contact, com.badlogic.gdx.physics.box2d.Manifold)
	 */
	@Override
	public void preSolve(Contact c, Manifold m) {
		Fixture fixtureA = c.getFixtureA();
		Fixture fixtureB = c.getFixtureB();

		handleFixture(fixtureA, fixtureB, c, m);
		handleFixture(fixtureB, fixtureA, c, m);
	}

	public void handleFixture(Fixture fixture, Fixture other, Contact c, Manifold m) {
		Object obj = fixture.getUserData();
		if (obj instanceof Collidable) {
			((Collidable) obj).collide(other, c, m);
		}
	}

}
src/org/matheusdev/ror/controller/ControllerPlayer.java
public class ControllerPlayer extends EntityController {
	private static final long serialVersionUID = 8212372970195205197L;

	public static final class Factory implements EntityControllerFactory {
		private static Factory instance = new Factory();
		private Factory() {
		}
		public static Factory get() {
			return instance;
		}

		@Override
		public String getName() {
			return "ControllerPlayer";
		}
		@Override
		public EntityController make(Entity entity, JsonObject config) {
			return new ControllerPlayer(entity, config);
		}
	}

	private final ComponentMovement movement = new ComponentMovement(Dir.DOWN);
	private final ComponentNetwork network = new ComponentNetwork();
	private final float strength;
	private final float maxspeed;
	private final float friction;

	public ControllerPlayer(Entity entity, JsonObject config) {
		super(entity);
		strength = Float.parseFloat(config.values.get("strength"));
		maxspeed = Float.parseFloat(config.values.get("maxspeed"));
		friction = Float.parseFloat(config.values.get("friction"));
	}

	@Override
	public void run() throws SuspendExecution {
		System.out.println("ControllerPlayer initializing: " + entity);
		movement.set(strength, maxspeed, friction);
		while (living) {
			long time = VirtualThread.currentThread().getProcessor().getCurrentTime();

			if (state != null) {
				network.setRemoteState(state);
				network.apply(entity);
			}

			if (input != null) {
				movement.setSteer(input.steerx, input.steery);
				movement.apply(entity);
			}

			state = null;

			VirtualThread.wakeupAt(time + 16);
		}
		System.out.println("ControllerPlayer dying");
	}

	public ComponentMovement getMovementComponent() {
		return movement;
	}

}
src/org/matheusdev/util/JsonDOM.java
public static class JsonObject extends JsonElement {
	public OrderedMap<String, JsonElement> elements = new OrderedMap<>();
	public OrderedMap<String, String> values = new OrderedMap<>();

	@Override
	public void toString(StringBuffer buffer) {
		buffer.append("{\n");
		for (Entry<String, String> entry : values.entries()) {
			buffer.append(entry.key).append(": ").append(entry.value).append('\n');
		}
		for (Entry<String, JsonElement> entry : elements.entries()) {
			buffer.append(entry.key).append(": ");
			entry.value.toString(buffer);
		}
		buffer.append("}\n");
	}

	public boolean valuesContainAllKeys(String... keys) {
		for (String key : keys) {
			if (!values.containsKey(key))
				return false;
		}
		return true;
	}

	public String getValue(String value, String defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : str;
	}

	public float getFloatValue(String value, float defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : (float) Double.parseDouble(str);
	}

	public double getDoubleValue(String value, double defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : Double.parseDouble(str);
	}

	public int getIntValue(String value, int defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : (int) Double.parseDouble(str);
	}

	public long getLongValue(String value, long defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : (long) Double.parseDouble(str);
	}

	public boolean getBoolValue(String value, boolean defaultValue) {
		String str = values.get(value);
		return str == null ? defaultValue : str.equalsIgnoreCase("true");
	}
}
src/org/matheusdev/ror/controller/EntityControllers.java
public class EntityControllers {

	private final VirtualProcessor proc;
	private final List<EntityController> controllers = new ArrayList<>();
	private final Map<String, EntityControllerFactory> factories = new HashMap<>();

	private long stateTime;

	public EntityControllers() {
		proc = new VirtualProcessor();
		addFactory(ControllerPlayer.Factory.get());
	}

	public void addFactory(EntityControllerFactory factory) {
		factories.put(factory.getName(), factory);
	}

	public void tick(long msTime) {
		stateTime += msTime;
		proc.tick(stateTime);
	}

	public void removeFrom(Entity e) {
		for (int i = 0; i < controllers.size(); i++) {
			if (controllers.get(i).getEntity() == e) {
				controllers.remove(i--);
			}
		}
	}

	public EntityController createController(String name, Entity e, JsonObject conf) {
		EntityControllerFactory factory = factories.get(name);
		if (factory == null) throw new UnkownControllerException("Unkown controller: " + name);

		EntityController contr = factory.make(e, conf);
		controllers.add(contr);
		new VirtualThread(contr).start(proc);
		return contr;
	}

}
src/org/matheusdev/ror/controller/EntityController.java
public abstract class EntityController implements VirtualRunnable {
	private static final long serialVersionUID = -1834760944554078514L;

	protected final Entity entity;
	protected Input input;
	protected EntityState state;
	protected boolean living = true;

	public EntityController(Entity entity) {
		this.entity = entity;
	}

	public void setInput(Input in) {
		this.input = in;
	}

	public void setEntityState(EntityState state) {
		this.state = state;
	}

	public void kill() {
		living = false;
	}

	public Entity getEntity() {
		return entity;
	}

}
src/org/matheusdev/ror/model/entity/Entity.java
public class Entity implements Comparable<Entity> {

	protected final Body body;
	protected final int id;
	protected final int belongsTo;
	protected final String type;

	public Entity(Body body, String type, int id, int belongsTo) {
		this.body = body;
		this.type = type;
		this.id = id;
		this.belongsTo = belongsTo;
	}

	public Body getBody() {
		return body;
	}

	public Vector2 getPos() {
		return body.getPosition();
	}

	public float getX() {
		return body.getPosition().x;
	}

	public float getY() {
		return body.getPosition().y;
	}

	public float getRotation() {
		return body.getAngle();
	}

	public String getType() {
		return type;
	}

	public int getID() {
		return id;
	}

	public int getBelongsTo() {
		return belongsTo;
	}

	@Override
	public int compareTo(Entity that) {
		// reverse sorting:
		return (int) (that.getY() * 1000f - this.getY() * 1000f);
	}

	public String toString() {
		return String.format(
				"[Entity]:\n" +
				"\ttype: %s\n" +
				"\tid: %d\n" +
				"\tconnection: %d" +
				"\tpos: %s\n" +
				"\trot: %G\n" +
				"\tvel: %s\n" +
				"\trot-vel: %G",
				type, id, belongsTo,
				getPos().toString(),
				getRotation(),
				getBody().getLinearVelocity().toString(),
				getBody().getAngularVelocity()
		);
	}
}


Question: import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.Controllers;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.ObjectMap;
import org.matheusdev.ror.EntityParser;
import org.matheusdev.ror.Master;
import org.matheusdev.ror.ResourceLoader;
import org.matheusdev.ror.collision.Physics;
import org.matheusdev.ror.controller.ControllerPlayer;
import org.matheusdev.ror.controller.EntityController;
import org.matheusdev.ror.controller.EntityControllers;
import org.matheusdev.ror.map.FringeLayer;
import org.matheusdev.ror.model.entity.Entity;
import org.matheusdev.ror.net.packages.*;
import org.matheusdev.ror.view.EntityView;
import org.matheusdev.ror.view.EntityViews;
import org.matheusdev.util.Config;
import org.matheusdev.util.JsonDOM.JsonObject;
import org.matheusdev.util.PingPongEq;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
 * Copyright (c) 2013 matheusdev
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.matheusdev.ror.client;



/**
 * @author matheusdev
 *
 */
public class ClientMaster extends Master {

	private boolean disposed;

	private final EntityControllers controllers = new EntityControllers();
	private final EntityViews views = new EntityViews();
	private final List<ClientEntity> entities = new ArrayList<>();
	private final ObjectMap<Integer, ClientEntity> entitiesById = new ObjectMap<>();

	private final ResourceLoader res;
Answer: 	private final Physics physics;