This commit is contained in:
Anuken 2020-01-20 16:14:29 -05:00
parent be0b13e27d
commit df1a102021
12 changed files with 208 additions and 150 deletions

View File

@ -249,7 +249,9 @@ public class Control implements ApplicationListener, Loadable{
});
}
public void playZone(Zone zone){
//TODO remove, make it viable on a server
/*public void playZone(Zone zone){
ui.loadAnd(() -> {
logic.reset();
net.reset();
@ -267,6 +269,16 @@ public class Control implements ApplicationListener, Loadable{
logic.play();
Events.fire(Trigger.newGame);
});
}*/
public void playSector(Sector sector){
ui.loadAnd(() -> {
logic.reset();
world.loadSector(sector);
state.set(State.playing);
logic.play();
ui.planet.hide();
});
}
public void playTutorial(){

View File

@ -1,11 +1,13 @@
package mindustry.core;
import arc.*;
import arc.func.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
@ -14,7 +16,6 @@ import mindustry.io.*;
import mindustry.maps.*;
import mindustry.maps.filters.*;
import mindustry.maps.filters.GenerateFilter.*;
import mindustry.maps.generators.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
@ -184,15 +185,32 @@ public class World{
return state.rules.zone;
}
public void loadGenerator(Generator generator){
public void loadGenerator(int width, int height, Cons<Tiles> generator){
beginMapLoad();
resize(generator.width, generator.height);
generator.generate(tiles);
resize(width, height);
generator.get(tiles);
endMapLoad();
}
public void loadSector(Sector sector){
int size = (int)(sector.rect.radius * 2500);
loadGenerator(size, size, tiles -> {
TileGen gen = new TileGen();
tiles.each((x, y) -> {
gen.reset();
Vec3 position = sector.rect.project(x / (float)size, y / (float)size);
sector.planet.generator.generate(position, gen);
tiles.set(x, y, new Tile(x, y, gen.floor, gen.overlay, gen.block));
});
tiles.get(size/2, size/2).setBlock(Blocks.coreShard, Team.sharded);
});
}
public void loadMap(Map map){
loadMap(map, new Rules());
}

View File

@ -4,7 +4,10 @@ import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
//TODO clean this up somehow
public class PlanetGrid{
private static final PlanetGrid[] cache = new PlanetGrid[10];
private static final float x = -0.525731112119133606f;
private static final float z = -0.850650808352039932f;
@ -20,12 +23,10 @@ public class PlanetGrid{
{5, 3, 10, 1, 4}, {2, 5, 4, 0, 11}, {3, 7, 6, 1, 8}, {7, 2, 9, 0, 6}
};
private static PlanetGrid[] cache = new PlanetGrid[10];
int size;
Ptile[] tiles;
Corner[] corners;
Edge[] edges;
public final int size;
public final Ptile[] tiles;
public final Corner[] corners;
public final Edge[] edges;
PlanetGrid(int size){
this.size = size;
@ -46,7 +47,7 @@ public class PlanetGrid{
}
}
static PlanetGrid newGrid(int size){
public static PlanetGrid newGrid(int size){
//cache grids between calls, since only ~5 different grids total are needed
if(size < cache.length && cache[size] != null){
return cache[size];
@ -104,8 +105,7 @@ public class PlanetGrid{
for(Ptile t : grid.tiles){
for(int k = 0; k < 5; k++){
if(t.edges[k] == null){
addEdge(nextEdge, grid, t.id, iTilesP[t.id][k]);
nextEdge++;
addEdge(nextEdge++, grid, t.id, iTilesP[t.id][k]);
}
}
}
@ -220,13 +220,15 @@ public class PlanetGrid{
return 30 * Mathf.pow(3, size);
}
static class Ptile{
int id;
int edgeCount;
Vec3 v = new Vec3();
Ptile[] tiles;
Corner[] corners;
Edge[] edges;
public static class Ptile{
public final int id;
public final int edgeCount;
public final Ptile[] tiles;
public final Corner[] corners;
public final Edge[] edges;
public Vec3 v = new Vec3();
public Ptile(int id, int edgeCount){
this.id = id;
@ -238,23 +240,24 @@ public class PlanetGrid{
}
}
static class Corner{
int id;
Ptile[] tiles = new Ptile[3];
Corner[] corners = new Corner[3];
Edge[] edges = new Edge[3];
Vec3 v = new Vec3();
Vec3 bv = new Vec3();
public static class Corner{
public final int id;
public final Ptile[] tiles = new Ptile[3];
public final Corner[] corners = new Corner[3];
public final Edge[] edges = new Edge[3];
public Vec3 v = new Vec3();
public Vec3 bv = new Vec3();
public Corner(int id){
this.id = id;
}
}
static class Edge{
int id;
Ptile[] tiles = new Ptile[2];
Corner[] corners = new Corner[2];
public static class Edge{
public final int id;
public final Ptile[] tiles = new Ptile[2];
public final Corner[] corners = new Corner[2];
public Edge(int id){
this.id = id;

View File

@ -3,7 +3,6 @@ package mindustry.graphics;
import arc.graphics.*;
import arc.graphics.VertexAttributes.*;
import arc.graphics.gl.*;
import arc.graphics.g3d.*;
import arc.math.geom.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
@ -12,11 +11,10 @@ import mindustry.maps.planet.*;
public class PlanetMesh{
private float[] floats = new float[3 + 3 + 1];
private Vec3 center = new Vec3(0, 0, 0);
private Vec3 vec = new Vec3();
private Plane plane = new Plane();
private Mesh mesh;
private PlanetGrid grid;
private Vec3 center = new Vec3();
private boolean lines;
private float radius, intensity = 0.2f;
@ -46,6 +44,13 @@ public class PlanetMesh{
generateMesh();
}
/** @return the sector that is hit by this ray, or null if nothing intersects it. */
public @Nullable Ptile getTile(Ray ray){
boolean found = Intersector3D.intersectRaySphere(ray, center, radius, Tmp.v33);
if(!found) return null;
return Structs.findMin(grid.tiles, t -> t.v.dst(Tmp.v33));
}
public void render(Mat3D mat){
Shaders.planet.begin();
Shaders.planet.setUniformMatrix4("u_projModelView", mat.val);
@ -53,46 +58,6 @@ public class PlanetMesh{
Shaders.planet.end();
}
/** Projects a tile onto a 4-corner square for use in map gen.
* Allocates a new object. Do not call in the main loop. */
public SectorRect projectTile(Ptile base){
Vec3[] corners = new Vec3[base.corners.length];
for(int i = 0; i < corners.length; i++){
corners[i] = base.corners[i].v.cpy().setLength(radius);
}
Tmp.v33.setZero();
for(Vec3 c : corners){
Tmp.v33.add(c);
}
//v33 is now the center of this shape
Vec3 center = Tmp.v33.scl(1f / corners.length).cpy(vec);
//radius of circle
float radius = Tmp.v33.dst(corners[0]) * 0.9f;
//get plane that these points are on
plane.set(corners[0], corners[2], corners[4]);
Vec3 planeTop = plane.project(center.cpy().add(0f, 1f, 0f)).sub(center).setLength(radius).add(center);
Vec3 planeRight = plane.project(center.cpy().rotate(Vec3.Y, -4f)).sub(center).setLength(radius).add(center);
return new SectorRect(center, planeTop.sub(center), planeRight.sub(center));
}
public @Nullable Ptile getTile(Ray ray){
Vec3 vec = intersect(ray);
if(vec == null) return null;
//TODO fix O(N) search
return Structs.findMin(grid.tiles, t -> t.v.dst(vec));
}
public @Nullable Vec3 intersect(Ray ray){
if(Intersector3D.intersectRaySphere(ray, center, radius, Tmp.v33)){
return Tmp.v33;
}
return null;
}
private void generateMesh(){
for(Ptile tile : grid.tiles){
@ -172,22 +137,4 @@ public class PlanetMesh{
floats[6] = color.toFloatBits();
mesh.getVerticesBuffer().put(floats);
}
public static class SectorRect{
public final Vec3 center, top, right;
public final Vec3 result = new Vec3();
public SectorRect(Vec3 center, Vec3 top, Vec3 right){
this.center = center;
this.top = top;
this.right = right;
}
/** Project a coordinate into 3D space.
* Both coordinates should be normalized to floats of the value 0..1 */
public Vec3 project(float x, float y){
float nx = (x - 0.5f) * 2f, ny = (y - 0.5f) * 2f;
return result.set(center).add(right, nx).add(top, ny);
}
}
}

View File

@ -7,15 +7,10 @@ import arc.graphics.g3d.*;
import arc.input.*;
import arc.math.geom.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.game.*;
import mindustry.graphics.PlanetGrid.*;
import mindustry.graphics.PlanetMesh.*;
import mindustry.maps.generators.*;
import mindustry.maps.planet.*;
import mindustry.type.*;
import mindustry.type.Sector.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@ -55,14 +50,17 @@ public class PlanetRenderer implements PlanetGenerator{
Ptile tile = outline.getTile(cam.getPickRay(Core.input.mouseX(), Core.input.mouseY()));
if(tile != null){
for(int i = 0; i < tile.corners.length; i++){
Sector sector = planet.getSector(tile);
for(int i = 0; i < sector.tile.corners.length; i++){
batch.color(outlineColor);
batch.vertex(tile.corners[i].v);
batch.vertex(sector.tile.corners[i].v);
}
batch.flush(cam.combined(), Gl.triangleFan);
if(drawnRect){
SectorRect rect = planet.mesh.projectTile(tile);
//TODO hack.
SectorRect rect = sector.rect;
rect.center.scl(outlineRad);
rect.right.scl(outlineRad);
rect.top.scl(outlineRad);
@ -77,27 +75,12 @@ public class PlanetRenderer implements PlanetGenerator{
batch.vertex(rect.project(0, 1));
batch.flush(cam.combined(), Gl.lineLoop);
SectorRect coords = planet.mesh.projectTile(tile);
rect.center.scl(1f / outlineRad);
rect.right.scl(1f / outlineRad);
rect.top.scl(1f / outlineRad);
if(Core.input.keyTap(KeyCode.SPACE)){
logic.reset();
Vars.world.loadGenerator(new Generator(250, 250){
@Override
public void generate(Tiles tiles){
TileGen gen = new TileGen();
tiles.each((x, y) -> {
gen.reset();
Vec3 position = coords.project(x / (float)width, y / (float)height);
planet.generator.generate(position, gen);
tiles.set(x, y, new Tile(x, y, gen.floor, gen.overlay, gen.block));
});
tiles.get(width/2, height/2).setBlock(Blocks.coreShard, Team.sharded);
}
});
state.set(State.playing);
logic.play();
control.playSector(sector);
ui.planet.hide();
}
}

View File

@ -0,0 +1,4 @@
package mindustry.maps.generators;
public class BaseGenerator{
}

View File

@ -1,22 +1,30 @@
package mindustry.type;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.ctype.*;
import mindustry.graphics.*;
import mindustry.graphics.PlanetGrid.*;
import mindustry.maps.planet.*;
public class Planet extends UnlockableContent{
/** Mesh used for rendering. Created on load(). */
/** Mesh used for rendering. Created on load() - will be null on the server! */
public PlanetMesh mesh;
/** Grid used for the sectors on the planet. */
public @NonNull PlanetGrid grid;
/** Generator that will make the planet. */
public @NonNull PlanetGenerator generator;
/** Array of sectors; directly maps to tiles in the grid. */
public @NonNull Array<Sector> sectors;
/** Detail in divisions. Must be between 1 and 10. 6 is a good number for this.*/
public int detail = 3;
/** Size in terms of divisions. This only controls the amount of sectors on the planet, not the visuals. */
public int size = 3;
/** Radius of the mesh/sphere. */
public float radius = 1f;
public Planet(String name){
super(name);
@ -27,6 +35,29 @@ public class Planet extends UnlockableContent{
mesh = new PlanetMesh(detail, generator);
}
@Override
public void init(){
grid = PlanetGrid.newGrid(size);
sectors = new Array<>(grid.tiles.length);
for(int i = 0; i < grid.tiles.length; i++){
sectors.add(new Sector(this, grid.tiles[i]));
}
}
/** Gets a sector a tile position. */
public Sector getSector(Ptile tile){
return sectors.get(tile.id);
}
/** @return the sector that is hit by this ray, or null if nothing intersects it.
* @param center the center of this planet in 3D space, usually (0,0,0). */
public @Nullable Sector getSector(Vec3 center, Ray ray){
boolean found = Intersector3D.intersectRaySphere(ray, center, radius, Tmp.v33);
if(!found) return null;
//TODO fix O(N) search
return sectors.min(t -> t.tile.v.dst(Tmp.v33));
}
/** Planets cannot be viewed in the database dialog. */
@Override
public boolean isHidden(){

View File

@ -0,0 +1,66 @@
package mindustry.type;
import arc.math.geom.*;
import arc.util.*;
import mindustry.graphics.PlanetGrid.*;
/** A small section of a planet. */
//TODO should this be content?
public class Sector{
public final SectorRect rect;
public final Planet planet;
public final Ptile tile;
public Sector(Planet planet, Ptile tile){
this.planet = planet;
this.tile = tile;
this.rect = makeRect();
}
/** Projects this sector onto a 4-corner square for use in map gen.
* Allocates a new object. Do not call in the main loop. */
private SectorRect makeRect(){
Vec3[] corners = new Vec3[tile.corners.length];
for(int i = 0; i < corners.length; i++){
corners[i] = tile.corners[i].v.cpy().setLength(planet.radius);
}
Tmp.v33.setZero();
for(Vec3 c : corners){
Tmp.v33.add(c);
}
//v33 is now the center of this shape
Vec3 center = Tmp.v33.scl(1f / corners.length).cpy();
//radius of circle
float radius = Tmp.v33.dst(corners[0]) * 0.9f;
//get plane that these points are on
Plane plane = new Plane();
plane.set(corners[0], corners[2], corners[4]);
Vec3 planeTop = plane.project(center.cpy().add(0f, 1f, 0f)).sub(center).setLength(radius).add(center);
Vec3 planeRight = plane.project(center.cpy().rotate(Vec3.Y, -4f)).sub(center).setLength(radius).add(center);
return new SectorRect(radius, center, planeTop.sub(center), planeRight.sub(center));
}
public static class SectorRect{
public final Vec3 center, top, right;
public final Vec3 result = new Vec3();
public final float radius;
public SectorRect(float radius, Vec3 center, Vec3 top, Vec3 right){
this.center = center;
this.top = top;
this.right = right;
this.radius = radius;
}
/** Project a coordinate into 3D space.
* Both coordinates should be normalized to floats in the range [0, 1] */
public Vec3 project(float x, float y){
float nx = (x - 0.5f) * 2f, ny = (y - 0.5f) * 2f;
return result.set(center).add(right, nx).add(top, ny);
}
}
}

View File

@ -1,14 +1,12 @@
package mindustry.type;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.ArcAnnotate.*;
import mindustry.content.*;
import mindustry.ctype.ContentType;
import mindustry.ctype.UnlockableContent;
import mindustry.ctype.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Objectives.*;
@ -29,7 +27,6 @@ public class Zone extends UnlockableContent{
public int conditionWave = Integer.MAX_VALUE;
public int launchPeriod = 10;
public Schematic loadout = Loadouts.basicShard;
public TextureRegion preview;
protected Array<ItemStack> baseLaunchCost = new Array<>();
protected Array<ItemStack> startingItems = new Array<>();
@ -47,11 +44,6 @@ public class Zone extends UnlockableContent{
this(name, Planets.starter, new MapGenerator(name));
}
@Override
public void load(){
preview = Core.atlas.find("zone-" + name, Core.atlas.find(name + "-zone"));
}
public Rules getRules(){
if(generator instanceof MapGenerator){
return ((MapGenerator)generator).getMap().rules();

View File

@ -1,7 +1,6 @@
package mindustry.ui.dialogs;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
@ -10,10 +9,10 @@ import arc.math.*;
import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.scene.utils.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
@ -143,17 +142,17 @@ public class DeployDialog extends FloatingDialog{
if(slot.getZone() != null){
sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.gray(0.1f)).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> {
TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable();
if(draw.getRegion().getTexture().isDisposed()){
draw.setRegion(slot.getZone().preview);
}
//sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> {
//TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable();
//if(draw.getRegion().getTexture().isDisposed()){
// draw.setRegion(slot.getZone().preview);
// }
Texture text = slot.previewTexture();
if(draw.getRegion() == slot.getZone().preview && text != null){
draw.setRegion(new TextureRegion(text));
}
}).color(Color.darkGray).grow()));
//if(draw.getRegion() == slot.getZone().preview && text != null){
// draw.setRegion(new TextureRegion(text));
//}
// }).color(Color.darkGray).grow()));
}
TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName), Styles.squaret, () -> {
@ -250,12 +249,12 @@ public class DeployDialog extends FloatingDialog{
for(ZoneNode node : nodes){
Stack stack = new Stack();
Tmp.v1.set(node.width, node.height);
if(node.zone.preview != null){
Tmp.v1.set(Scaling.fit.apply(node.zone.preview.getWidth(), node.zone.preview.getHeight(), node.width, node.height));
}
//if(node.zone.preview != null){
// Tmp.v1.set(Scaling.fit.apply(node.zone.preview.getWidth(), node.zone.preview.getHeight(), node.width, node.height));
//}
stack.setSize(Tmp.v1.x, Tmp.v1.y);
stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.gray(0.2f)).grow()));
// stack.setSize(Tmp.v1.x, Tmp.v1.y);
// stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.gray(0.2f)).grow()));
stack.update(() -> stack.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center));
Button button = new Button(Styles.squaret);

View File

@ -14,6 +14,7 @@ import mindustry.ui.Cicon;
import static mindustry.Vars.*;
//TODO remove
public class ZoneInfoDialog extends FloatingDialog{
private LoadoutDialog loadout = new LoadoutDialog();
@ -158,7 +159,7 @@ public class ZoneInfoDialog extends FloatingDialog{
ui.planet.hide();
data.removeItems(zone.getLaunchCost());
hide();
control.playZone(zone);
//control.playZone(zone);
}
}).minWidth(200f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !zone.canUnlock() : !data.hasItems(zone.getLaunchCost())).uniformY().get();

View File

@ -32,12 +32,14 @@ public class ZoneTests{
Array<DynamicTest> out = new Array<>();
if(world == null) world = new World();
fail("Zone validity tests need to be refactored!");
for(Zone zone : content.zones()){
out.add(dynamicTest(zone.name, () -> {
zone.generator.init(zone.loadout);
logic.reset();
try{
world.loadGenerator(zone.generator);
//world.loadGenerator(zone.generator);
}catch(SaveException e){
e.printStackTrace();
return;