/* * Copyright 2016 Nathan Howard * * This file is part of OpenGrave * * OpenGrave 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 3 of the License, or * (at your option) any later version. * * OpenGrave is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenGrave. If not, see <http://www.gnu.org/licenses/>. */ package com.opengrave.og.terrain; import java.io.*; import java.util.ArrayList; import com.opengrave.common.*; import com.opengrave.common.world.CommonAreaLoc; import com.opengrave.og.Util; import com.opengrave.og.base.Wall; import com.opengrave.og.engine.Location; import com.opengrave.og.engine.Node; import com.opengrave.og.light.Shadow; import com.opengrave.og.resources.RenderStyle; import com.opengrave.og.util.Matrix4f; import com.opengrave.og.util.Vector3f; public class TerrainArea extends Node implements ThreadedLoading { private TerrainWorld world; private CommonAreaLoc locationInWorld; private ArrayList<Wall> wallList = new ArrayList<Wall>(); private ArrayList<TerrainLayerNode> layers = new ArrayList<TerrainLayerNode>(); private ArrayList<TerrainLiquidLayerNode> liquidLayer = new ArrayList<TerrainLiquidLayerNode>(); private Matrix4f renderOffset = new Matrix4f(); // private Location location = new Location(); private boolean loaded = false; public TerrainArea(TerrainWorld terrainWorld, CommonAreaLoc tac) { this.world = terrainWorld; world.addChild(this); this.locationInWorld = tac; renderOffset.translate(new Vector3f((float) (tac.getX() * (TerrainLayer.size - 1)), (float) (tac.getY() * (TerrainLayer.size - 1)), 0f), renderOffset); LoadingThread.addLoadable(this); } @Override public void doRenderShadows(Matrix4f matrix, Shadow shadow) { } @Override public void doRenderForPicking(Matrix4f matrix) { } @Override public void doRender(Matrix4f matrix) { } @Override public void doRenderSemiTransparent(Matrix4f matrix) { } @Override public void doUpdate(float delta) { } public void save() { String name = locationInWorld.getX() + ":" + locationInWorld.getY() + ".area"; File f = new File(world.getDirectory(), name); System.out.println("Saving area : " + f); if (!f.isDirectory()) { File parent = f.getParentFile(); if (!parent.isDirectory()) { parent.mkdirs(); } synchronized (world) { try (OGOutputStream stream = new OGOutputStream(new FileOutputStream(f, false))) { synchronized (layers) { stream.writeInt(layers.size()); for (TerrainLayerNode layer : layers) { layer.save(stream); } } stream.writeInt(0); // Keep binary compatibility with older worlds synchronized (wallList) { stream.writeInt(wallList.size()); for (Wall wall : wallList) { wall.save(stream); } } synchronized (liquidLayer) { stream.writeInt(liquidLayer.size()); for (TerrainLiquidLayerNode tll : liquidLayer) { tll.save(stream); } } } catch (FileNotFoundException e) { new DebugExceptionHandler(e); } catch (IOException e) { new DebugExceptionHandler(e); } } } } public void load() { } /* * public TerrainEditableVertex getVertexAt(int inmapx, int inmapy, int layer, boolean ignoreEdge) { * synchronized (world) { * synchronized (layers) { * if (layers.size() <= layer) { return null; } * TerrainLayerNode tl = layers.get(layer); * return tl.layer.getVertexAt(inmapx, inmapy, ignoreEdge); * } * } * } */ /* * public TerrainLiquidEditableVertex getLiquidVertexAt(int inmapx, int inmapy, int layer, boolean ignoreEdge) { * synchronized (world) { * synchronized (liquidLayer) { * if (liquidLayer.size() <= layer) { return null; } * * TerrainLiquidLayerNode tll = liquidLayer.get(layer); * return tll.layer.getVertexAt(inmapx, inmapy, ignoreEdge); * } * } * } */ public Location relativeLocationOf(Location l) { Location l2 = new Location(); l2.setLocation(l.getTileX() - (locationInWorld.getX() * 64l), l.getMinorX(), l.getTileY() - (locationInWorld.getY() * 64l), l.getMinorY()); l2.setLayer(l.getLayer()); return l2; } public void addWall(Wall wall) { synchronized (world) { synchronized (wallList) { wallList.add(wall); addChild(wall); } } } public void setAllObjectsRenderStyle(RenderStyle renderStyle) { synchronized (world) { // synchronized (objectList) { // for (BaseObject obj : objectList) { // obj.setRenderStyle(renderStyle); // } // } synchronized (wallList) { for (Wall wall : wallList) { wall.setRenderStyle(renderStyle); } } synchronized (layers) { for (TerrainLayerNode layer : layers) { layer.layer.setRenderStyle(renderStyle); } } synchronized (liquidLayer) { for (TerrainLiquidLayerNode layer : liquidLayer) { layer.layer.setRenderStyle(renderStyle); } } } } public boolean ownsLayer(TerrainLayer layer) { synchronized (world) { if (layer == null) { return false; } synchronized (layers) { for (TerrainLayerNode layer2 : layers) { if (layer2.layer.equals(layer)) { return true; } } } } return false; } public boolean ownsLayer(TerrainLiquidLayer layer) { synchronized (world) { if (layer == null) { return false; } synchronized (liquidLayer) { for (TerrainLiquidLayerNode layer2 : liquidLayer) { if (layer2.layer.equals(layer)) { return true; } } } } return false; } public int getLayerCount() { synchronized (world) { synchronized (layers) { return layers.size(); } } } public int getLiquidCount() { synchronized (world) { synchronized (liquidLayer) { return liquidLayer.size(); } } } public void addLayer(boolean fill) { synchronized (world) { synchronized (layers) { int i = layers.size(); TerrainLayerNode tl = new TerrainLayerNode(new TerrainLayer(world, locationInWorld, getLayerCount(), null), i); layers.add(tl); addChild(tl); if (!fill) { tl.layer.setAllTextures(-1); } } } } public void addLiquid(boolean fill) { synchronized (world) { synchronized (liquidLayer) { TerrainLiquidLayerNode tll = new TerrainLiquidLayerNode(new TerrainLiquidLayer(world, locationInWorld, getLiquidCount(), null)); liquidLayer.add(tll); addChild(tll); if (!fill) { tll.layer.setAllTextures(-1); } } } } public TerrainLayerNode getLayer(int editingLayer) { synchronized (layers) { if (editingLayer >= layers.size()) { return null; } return layers.get(editingLayer); } } public TerrainLiquidLayerNode getLiquid(int leditingLayer) { synchronized (world) { synchronized (liquidLayer) { if (leditingLayer >= liquidLayer.size()) { addLiquid(false); } return liquidLayer.get(leditingLayer); } } } /* * public boolean ownsObject(BaseObject object) { * synchronized (objectList) { * for (BaseObject obj : objectList) { * if (obj.equals(object)) { return true; } * } * } * return false; * } */ public Location getLocation() { Location l = new Location(); l.setLocation(locationInWorld.getX() * 63, 0, locationInWorld.getY() * 63, 0); return l; } /* * public void getObjectsByIdentifier(ArrayList<BaseObject> objList, String ident) { * synchronized (objectList) { * for (BaseObject obj : objectList) { * if (obj.getIdentifier().equals(ident)) { * objList.add(obj); * } * } * } * * } */ /** * * @param loc * Location in relative proportions. * @return */ public float getHeightAt(Location loc) { synchronized (world) { synchronized (layers) { if (layers.size() <= loc.getLayer()) { return 0f; } TerrainLayerNode layer = layers.get(loc.getLayer()); return layer.layer.getHeightAt(loc); } } } @Override public Matrix4f getMatrix() { return Util.createMatrixFor(getLocation(), null, null, null); } public CommonAreaLoc getAreaLoc() { return locationInWorld; } public void alter(int x, int y, int layer, TerrainLayerAlteration alter) { if (x < 0 || x >= TerrainLayer.size || y < 0 || y >= TerrainLayer.size) { throw new RuntimeException("Cannot be <0 or >63... x:" + x + " y:" + y); } synchronized (world) { synchronized (layers) { if (layer < layers.size()) { TerrainLayerNode layerN = layers.get(layer); layerN.layer.alter(x, y, alter); } } } } public void alter(int x, int y, int layer, TerrainLiquidLayerAlteration alter) { if (x < 0 || x >= TerrainLayer.size || y < 0 || y >= TerrainLayer.size) { throw new RuntimeException("Cannot be <0 or >63... x:" + x + " y:" + y); } synchronized (world) { synchronized (liquidLayer) { if (layer < liquidLayer.size()) { TerrainLiquidLayerNode layerN = liquidLayer.get(layer); layerN.layer.alter(x, y, alter); } } } } public void forceLiquidEdges(ArrayList<TerrainArea> connected) { for (TerrainArea area : connected) { CommonAreaLoc otherLoc = area.getAreaLoc(); int offx = otherLoc.getX() - locationInWorld.getX(); int offy = otherLoc.getY() - locationInWorld.getY(); synchronized (liquidLayer) { for (int i = 0; i < liquidLayer.size(); i++) { if (area.getLiquidCount() <= i) { break; } TerrainLiquidLayer thisLayer = liquidLayer.get(i).layer; TerrainLiquidLayer thatLayer = area.getLiquid(i).layer; // Both layers have a matching liquid X layer if (offx == 1 && offy == 0) { // Directly to the right - take whole left edge as right for (int c = 0; c < 64; c++) { if (thisLayer.getTextureAt(63, c) != -1 && thatLayer.getTextureAt(0, c) != -1) { thisLayer.setLastLiquidFlow(64, c + 1, thatLayer.getCurrentFlowXAt(0, c), thatLayer.getCurrentFlowYAt(0, c)); } } } if (offx == 0 && offy == 1) { // Directly below - take whole top edge as bottom for (int c = 0; c < 64; c++) { if (thatLayer.getTextureAt(c, 0) != -1 && thisLayer.getTextureAt(c, 63) != -1) { thisLayer.setLastLiquidFlow(c + 1, 64, thatLayer.getCurrentFlowXAt(c, 0), thatLayer.getCurrentFlowYAt(c, 0)); } } } if (offx == 1 && offy == 1) { // Take bottom right as top left thisLayer.setLastLiquidFlow(64, 64, thatLayer.getCurrentFlowXAt(0, 0), thatLayer.getCurrentFlowYAt(0, 0)); } } } } } @Override public void loadInThisThread() { // if (loaded) { return; } String name = locationInWorld.getX() + ":" + locationInWorld.getY() + ".area"; File f = new File(world.getDirectory(), name); ArrayList<TerrainLayerNode> layers = new ArrayList<TerrainLayerNode>(); ArrayList<Wall> walls = new ArrayList<Wall>(); ArrayList<TerrainLiquidLayerNode> liquids = new ArrayList<TerrainLiquidLayerNode>(); if (f.isFile()) { System.out.println("Reading area file : " + f); try (OGInputStream reader = new OGInputStream(new FileInputStream(f))) { int layerCount, wallCount, liquidCount; layerCount = reader.readInt(); for (int i = 0; i < layerCount; i++) { TerrainLayerNode layer = new TerrainLayerNode(new TerrainLayer(world, locationInWorld, i, reader), i); layers.add(layer); addChild(layer); } reader.readInt(); // Throw away an int for object count. No longer stored here wallCount = reader.readInt(); for (int i = 0; i < wallCount; i++) { Wall wall = Wall.createWall(reader); walls.add(wall); addChild(wall); } liquidCount = reader.readInt(); for (int i = 0; i < liquidCount; i++) { TerrainLiquidLayerNode layer = new TerrainLiquidLayerNode(new TerrainLiquidLayer(world, locationInWorld, i, reader)); liquids.add(layer); addChild(layer); } } catch (FileNotFoundException e) { new DebugExceptionHandler(e, name); } catch (IOException e) { new DebugExceptionHandler(e, name); } } else { System.out.println("Could not load area file : " + f); } if (layers.size() == 0) { TerrainLayerNode layer = new TerrainLayerNode(new TerrainLayer(world, locationInWorld, 0, null), 0); layers.add(layer); addChild(layer); } this.layers = layers; this.liquidLayer = liquids; this.wallList = walls; loaded = true; } @Override public boolean isLoaded() { return loaded; } @Override public void setLoaded(boolean b) { loaded = b; } }