From eed91eaaa01c3597e8c2ccd84d28a7a95d2995f2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 15 Jun 2021 19:29:12 -0400 Subject: [PATCH] # Conflicts: # core/src/mindustry/mod/ClassMap.java --- .github/workflows/deployment.yml | 6 +- .github/workflows/pr.yml | 6 +- .github/workflows/push.yml | 6 +- README.md | 2 +- android/build.gradle | 4 +- .../android/AndroidRhinoContext.java | 7 - build.gradle | 21 +-- core/src/mindustry/ClientLauncher.java | 2 +- core/src/mindustry/ai/BaseAI.java | 2 +- core/src/mindustry/content/Blocks.java | 1 - core/src/mindustry/content/UnitTypes.java | 4 +- core/src/mindustry/core/Control.java | 3 +- core/src/mindustry/core/Platform.java | 9 - .../mindustry/editor/MapGenerateDialog.java | 5 +- core/src/mindustry/editor/MapInfoDialog.java | 9 +- .../entities/effect/ParticleEffect.java | 4 +- core/src/mindustry/graphics/CacheLayer.java | 3 +- core/src/mindustry/graphics/MenuRenderer.java | 18 +- core/src/mindustry/graphics/g3d/SunMesh.java | 3 +- core/src/mindustry/logic/LExecutor.java | 3 - core/src/mindustry/logic/LogicOp.java | 3 +- .../mindustry/maps/filters/BlendFilter.java | 15 +- .../mindustry/maps/filters/ClearFilter.java | 7 +- .../maps/filters/CoreSpawnFilter.java | 4 +- .../mindustry/maps/filters/DistortFilter.java | 13 +- .../maps/filters/EnemySpawnFilter.java | 7 +- .../maps/filters/GenerateFilter.java | 44 ++--- .../mindustry/maps/filters/MedianFilter.java | 11 +- .../mindustry/maps/filters/MirrorFilter.java | 22 +-- .../mindustry/maps/filters/NoiseFilter.java | 23 ++- .../src/mindustry/maps/filters/OreFilter.java | 21 ++- .../maps/filters/OreMedianFilter.java | 11 +- .../maps/filters/RiverNoiseFilter.java | 23 ++- .../mindustry/maps/filters/ScatterFilter.java | 19 +- .../maps/filters/SpawnPathFilter.java | 6 +- .../mindustry/maps/filters/TerrainFilter.java | 25 ++- .../maps/generators/PlanetGenerator.java | 3 +- .../maps/planet/SerpuloPlanetGenerator.java | 18 +- core/src/mindustry/mod/ClassMap.java | 19 +- core/src/mindustry/mod/ContentParser.java | 4 +- core/src/mindustry/mod/Scripts.java | 10 -- core/src/mindustry/ui/dialogs/ModsDialog.java | 26 +-- .../world/blocks/ConstructBlock.java | 8 +- .../world/blocks/distribution/MassDriver.java | 2 +- .../world/blocks/experimental/BlockForge.java | 14 ++ .../blocks/experimental/BlockLoader.java | 142 +-------------- .../blocks/experimental/BlockUnloader.java | 61 +------ .../world/blocks/payloads/BlockLoader.java | 147 ++++++++++++++++ .../world/blocks/payloads/BlockUnloader.java | 67 +++++++ .../blocks/payloads/PayloadMassDriver.java | 1 + .../world/blocks/payloads/PayloadVoid.java | 2 +- .../blocks/power/ItemLiquidGenerator.java | 2 + desktop/build.gradle | 2 +- gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 31 ++-- gradlew.bat | 25 +-- jitpack.yml | 7 +- .../src/mindustry/server/ServerLauncher.java | 10 -- servers_be.json | 3 - settings.gradle | 4 +- tests/src/test/java/ApplicationTests.java | 165 +++++++++++++++++- tests/src/test/java/GenericModTest.java | 35 ++++ tests/src/test/java/IOTests.java | 63 ------- tests/src/test/java/ModTestBM.java | 39 +++++ tests/src/test/java/ModTestExotic.java | 40 +++++ tests/src/test/java/ModTestHAI.java | 39 +++++ tests/src/test/java/SectorTests.java | 105 ----------- .../test/java/power/DirectConsumerTests.java | 37 ++-- .../java/power/ItemLiquidGeneratorTests.java | 1 - tools/src/mindustry/tools/Generators.java | 11 +- 72 files changed, 820 insertions(+), 704 deletions(-) create mode 100644 core/src/mindustry/world/blocks/experimental/BlockForge.java create mode 100644 core/src/mindustry/world/blocks/payloads/BlockLoader.java create mode 100644 core/src/mindustry/world/blocks/payloads/BlockUnloader.java create mode 100644 tests/src/test/java/GenericModTest.java delete mode 100644 tests/src/test/java/IOTests.java create mode 100644 tests/src/test/java/ModTestBM.java create mode 100644 tests/src/test/java/ModTestExotic.java create mode 100644 tests/src/test/java/ModTestHAI.java delete mode 100644 tests/src/test/java/SectorTests.java diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 29dad558e5..b64e8feca4 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -6,15 +6,15 @@ on: - 'v*' jobs: - buildJava14: + deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 14 + - name: Set up JDK 16 uses: actions/setup-java@v1 with: - java-version: 14 + java-version: 16 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Add Arc release diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f769d87b6a..5888db4507 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -3,15 +3,15 @@ name: Pull Request Tests on: [pull_request, workflow_dispatch] jobs: - buildJava14: + testPR: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up JDK 14 + - name: Set up JDK 16 uses: actions/setup-java@v1 with: - java-version: 14 + java-version: 16 - name: Run unit tests and build JAR run: ./gradlew test desktop:dist - name: Upload desktop JAR for testing diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index d300e57e24..1409aef4ff 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -3,7 +3,7 @@ name: Tests on: [push, workflow_dispatch] jobs: - buildJava14: + runPush: runs-on: ubuntu-latest steps: @@ -17,9 +17,9 @@ jobs: git tag ${BNUM} git config --global user.name "Build Uploader" git push https://Anuken:${{ secrets.API_TOKEN_GITHUB }}@github.com/Anuken/MindustryBuilds ${BNUM} - - name: Set up JDK 14 + - name: Set up JDK 16 uses: actions/setup-java@v1 with: - java-version: 14 + java-version: 16 - name: Run unit tests run: ./gradlew clean cleanTest test diff --git a/README.md b/README.md index b6b3e26597..575f421530 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ See [CONTRIBUTING](CONTRIBUTING.md). Bleeding-edge builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases). If you'd rather compile on your own, follow these instructions. -First, make sure you have [JDK 14](https://adoptopenjdk.net/archive.html?variant=openjdk14&jvmVariant=hotspot) installed. **Other JDK versions will not work.** Open a terminal in the Mindustry directory and run the following commands: +First, make sure you have [JDK 16](https://adoptopenjdk.net/archive.html?variant=openjdk16&jvmVariant=hotspot) installed. **Other JDK versions will not work.** Open a terminal in the Mindustry directory and run the following commands: ### Windows diff --git a/android/build.gradle b/android/build.gradle index 0196805db9..a4de97915b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,9 +7,7 @@ buildscript{ } dependencies{ - //IMPORTANT NOTICE: any version of the plugin after 3.4.1 will break builds - //it appears abstract methods don't get desugared properly (if at all) - classpath 'com.android.tools.build:gradle:3.4.1' + classpath 'com.android.tools.build:gradle:7.1.0-alpha02' } } diff --git a/android/src/mindustry/android/AndroidRhinoContext.java b/android/src/mindustry/android/AndroidRhinoContext.java index 1b845d61cf..ab28532941 100644 --- a/android/src/mindustry/android/AndroidRhinoContext.java +++ b/android/src/mindustry/android/AndroidRhinoContext.java @@ -62,13 +62,6 @@ public class AndroidRhinoContext{ initApplicationClassLoader(createClassLoader(AndroidContextFactory.class.getClassLoader())); } - @Override - protected Context makeContext(){ - Context ctx = super.makeContext(); - ctx.setClassShutter(Scripts::allowClass); - return ctx; - } - /** * Create a ClassLoader which is able to deal with bytecode * @param parent the parent of the create classloader diff --git a/build.gradle b/build.gradle index 950d2cda44..f93082e0fa 100644 --- a/build.gradle +++ b/build.gradle @@ -196,12 +196,7 @@ allprojects{ tasks.withType(JavaCompile){ targetCompatibility = 8 - //TODO fix dynamically, this is a hack - if(System.getProperty("user.name") == "anuke"){ - sourceCompatibility = JavaVersion.VERSION_15 - }else{ - sourceCompatibility = JavaVersion.VERSION_14 - } + sourceCompatibility = JavaVersion.VERSION_16 options.encoding = "UTF-8" options.compilerArgs += ["-Xlint:deprecation"] dependsOn clearCache @@ -224,18 +219,13 @@ configure(project(":annotations")){ //compile with java 8 compatibility for everything except the annotation project configure(subprojects - project(":annotations")){ tasks.withType(JavaCompile){ - options.compilerArgs.addAll(['--release', '8', '--enable-preview']) - - doFirst{ - options.compilerArgs = options.compilerArgs.findAll{it != '--enable-preview' } - } + options.compilerArgs.addAll(['--release', '8']) } tasks.withType(Javadoc){ options{ addStringOption('Xdoclint:none', '-quiet') - addBooleanOption('-enable-preview', true) - addStringOption('-release', '14') + addStringOption('-release', '16') } } } @@ -302,9 +292,8 @@ project(":core"){ kapt{ javacOptions{ - option("-source", "14") + option("-source", "16") option("-target", "1.8") - option("--enable-preview") } } @@ -430,6 +419,8 @@ project(":tests"){ } test{ + //fork every test so mods don't interact with each other + forkEvery = 1 useJUnitPlatform() workingDir = new File("../core/assets") testLogging{ diff --git a/core/src/mindustry/ClientLauncher.java b/core/src/mindustry/ClientLauncher.java index 6042a38b19..71b04314a8 100644 --- a/core/src/mindustry/ClientLauncher.java +++ b/core/src/mindustry/ClientLauncher.java @@ -83,7 +83,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform Fonts.loadDefaultFont(); //load fallback atlas if max texture size is below 4096 - assets.load(new AssetDescriptor<>(maxTextureSize >= 4096 ? "sprites/sprites.aatls" : "sprites/fallback/sprites.aatls", TextureAtlas.class)).loaded = t -> atlas = (TextureAtlas)t; + assets.load(new AssetDescriptor<>(maxTextureSize >= 4096 ? "sprites/sprites.aatls" : "sprites/fallback/sprites.aatls", TextureAtlas.class)).loaded = t -> atlas = (TextureAtlas)t; assets.loadRun("maps", Map.class, () -> maps.loadPreviews()); Musics.load(); diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java index bebbdc1e8c..6ca2a5a751 100644 --- a/core/src/mindustry/ai/BaseAI.java +++ b/core/src/mindustry/ai/BaseAI.java @@ -289,7 +289,7 @@ public class BaseAI{ } Tile o = world.tile(tile.x + p.x, tile.y + p.y); - if(o != null && (o.block() instanceof PayloadBlock || o.block() instanceof PayloadConveyor)){ + if(o != null && (o.block() instanceof PayloadBlock || o.block() instanceof PayloadConveyor || o.block() instanceof ShockMine)){ continue outer; } diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index bd283e80e9..16e1af2d52 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -16,7 +16,6 @@ import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.turrets.*; import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.environment.*; -import mindustry.world.blocks.experimental.*; import mindustry.world.blocks.legacy.*; import mindustry.world.blocks.liquid.*; import mindustry.world.blocks.logic.*; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index e6bffdedd4..b5225e6b85 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -612,9 +612,9 @@ public class UnitTypes implements ContentList{ bullet = new LiquidBulletType(Liquids.slag){{ damage = 11; speed = 2.4f; - drag = 0.01f; + drag = 0.009f; shootEffect = Fx.shootSmall; - lifetime = 56f; + lifetime = 57f; collidesAir = false; }}; }}); diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 93fa1e68a2..a416b5d2fd 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -323,13 +323,14 @@ public class Control implements ApplicationListener, Loadable{ if(slot != null && !clearSectors){ try{ + boolean hadNoCore = !sector.info.hasCore; reloader.begin(); slot.load(); slot.setAutosave(true); state.rules.sector = sector; //if there is no base, simulate a new game and place the right loadout at the spawn position - if(state.rules.defaultTeam.cores().isEmpty()){ + if(state.rules.defaultTeam.cores().isEmpty() || hadNoCore){ //no spawn set -> delete the sector save if(sector.info.spawnPosition == 0){ diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index a595668aa8..bbceee8a64 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -79,15 +79,6 @@ public interface Platform{ } default Context getScriptContext(){ - ContextFactory.getGlobalSetter().setContextFactoryGlobal(new ContextFactory(){ - @Override - protected Context makeContext(){ - Context ctx = super.makeContext(); - ctx.setClassShutter(Scripts::allowClass); - return ctx; - } - }); - Context c = Context.enter(); c.setOptimizationLevel(9); return c; diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index 71f4f60264..31af738182 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -164,7 +164,7 @@ public class MapGenerateDialog extends BaseDialog{ for(int x = 0; x < editor.width(); x++){ for(int y = 0; y < editor.height(); y++){ Tile tile = editor.tile(x, y); - input.apply(x, y, tile.block(), tile.floor(), tile.overlay()); + input.set(x, y, tile.block(), tile.floor(), tile.overlay()); filter.apply(input); writeTiles[x + y*world.width()] = PackTile.get(input.block.id, input.floor.id, input.overlay.id); } @@ -340,6 +340,7 @@ public class MapGenerateDialog extends BaseDialog{ if(filter.isPost() && applied) continue; p.button((icon == '\0' ? "" : icon + " ") + filter.name(), Styles.cleart, () -> { + filter.randomize(); filters.add(filter); rebuildFilters(); update(); @@ -419,7 +420,7 @@ public class MapGenerateDialog extends BaseDialog{ pixmap.each((px, py) -> { int x = px * scaling, y = py * scaling; long tile = buffer1[px + py * w]; - input.apply(x, y, content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile))); + input.set(x, y, content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile))); filter.apply(input); buffer2[px + py * w] = PackTile.get(input.block.id, input.floor.id, input.overlay.id); }); diff --git a/core/src/mindustry/editor/MapInfoDialog.java b/core/src/mindustry/editor/MapInfoDialog.java index a18828f1f0..da4bf5a4b3 100644 --- a/core/src/mindustry/editor/MapInfoDialog.java +++ b/core/src/mindustry/editor/MapInfoDialog.java @@ -3,6 +3,7 @@ package mindustry.editor; import arc.*; import arc.scene.ui.*; import arc.struct.*; +import arc.util.*; import mindustry.*; import mindustry.game.*; import mindustry.io.*; @@ -73,8 +74,12 @@ public class MapInfoDialog extends BaseDialog{ t.row(); t.add("@editor.generation").padRight(8).left(); t.button("@edit", () -> { - generate.show(Vars.maps.readFilters(editor.tags.get("genfilters", "")), - filters -> editor.tags.put("genfilters", JsonIO.write(filters))); + generate.show(maps.readFilters(editor.tags.get("genfilters", "")), + filters -> { + //reset seed to 0 so it is not written + filters.each(f -> f.seed = 0); + editor.tags.put("genfilters", JsonIO.write(filters)); + }); hide(); }).left().width(200f); diff --git a/core/src/mindustry/entities/effect/ParticleEffect.java b/core/src/mindustry/entities/effect/ParticleEffect.java index a6e5df24a8..2b8fd4e52d 100644 --- a/core/src/mindustry/entities/effect/ParticleEffect.java +++ b/core/src/mindustry/entities/effect/ParticleEffect.java @@ -59,12 +59,12 @@ public class ParticleEffect extends Effect{ Angles.randLenVectors(e.id, particles, length * fin + baseLength, e.rotation, cone, (x, y) -> { Lines.lineAngle(ox + x, oy + y, Mathf.angle(x, y), len); - Drawf.light(ox + x, oy + y, len * lightScl, lightColor, lightOpacity); + Drawf.light(ox + x, oy + y, len * lightScl, lightColor, lightOpacity* Draw.getColor().a); }); }else{ Angles.randLenVectors(e.id, particles, length * fin + baseLength, e.rotation, cone, (x, y) -> { Draw.rect(tex, ox + x, oy + y, rad, rad, e.rotation + offset + e.time * spin); - Drawf.light(ox + x, oy + y, rad * lightScl, lightColor, lightOpacity); + Drawf.light(ox + x, oy + y, rad * lightScl, lightColor, lightOpacity * Draw.getColor().a); }); } } diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index 31b8074196..a68b7f6e06 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -3,6 +3,7 @@ package mindustry.graphics; import arc.*; import arc.graphics.*; import arc.graphics.gl.*; +import arc.util.*; import static mindustry.Vars.*; @@ -53,7 +54,7 @@ public class CacheLayer{ } public static class ShaderLayer extends CacheLayer{ - public Shader shader; + public @Nullable Shader shader; public ShaderLayer(Shader shader){ //shader will be null on headless backend, but that's ok diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 307b337028..3bb562bde1 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -44,9 +44,7 @@ public class MenuRenderer implements Disposable{ Seq ores = content.blocks().select(b -> b instanceof OreBlock && !(b instanceof WallOreBlock)); shadows = new FrameBuffer(width, height); int offset = Mathf.random(100000); - Simplex s1 = new Simplex(offset); - Simplex s2 = new Simplex(offset + 1); - Simplex s3 = new Simplex(offset + 2); + int s1 = offset, s2 = offset + 1, s3 = offset + 2; Block[] selected = Structs.select( new Block[]{Blocks.sand, Blocks.sandWall}, new Block[]{Blocks.shale, Blocks.shaleWall}, @@ -85,27 +83,27 @@ public class MenuRenderer implements Disposable{ Block ore = Blocks.air; Block wall = Blocks.air; - if(s1.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){ + if(Simplex.noise2d(s1, 3, 0.5, 1/20.0, x, y) > 0.5){ wall = walld; } - if(s3.octaveNoise2D(3, 0.5, 1/20.0, x, y) > 0.5){ + if(Simplex.noise2d(s3, 3, 0.5, 1/20.0, x, y) > 0.5){ floor = floord2; if(wall != Blocks.air){ wall = walld2; } } - if(s2.octaveNoise2D(3, 0.3, 1/30.0, x, y) > tr1){ + if(Simplex.noise2d(s2, 3, 0.3, 1/30.0, x, y) > tr1){ ore = ore1; } - if(s2.octaveNoise2D(2, 0.2, 1/15.0, x, y+99999) > tr2){ + if(Simplex.noise2d(s2, 2, 0.2, 1/15.0, x, y+99999) > tr2){ ore = ore2; } if(doheat){ - double heat = s3.octaveNoise2D(4, 0.6, 1 / 50.0, x, y + 9999); + double heat = Simplex.noise2d(s3, 4, 0.6, 1 / 50.0, x, y + 9999); double base = 0.65; if(heat > base){ @@ -126,7 +124,7 @@ public class MenuRenderer implements Disposable{ if(tech){ int mx = x % secSize, my = y % secSize; int sclx = x / secSize, scly = y / secSize; - if(s1.octaveNoise2D(2, 1f / 10f, 0.5f, sclx, scly) > 0.4f && (mx == 0 || my == 0 || mx == secSize - 1 || my == secSize - 1)){ + if(Simplex.noise2d(s1, 2, 1f / 10f, 0.5f, sclx, scly) > 0.4f && (mx == 0 || my == 0 || mx == secSize - 1 || my == secSize - 1)){ floor = Blocks.darkPanel3; if(Mathf.dst(mx, my, secSize/2, secSize/2) > secSize/2f + 1){ floor = Blocks.darkPanel4; @@ -140,7 +138,7 @@ public class MenuRenderer implements Disposable{ } if(tendrils){ - if(RidgedPerlin.noise2d(1 + offset, x, y, 1f / 17f) > 0f){ + if(Ridged.noise2d(1 + offset, x, y, 1f / 17f) > 0f){ floor = Mathf.chance(0.2) ? Blocks.sporeMoss : Blocks.moss; if(wall != Blocks.air){ diff --git a/core/src/mindustry/graphics/g3d/SunMesh.java b/core/src/mindustry/graphics/g3d/SunMesh.java index bef0761d5f..6b00aa3885 100644 --- a/core/src/mindustry/graphics/g3d/SunMesh.java +++ b/core/src/mindustry/graphics/g3d/SunMesh.java @@ -12,7 +12,6 @@ public class SunMesh extends HexMesh{ public SunMesh(Planet planet, int divisions, double octaves, double persistence, double scl, double pow, double mag, float colorScale, Color... colors){ super(planet, new HexMesher(){ - Simplex sim = new Simplex(); @Override public float getHeight(Vec3 position){ @@ -21,7 +20,7 @@ public class SunMesh extends HexMesh{ @Override public Color getColor(Vec3 position){ - double height = Math.pow(sim.octaveNoise3D(octaves, persistence, scl, position.x, position.y, position.z), pow) * mag; + double height = Math.pow(Simplex.noise3d(0, octaves, persistence, scl, position.x, position.y, position.z), pow) * mag; return Tmp.c1.set(colors[Mathf.clamp((int)(height * colors.length), 0, colors.length - 1)]).mul(colorScale); } }, divisions, Shaders.unlit); diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 43a90298bc..b5695d9773 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -28,9 +28,6 @@ import static mindustry.Vars.*; public class LExecutor{ public static final int maxInstructions = 1000; - //for noise operations - public static final Simplex noise = new Simplex(); - //special variables public static final int varCounter = 0, diff --git a/core/src/mindustry/logic/LogicOp.java b/core/src/mindustry/logic/LogicOp.java index 2de33558b9..9604279584 100644 --- a/core/src/mindustry/logic/LogicOp.java +++ b/core/src/mindustry/logic/LogicOp.java @@ -2,6 +2,7 @@ package mindustry.logic; import arc.math.*; import arc.util.*; +import arc.util.noise.*; public enum LogicOp{ add("+", (a, b) -> a + b), @@ -32,7 +33,7 @@ public enum LogicOp{ min("min", true, Math::min), angle("angle", true, (x, y) -> Angles.angle((float)x, (float)y)), len("len", true, (x, y) -> Mathf.dst((float)x, (float)y)), - noise("noise", true, LExecutor.noise::rawNoise2D), + noise("noise", true, (x, y) -> Simplex.raw2d(0, x, y)), abs("abs", a -> Math.abs(a)), log("log", Math::log), log10("log10", Math::log10), diff --git a/core/src/mindustry/maps/filters/BlendFilter.java b/core/src/mindustry/maps/filters/BlendFilter.java index d8d1ceda9e..7f0d319df9 100644 --- a/core/src/mindustry/maps/filters/BlendFilter.java +++ b/core/src/mindustry/maps/filters/BlendFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -13,12 +12,12 @@ public class BlendFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), - new BlockOption("block", () -> block, b -> block = b, anyOptional), - new BlockOption("floor", () -> floor, b -> floor = b, anyOptional), - new BlockOption("ignore", () -> ignore, b -> ignore = b, floorsOptional) - ); + return new FilterOption[]{ + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), + new BlockOption("block", () -> block, b -> block = b, anyOptional), + new BlockOption("floor", () -> floor, b -> floor = b, anyOptional), + new BlockOption("ignore", () -> ignore, b -> ignore = b, floorsOptional) + }; } @Override @@ -32,7 +31,7 @@ public class BlendFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ if(in.floor == block || block == Blocks.air || in.floor == ignore || (!floor.isFloor() && (in.block == block || in.block == ignore))) return; int rad = (int)radius; diff --git a/core/src/mindustry/maps/filters/ClearFilter.java b/core/src/mindustry/maps/filters/ClearFilter.java index 59e1a5b53c..3b2684ef7e 100644 --- a/core/src/mindustry/maps/filters/ClearFilter.java +++ b/core/src/mindustry/maps/filters/ClearFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -12,7 +11,9 @@ public class ClearFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr(new BlockOption("block", () -> block, b -> block = b, b -> oresOnly.get(b) || wallsOnly.get(b))); + return new BlockOption[]{ + new BlockOption("block", () -> block, b -> block = b, b -> oresOnly.get(b) || wallsOnly.get(b)) + }; } @Override @@ -21,7 +22,7 @@ public class ClearFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ if(in.block == block){ in.block = Blocks.air; diff --git a/core/src/mindustry/maps/filters/CoreSpawnFilter.java b/core/src/mindustry/maps/filters/CoreSpawnFilter.java index 84447ea1f3..5e18726d45 100644 --- a/core/src/mindustry/maps/filters/CoreSpawnFilter.java +++ b/core/src/mindustry/maps/filters/CoreSpawnFilter.java @@ -1,7 +1,6 @@ package mindustry.maps.filters; import arc.struct.*; -import arc.util.*; import mindustry.gen.*; import mindustry.world.*; import mindustry.world.blocks.storage.*; @@ -14,10 +13,9 @@ public class CoreSpawnFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( //disabled until necessary // SliderOption("amount", () -> amount, f -> amount = (int)f, 1, 10).display() - ); + return new FilterOption[]{}; } @Override diff --git a/core/src/mindustry/maps/filters/DistortFilter.java b/core/src/mindustry/maps/filters/DistortFilter.java index 4ae9c5a1d2..8b6d80e8e1 100644 --- a/core/src/mindustry/maps/filters/DistortFilter.java +++ b/core/src/mindustry/maps/filters/DistortFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.gen.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; @@ -10,10 +9,10 @@ public class DistortFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 200f), - new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) - ); + return new SliderOption[]{ + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 200f), + new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f) + }; } @Override @@ -27,8 +26,8 @@ public class DistortFilter extends GenerateFilter{ } @Override - public void apply(){ - Tile tile = in.tile(in.x + noise(in.x, in.y, scl, mag) - mag / 2f, in.y + noise(in.x, in.y + o, scl, mag) - mag / 2f); + public void apply(GenerateInput in){ + Tile tile = in.tile(in.x + noise(in, scl, mag) - mag / 2f, in.y + noise(in, scl, mag) - mag / 2f); in.floor = tile.floor(); if(!tile.block().synthetic() && !in.block.synthetic()) in.block = tile.block(); diff --git a/core/src/mindustry/maps/filters/EnemySpawnFilter.java b/core/src/mindustry/maps/filters/EnemySpawnFilter.java index 682d82debf..7d2a5d8d1d 100644 --- a/core/src/mindustry/maps/filters/EnemySpawnFilter.java +++ b/core/src/mindustry/maps/filters/EnemySpawnFilter.java @@ -1,7 +1,6 @@ package mindustry.maps.filters; import arc.struct.*; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.maps.filters.FilterOption.*; @@ -13,9 +12,9 @@ public class EnemySpawnFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("amount", () -> amount, f -> amount = (int)f, 1, 10).display() - ); + return new SliderOption[]{ + new SliderOption("amount", () -> amount, f -> amount = (int)f, 1, 10).display() + }; } @Override diff --git a/core/src/mindustry/maps/filters/GenerateFilter.java b/core/src/mindustry/maps/filters/GenerateFilter.java index b938914528..cdddad9099 100644 --- a/core/src/mindustry/maps/filters/GenerateFilter.java +++ b/core/src/mindustry/maps/filters/GenerateFilter.java @@ -12,12 +12,9 @@ import mindustry.gen.*; import mindustry.world.*; public abstract class GenerateFilter{ - protected transient float o = (float)(Math.random() * 10000000.0); - protected transient int seed; - protected transient GenerateInput in; + public int seed = 0; public void apply(Tiles tiles, GenerateInput in){ - this.in = in; if(isBuffered()){ //buffer of tiles used, each tile packed into a long struct @@ -26,8 +23,8 @@ public abstract class GenerateFilter{ for(int i = 0; i < tiles.width * tiles.height; i++){ Tile tile = tiles.geti(i); - in.apply(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay()); - apply(); + in.set(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay()); + apply(in); buffer[i] = PackTile.get(in.block.id, in.floor.id, in.overlay.id); } @@ -48,8 +45,8 @@ public abstract class GenerateFilter{ } }else{ for(Tile tile : tiles){ - in.apply(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay()); - apply(); + in.set(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay()); + apply(in); tile.setFloor(in.floor.asFloor()); tile.setOverlay(!in.floor.asFloor().hasSurface() && in.overlay.asFloor().needsSurface ? Blocks.air : in.overlay); @@ -61,16 +58,11 @@ public abstract class GenerateFilter{ } } - public final void apply(GenerateInput in){ - this.in = in; - apply(); - } - /** @return a new array of options for configuring this filter */ public abstract FilterOption[] options(); /** apply the actual filter on the input */ - protected void apply(){} + public void apply(GenerateInput in){} /** draw any additional guides */ public void draw(Image image){} @@ -93,7 +85,7 @@ public abstract class GenerateFilter{ /** set the seed to a random number */ public void randomize(){ - seed = Mathf.random(99999999); + seed = Mathf.random(999999999); } /** @return whether this filter needs a read/write buffer (e.g. not a 1:1 tile mapping). */ @@ -108,24 +100,26 @@ public abstract class GenerateFilter{ //utility generation functions - protected float noise(float x, float y, float scl, float mag){ - return (float)in.noise.octaveNoise2D(1f, 0f, 1f / scl, x + o, y + o) * mag; + //TODO would be nice if these functions used the seed and ditched "in" completely; simplex should be stateless + + protected float noise(GenerateInput in, float scl, float mag){ + return (float)Simplex.noise2d(seed, 1f, 0f, 1f / scl, in.x, in.y) * mag; } - protected float noise(float x, float y, float scl, float mag, float octaves, float persistence){ - return (float)in.noise.octaveNoise2D(octaves, persistence, 1f / scl, x + o, y + o) * mag; + protected float noise(GenerateInput in, float scl, float mag, float octaves, float persistence){ + return (float)Simplex.noise2d(seed, octaves, persistence, 1f / scl, in.x, in.y) * mag; } protected float rnoise(float x, float y, float scl, float mag){ - return RidgedPerlin.noise2d(seed + 1, (int)(x + o), (int)(y + o), 1f / scl) * mag; + return Ridged.noise2d(seed + 1, (int)(x), (int)(y), 1f / scl) * mag; } protected float rnoise(float x, float y, int octaves, float scl, float falloff, float mag){ - return RidgedPerlin.noise2d(seed + 1, (int)(x + o), (int)(y + o), octaves, falloff, 1f / scl) * mag; + return Ridged.noise2d(seed + 1, (int)(x), (int)(y), octaves, falloff, 1f / scl) * mag; } - protected float chance(){ - return Mathf.randomSeed(Pack.longInt(in.x, in.y + seed)); + protected float chance(int x, int y){ + return Mathf.randomSeed(Pack.longInt(x, y + seed)); } /** an input for generating at a certain coordinate. should only be instantiated once. */ @@ -137,10 +131,9 @@ public abstract class GenerateFilter{ /** output parameters */ public Block floor, block, overlay; - Simplex noise = new Simplex(); TileProvider buffer; - public void apply(int x, int y, Block block, Block floor, Block overlay){ + public void set(int x, int y, Block block, Block floor, Block overlay){ this.floor = floor; this.block = block; this.overlay = overlay; @@ -152,7 +145,6 @@ public abstract class GenerateFilter{ this.buffer = buffer; this.width = width; this.height = height; - noise.setSeed(filter.seed); } Tile tile(float x, float y){ diff --git a/core/src/mindustry/maps/filters/MedianFilter.java b/core/src/mindustry/maps/filters/MedianFilter.java index 001d79bba5..35d08f814d 100644 --- a/core/src/mindustry/maps/filters/MedianFilter.java +++ b/core/src/mindustry/maps/filters/MedianFilter.java @@ -2,7 +2,6 @@ package mindustry.maps.filters; import arc.math.*; import arc.struct.*; -import arc.util.*; import mindustry.gen.*; import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; @@ -17,10 +16,10 @@ public class MedianFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), - new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) - ); + return new SliderOption[]{ + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 10f), + new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) + }; } @Override @@ -34,7 +33,7 @@ public class MedianFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ int rad = (int)radius; blocks.clear(); floors.clear(); diff --git a/core/src/mindustry/maps/filters/MirrorFilter.java b/core/src/mindustry/maps/filters/MirrorFilter.java index cdb324b0ef..d96c3a6b5f 100644 --- a/core/src/mindustry/maps/filters/MirrorFilter.java +++ b/core/src/mindustry/maps/filters/MirrorFilter.java @@ -12,17 +12,17 @@ import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; public class MirrorFilter extends GenerateFilter{ - private final Vec2 v1 = new Vec2(), v2 = new Vec2(), v3 = new Vec2(); + private static final Vec2 v1 = new Vec2(), v2 = new Vec2(), v3 = new Vec2(); int angle = 45; boolean rotate = false; @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45), - new ToggleOption("rotate", () -> rotate, f -> rotate = f) - ); + return new FilterOption[]{ + new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45), + new ToggleOption("rotate", () -> rotate, f -> rotate = f) + }; } @Override @@ -31,7 +31,7 @@ public class MirrorFilter extends GenerateFilter{ } @Override - protected void apply(){ + public void apply(GenerateInput in){ v1.trnsExact(angle - 90, 1f); v2.set(v1).scl(-1f); @@ -41,7 +41,7 @@ public class MirrorFilter extends GenerateFilter{ v3.set(in.x, in.y); if(!left(v1, v2, v3)){ - mirror(v3, v1.x, v1.y, v2.x, v2.y); + mirror(in.width, in.height, v3, v1.x, v1.y, v2.x, v2.y); Tile tile = in.tile(v3.x, v3.y); in.floor = tile.floor(); if(!tile.block().synthetic()){ @@ -73,11 +73,11 @@ public class MirrorFilter extends GenerateFilter{ Draw.reset(); } - void mirror(Vec2 p, float x0, float y0, float x1, float y1){ + void mirror(int width, int height, Vec2 p, float x0, float y0, float x1, float y1){ //special case: uneven map mirrored at 45 degree angle (or someone might just want rotational symmetry) - if((in.width != in.height && angle % 90 != 0) || rotate){ - p.x = in.width - p.x - 1; - p.y = in.height - p.y - 1; + if((width != height && angle % 90 != 0) || rotate){ + p.x = width - p.x - 1; + p.y = height - p.y - 1; }else{ float dx = x1 - x0; float dy = y1 - y0; diff --git a/core/src/mindustry/maps/filters/NoiseFilter.java b/core/src/mindustry/maps/filters/NoiseFilter.java index acbf8162c6..b4aad342d2 100644 --- a/core/src/mindustry/maps/filters/NoiseFilter.java +++ b/core/src/mindustry/maps/filters/NoiseFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -13,15 +12,15 @@ public class NoiseFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), - new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), - new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), - new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("target", () -> target, b -> target = b, anyOptional), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), - new BlockOption("wall", () -> block, b -> block = b, wallsOptional) - ); + return new FilterOption[]{ + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), + new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), + new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), + new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), + new BlockOption("target", () -> target, b -> target = b, anyOptional), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), + new BlockOption("wall", () -> block, b -> block = b, wallsOptional) + }; } @Override @@ -30,8 +29,8 @@ public class NoiseFilter extends GenerateFilter{ } @Override - public void apply(){ - float noise = noise(in.x, in.y, scl, 1f, octaves, falloff); + public void apply(GenerateInput in){ + float noise = noise(in, scl, 1f, octaves, falloff); if(noise > threshold && (target == Blocks.air || in.floor == target || in.block == target)){ if(floor != Blocks.air) in.floor = floor; diff --git a/core/src/mindustry/maps/filters/OreFilter.java b/core/src/mindustry/maps/filters/OreFilter.java index 5487ea0d59..e5fd5f1344 100644 --- a/core/src/mindustry/maps/filters/OreFilter.java +++ b/core/src/mindustry/maps/filters/OreFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -13,14 +12,14 @@ public class OreFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), - new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), - new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), - new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("ore", () -> ore, b -> ore = b, oresOnly), - new BlockOption("target", () -> target, b -> target = b, oresFloorsOptional) - ); + return new FilterOption[]{ + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), + new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), + new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), + new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), + new BlockOption("ore", () -> ore, b -> ore = b, oresOnly), + new BlockOption("target", () -> target, b -> target = b, oresFloorsOptional) + }; } @Override @@ -29,8 +28,8 @@ public class OreFilter extends GenerateFilter{ } @Override - public void apply(){ - float noise = noise(in.x, in.y, scl, 1f, octaves, falloff); + public void apply(GenerateInput in){ + float noise = noise(in, scl, 1f, octaves, falloff); if(noise > threshold && in.overlay != Blocks.spawn && (target == Blocks.air || in.floor == target || in.overlay == target) && in.floor.asFloor().hasSurface()){ in.overlay = ore; diff --git a/core/src/mindustry/maps/filters/OreMedianFilter.java b/core/src/mindustry/maps/filters/OreMedianFilter.java index cba1d56936..9409604c23 100644 --- a/core/src/mindustry/maps/filters/OreMedianFilter.java +++ b/core/src/mindustry/maps/filters/OreMedianFilter.java @@ -2,7 +2,6 @@ package mindustry.maps.filters; import arc.math.*; import arc.struct.*; -import arc.util.*; import mindustry.*; import mindustry.content.*; import mindustry.gen.*; @@ -17,10 +16,10 @@ public class OreMedianFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), - new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) - ); + return new SliderOption[]{ + new SliderOption("radius", () -> radius, f -> radius = f, 1f, 12f), + new SliderOption("percentile", () -> percentile, f -> percentile = f, 0f, 1f) + }; } @Override @@ -34,7 +33,7 @@ public class OreMedianFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ if(in.overlay == Blocks.spawn) return; int cx = (in.x / 2) * 2; diff --git a/core/src/mindustry/maps/filters/RiverNoiseFilter.java b/core/src/mindustry/maps/filters/RiverNoiseFilter.java index aeefe8422a..3fb6efab5e 100644 --- a/core/src/mindustry/maps/filters/RiverNoiseFilter.java +++ b/core/src/mindustry/maps/filters/RiverNoiseFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -13,16 +12,16 @@ public class RiverNoiseFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), - new SliderOption("threshold", () -> threshold, f -> threshold = f, -1f, 1f), - new SliderOption("threshold2", () -> threshold2, f -> threshold2 = f, -1f, 1f), - new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), - new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("block", () -> block, b -> block = b, wallsOnly), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly), - new BlockOption("floor2", () -> floor2, b -> floor2 = b, floorsOnly) - ); + return new FilterOption[]{ + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), + new SliderOption("threshold", () -> threshold, f -> threshold = f, -1f, 1f), + new SliderOption("threshold2", () -> threshold2, f -> threshold2 = f, -1f, 1f), + new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), + new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), + new BlockOption("block", () -> block, b -> block = b, wallsOnly), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly), + new BlockOption("floor2", () -> floor2, b -> floor2 = b, floorsOnly) + }; } @Override @@ -31,7 +30,7 @@ public class RiverNoiseFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ float noise = rnoise(in.x, in.y, (int)octaves, scl, falloff, 1f); if(noise >= threshold){ diff --git a/core/src/mindustry/maps/filters/ScatterFilter.java b/core/src/mindustry/maps/filters/ScatterFilter.java index b766183087..ca094891b4 100644 --- a/core/src/mindustry/maps/filters/ScatterFilter.java +++ b/core/src/mindustry/maps/filters/ScatterFilter.java @@ -1,6 +1,5 @@ package mindustry.maps.filters; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -13,12 +12,12 @@ public class ScatterFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("chance", () -> chance, f -> chance = f, 0f, 1f), - new BlockOption("flooronto", () -> flooronto, b -> flooronto = b, floorsOptional), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), - new BlockOption("block", () -> block, b -> block = b, wallsOresOptional) - ); + return new FilterOption[]{ + new SliderOption("chance", () -> chance, f -> chance = f, 0f, 1f), + new BlockOption("flooronto", () -> flooronto, b -> flooronto = b, floorsOptional), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), + new BlockOption("block", () -> block, b -> block = b, wallsOresOptional) + }; } @Override @@ -27,9 +26,9 @@ public class ScatterFilter extends GenerateFilter{ } @Override - public void apply(){ + public void apply(GenerateInput in){ - if(block != Blocks.air && (in.floor == flooronto || flooronto == Blocks.air) && in.block == Blocks.air && chance() <= chance){ + if(block != Blocks.air && (in.floor == flooronto || flooronto == Blocks.air) && in.block == Blocks.air && chance(in.x, in.y) <= chance){ if(!block.isOverlay()){ in.block = block; }else{ @@ -37,7 +36,7 @@ public class ScatterFilter extends GenerateFilter{ } } - if(floor != Blocks.air && (in.floor == flooronto || flooronto == Blocks.air) && chance() <= chance){ + if(floor != Blocks.air && (in.floor == flooronto || flooronto == Blocks.air) && chance(in.x, in.y) <= chance){ in.floor = floor; } } diff --git a/core/src/mindustry/maps/filters/SpawnPathFilter.java b/core/src/mindustry/maps/filters/SpawnPathFilter.java index ac49b13d31..09d453e513 100644 --- a/core/src/mindustry/maps/filters/SpawnPathFilter.java +++ b/core/src/mindustry/maps/filters/SpawnPathFilter.java @@ -19,9 +19,9 @@ public class SpawnPathFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("radius", () -> radius, f -> radius = (int)f, 1, 20).display() - ); + return new SliderOption[]{ + new SliderOption("radius", () -> radius, f -> radius = (int)f, 1, 20).display() + }; } @Override diff --git a/core/src/mindustry/maps/filters/TerrainFilter.java b/core/src/mindustry/maps/filters/TerrainFilter.java index f494d0c143..98fdc53d9d 100644 --- a/core/src/mindustry/maps/filters/TerrainFilter.java +++ b/core/src/mindustry/maps/filters/TerrainFilter.java @@ -1,7 +1,6 @@ package mindustry.maps.filters; import arc.math.*; -import arc.util.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.world.*; @@ -14,16 +13,16 @@ public class TerrainFilter extends GenerateFilter{ @Override public FilterOption[] options(){ - return Structs.arr( - new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), - new SliderOption("mag", () -> magnitude, f -> magnitude = f, 0f, 2f), - new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), - new SliderOption("circle-scale", () -> circleScl, f -> circleScl = f, 0f, 3f), - new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), - new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), - new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), - new BlockOption("wall", () -> block, b -> block = b, wallsOnly) - ); + return new FilterOption[]{ + new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f), + new SliderOption("mag", () -> magnitude, f -> magnitude = f, 0f, 2f), + new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f), + new SliderOption("circle-scale", () -> circleScl, f -> circleScl = f, 0f, 3f), + new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f), + new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f), + new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional), + new BlockOption("wall", () -> block, b -> block = b, wallsOnly) + }; } @Override @@ -32,8 +31,8 @@ public class TerrainFilter extends GenerateFilter{ } @Override - public void apply(){ - float noise = noise(in.x, in.y, scl, magnitude, octaves, falloff) + Mathf.dst((float)in.x / in.width, (float)in.y / in.height, 0.5f, 0.5f) * circleScl; + public void apply(GenerateInput in){ + float noise = noise(in, scl, magnitude, octaves, falloff) + Mathf.dst((float)in.x / in.width, (float)in.y / in.height, 0.5f, 0.5f) * circleScl; if(floor != Blocks.air){ in.floor = floor; diff --git a/core/src/mindustry/maps/generators/PlanetGenerator.java b/core/src/mindustry/maps/generators/PlanetGenerator.java index 521e5aa08e..4fe870d3dc 100644 --- a/core/src/mindustry/maps/generators/PlanetGenerator.java +++ b/core/src/mindustry/maps/generators/PlanetGenerator.java @@ -18,7 +18,6 @@ import static mindustry.Vars.*; public abstract class PlanetGenerator extends BasicGenerator implements HexMesher{ protected IntSeq ints = new IntSeq(); protected Sector sector; - protected Simplex noise = new Simplex(); /** Should generate sector bases for a planet. */ public void generateSector(Sector sector){ @@ -116,7 +115,7 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe @Override protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){ Vec3 v = sector.rect.project(x, y); - return (float)noise.octaveNoise3D(octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; + return (float)Simplex.noise3d(0, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; } /** @return the scaling factor for sector rects. */ diff --git a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java index fb68343b1a..f69537ef44 100644 --- a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java @@ -18,6 +18,8 @@ import mindustry.world.*; import static mindustry.Vars.*; public class SerpuloPlanetGenerator extends PlanetGenerator{ + static final int seed = 0; + BaseGenerator basegen = new BaseGenerator(); float scl = 5f; float waterOffset = 0.07f; @@ -55,7 +57,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ float rawHeight(Vec3 position){ position = Tmp.v33.set(position).scl(scl); - return (Mathf.pow((float)noise.octaveNoise3D(7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset); + return (Mathf.pow((float)Simplex.noise3d(seed, 7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset); } @Override @@ -114,7 +116,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ tile.floor = getBlock(position); tile.block = tile.floor.asFloor().wall; - if(RidgedPerlin.noise3d(1, position.x, position.y, position.z, 2, 22) > 0.31){ + if(Ridged.noise3d(1, position.x, position.y, position.z, 2, 22) > 0.31){ tile.block = Blocks.air; } } @@ -125,12 +127,12 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ position = Tmp.v33.set(position).scl(scl); float rad = scl; float temp = Mathf.clamp(Math.abs(position.y * 2f) / (rad)); - float tnoise = (float)noise.octaveNoise3D(7, 0.56, 1f/3f, position.x, position.y + 999f, position.z); + float tnoise = (float)Simplex.noise3d(seed, 7, 0.56, 1f/3f, position.x, position.y + 999f, position.z); temp = Mathf.lerp(temp, tnoise, 0.5f); height *= 1.2f; height = Mathf.clamp(height); - float tar = (float)noise.octaveNoise3D(4, 0.55f, 1f/2f, position.x, position.y + 999f, position.z) * 0.3f + Tmp.v31.dst(0, 0, 1f) * 0.2f; + float tar = (float)Simplex.noise3d(seed, 4, 0.55f, 1f/2f, position.x, position.y + 999f, position.z) * 0.3f + Tmp.v31.dst(0, 0, 1f) * 0.2f; Block res = arr[Mathf.clamp((int)(temp * arr.length), 0, arr[0].length - 1)][Mathf.clamp((int)(height * arr[0].length), 0, arr[0].length - 1)]; if(tar > 0.5f){ @@ -143,7 +145,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ @Override protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){ Vec3 v = sector.rect.project(x, y).scl(5f); - return (float)noise.octaveNoise3D(octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; + return (float)Simplex.noise3d(seed, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; } @Override @@ -250,15 +252,15 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{ float scl = 1f; float addscl = 1.3f; - if(noise.octaveNoise3D(2, 0.5, scl, sector.tile.v.x, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.25f*addscl){ + if(Simplex.noise3d(seed, 2, 0.5, scl, sector.tile.v.x, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.25f*addscl){ ores.add(Blocks.oreCoal); } - if(noise.octaveNoise3D(2, 0.5, scl, sector.tile.v.x + 1, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.5f*addscl){ + if(Simplex.noise3d(seed, 2, 0.5, scl, sector.tile.v.x + 1, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.5f*addscl){ ores.add(Blocks.oreTitanium); } - if(noise.octaveNoise3D(2, 0.5, scl, sector.tile.v.x + 2, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.7f*addscl){ + if(Simplex.noise3d(seed, 2, 0.5, scl, sector.tile.v.x + 2, sector.tile.v.y, sector.tile.v.z)*nmag + poles > 0.7f*addscl){ ores.add(Blocks.oreThorium); } diff --git a/core/src/mindustry/mod/ClassMap.java b/core/src/mindustry/mod/ClassMap.java index aa258a0666..de033c0e9a 100644 --- a/core/src/mindustry/mod/ClassMap.java +++ b/core/src/mindustry/mod/ClassMap.java @@ -1,6 +1,9 @@ package mindustry.mod; import arc.struct.*; +import mindustry.world.blocks.environment.*; +import mindustry.world.blocks.payloads.*; + /** Generated class. Maps simple class names to concrete classes. For use in JSON mods. */ @SuppressWarnings("deprecation") public class ClassMap{ @@ -171,20 +174,20 @@ public class ClassMap{ classes.put("OreBlock", mindustry.world.blocks.environment.OreBlock.class); classes.put("OverlayFloor", mindustry.world.blocks.environment.OverlayFloor.class); classes.put("Prop", mindustry.world.blocks.environment.Prop.class); - classes.put("SeaBush", mindustry.world.blocks.environment.SeaBush.class); - classes.put("Seaweed", mindustry.world.blocks.environment.Seaweed.class); + classes.put("Bush", Bush.class); + classes.put("WavingProp", WavingProp.class); classes.put("ShallowLiquid", mindustry.world.blocks.environment.ShallowLiquid.class); classes.put("SpawnBlock", mindustry.world.blocks.environment.SpawnBlock.class); - classes.put("StaticCoralWall", mindustry.world.blocks.environment.StaticCoralWall.class); + classes.put("StaticClusterWall", StaticClusterWall.class); classes.put("StaticTree", mindustry.world.blocks.environment.StaticTree.class); classes.put("StaticWall", mindustry.world.blocks.environment.StaticWall.class); classes.put("TreeBlock", mindustry.world.blocks.environment.TreeBlock.class); classes.put("WallOreBlock", mindustry.world.blocks.environment.WallOreBlock.class); classes.put("WobbleProp", mindustry.world.blocks.environment.WobbleProp.class); - classes.put("BlockLoader", mindustry.world.blocks.experimental.BlockLoader.class); - classes.put("BlockLoaderBuild", mindustry.world.blocks.experimental.BlockLoader.BlockLoaderBuild.class); - classes.put("BlockUnloader", mindustry.world.blocks.experimental.BlockUnloader.class); - classes.put("BlockUnloaderBuild", mindustry.world.blocks.experimental.BlockUnloader.BlockUnloaderBuild.class); + classes.put("BlockLoader", BlockLoader.class); + classes.put("BlockLoaderBuild", BlockLoader.BlockLoaderBuild.class); + classes.put("BlockUnloader", BlockUnloader.class); + classes.put("BlockUnloaderBuild", BlockUnloader.BlockUnloaderBuild.class); classes.put("LegacyBlock", mindustry.world.blocks.legacy.LegacyBlock.class); classes.put("LegacyMechPad", mindustry.world.blocks.legacy.LegacyMechPad.class); classes.put("LegacyMechPadBuild", mindustry.world.blocks.legacy.LegacyMechPad.LegacyMechPadBuild.class); @@ -235,7 +238,7 @@ public class ClassMap{ classes.put("PayloadSource", mindustry.world.blocks.payloads.PayloadSource.class); classes.put("PayloadSourceBuild", mindustry.world.blocks.payloads.PayloadSource.PayloadSourceBuild.class); classes.put("PayloadVoid", mindustry.world.blocks.payloads.PayloadVoid.class); - classes.put("BlockLoaderBuild", mindustry.world.blocks.payloads.PayloadVoid.BlockLoaderBuild.class); + classes.put("BlockLoaderBuild", PayloadVoid.PayloadVoidBuild.class); classes.put("UnitPayload", mindustry.world.blocks.payloads.UnitPayload.class); classes.put("Battery", mindustry.world.blocks.power.Battery.class); classes.put("BatteryBuild", mindustry.world.blocks.power.Battery.BatteryBuild.class); diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 6862b1a540..9c8c7f3b3a 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -752,8 +752,8 @@ public class ContentParser{ var out = ClassMap.classes.get(!base.isEmpty() && Character.isLowerCase(base.charAt(0)) ? Strings.capitalize(base) : base); if(out != null) return (Class)out; - //try to resolve it as a raw class name if it's allowed - if(base.indexOf('.') != -1 && Scripts.allowClass(base)){ + //try to resolve it as a raw class name + if(base.indexOf('.') != -1){ try{ return (Class)Class.forName(base); }catch(Exception ignored){ diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index 4f70c0c814..1aa69b9ab7 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -22,22 +22,12 @@ import java.util.*; import java.util.regex.*; public class Scripts implements Disposable{ - private static final Seq blacklist = Seq.with(".net.", "java.net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk", - "runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system", - ".awt", "socket", "classloader", "oracle", "invoke", "java.util.function", "java.util.stream", "org.", "mod.classmap"); - private static final Seq whitelist = Seq.with("mindustry.net", "netserver", "netclient", "com.sun.proxy.$proxy", "jdk.proxy", "mindustry.gen.", - "mindustry.logic.", "mindustry.async.", "saveio", "systemcursor", "filetreeinitevent", "asyncexecutor"); - private final Context context; private final Scriptable scope; private boolean errored; LoadedMod currentMod = null; - public static boolean allowClass(String type){ - return !blacklist.contains(t -> type.toLowerCase(Locale.ROOT).contains(t)) || whitelist.contains(t -> type.toLowerCase(Locale.ROOT).contains(t)); - } - public Scripts(){ Time.mark(); diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 44ebebe8ae..ca5ff1fcf8 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -174,21 +174,12 @@ public class ModsDialog extends BaseDialog{ dialog.hide(); platform.showMultiFileChooser(file -> { - Runnable go = () -> { - try{ - mods.importMod(file); - setup(); - }catch(IOException e){ - ui.showException(e); - e.printStackTrace(); - } - }; - - //show unsafe jar file warning - if(file.extEquals("jar")){ - ui.showConfirm("@warning", "@mod.jarwarn", go); - }else{ - go.run(); + try{ + mods.importMod(file); + setup(); + }catch(IOException e){ + ui.showException(e); + Log.err(e); } }, "zip", "jar"); }).margin(12f); @@ -529,10 +520,7 @@ public class ModsDialog extends BaseDialog{ private void githubImportMod(String repo, boolean isJava){ if(isJava){ - ui.showConfirm("@warning", "@mod.jarwarn", () -> { - ui.loadfrag.show(); - githubImportJavaMod(repo); - }); + githubImportJavaMod(repo); }else{ ui.loadfrag.show(); Core.net.httpGet(ghApi + "/repos/" + repo, res -> { diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 5e31f6df00..4c2fc98b1c 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -92,6 +92,8 @@ public class ConstructBlock extends Block{ Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size); if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); + + Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); } static boolean shouldPlay(){ @@ -123,8 +125,6 @@ public class ConstructBlock extends Block{ if(tile.build != null){ tile.build.placed(); } - - Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config)); } @Override @@ -259,7 +259,9 @@ public class ConstructBlock extends Block{ if(progress >= 1f || state.rules.infiniteResources){ if(lastBuilder == null) lastBuilder = builder; - constructed(tile, current, lastBuilder, (byte)rotation, builder.team, config); + if(!net.client()){ + constructed(tile, current, lastBuilder, (byte)rotation, builder.team, config); + } } } diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 94b993aa7f..045d61736f 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -324,7 +324,7 @@ public class MassDriver extends Block{ } protected boolean shooterValid(Building other){ - return other instanceof MassDriverBuild entity && other.consValid() && entity.block == block && entity.link == pos() && within(other, range); + return other instanceof MassDriverBuild entity && other.isValid() && other.consValid() && entity.block == block && entity.link == pos() && within(other, range); } protected boolean linkValid(){ diff --git a/core/src/mindustry/world/blocks/experimental/BlockForge.java b/core/src/mindustry/world/blocks/experimental/BlockForge.java new file mode 100644 index 0000000000..29adc64d00 --- /dev/null +++ b/core/src/mindustry/world/blocks/experimental/BlockForge.java @@ -0,0 +1,14 @@ +package mindustry.world.blocks.experimental; + +@Deprecated +public class BlockForge extends mindustry.world.blocks.payloads.BlockForge{ + + public BlockForge(String name){ + super(name); + } + + @Deprecated + public class BlockForgeBuild extends mindustry.world.blocks.payloads.BlockForge.BlockForgeBuild{ + + } +} diff --git a/core/src/mindustry/world/blocks/experimental/BlockLoader.java b/core/src/mindustry/world/blocks/experimental/BlockLoader.java index 41f2aa13f8..91a044d4f8 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockLoader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockLoader.java @@ -1,148 +1,14 @@ package mindustry.world.blocks.experimental; -import arc.*; -import arc.graphics.g2d.*; -import arc.util.*; -import mindustry.entities.units.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.type.*; -import mindustry.ui.*; -import mindustry.world.blocks.payloads.*; - -import static mindustry.Vars.*; - -public class BlockLoader extends PayloadBlock{ - public final int timerLoad = timers++; - - public float loadTime = 2f; - public int itemsLoaded = 5; - public float liquidsLoaded = 5f; - public int maxBlockSize = 2; +@Deprecated +public class BlockLoader extends mindustry.world.blocks.payloads.BlockLoader{ public BlockLoader(String name){ super(name); - - hasItems = true; - itemCapacity = 25; - //liquidCapacity = 25; - update = true; - outputsPayload = true; - size = 3; - rotate = true; } - @Override - public TextureRegion[] icons(){ - return new TextureRegion[]{region, inRegion, outRegion, topRegion}; - } + @Deprecated + public class BlockLoaderBuild extends mindustry.world.blocks.payloads.BlockLoader.BlockLoaderBuild{ - @Override - public boolean outputsItems(){ - return false; - } - - @Override - public void setBars(){ - super.setBars(); - - bars.add("progress", (BlockLoaderBuild entity) -> new Bar(() -> Core.bundle.format("bar.items", entity.payload == null ? 0 : entity.payload.build.items.total()), () -> Pal.items, entity::fraction)); - } - - @Override - public void drawRequestRegion(BuildPlan req, Eachable list){ - Draw.rect(region, req.drawx(), req.drawy()); - Draw.rect(inRegion, req.drawx(), req.drawy(), req.rotation * 90); - Draw.rect(outRegion, req.drawx(), req.drawy(), req.rotation * 90); - Draw.rect(topRegion, req.drawx(), req.drawy()); - } - - public class BlockLoaderBuild extends PayloadBlockBuild{ - - @Override - public boolean acceptPayload(Building source, Payload payload){ - return super.acceptPayload(source, payload) && - (payload instanceof BuildPayload build) && - ((build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize)/* || - ((BlockPayload)payload).entity.block().hasLiquids && ((BlockPayload)payload).block().liquidCapacity >= 10f)*/); - } - - @Override - public boolean acceptItem(Building source, Item item){ - return items.total() < itemCapacity; - } - - @Override - public void draw(){ - Draw.rect(region, x, y); - - //draw input - boolean fallback = true; - for(int i = 0; i < 4; i++){ - if(blends(i) && i != rotation){ - Draw.rect(inRegion, x, y, (i * 90) - 180); - fallback = false; - } - } - if(fallback) Draw.rect(inRegion, x, y, rotation * 90); - - Draw.rect(outRegion, x, y, rotdeg()); - - Draw.z(Layer.blockOver); - drawPayload(); - - Draw.z(Layer.blockOver + 0.1f); - Draw.rect(topRegion, x, y); - } - - @Override - public void updateTile(){ - if(shouldExport()){ - moveOutPayload(); - }else if(moveInPayload()){ - - //load up items - if(payload.block().hasItems && items.any()){ - if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){ - //load up items a set amount of times - for(int j = 0; j < itemsLoaded && items.any(); j++){ - - for(int i = 0; i < items.length(); i++){ - if(items.get(i) > 0){ - Item item = content.item(i); - if(payload.build.acceptItem(payload.build, item)){ - payload.build.handleItem(payload.build, item); - items.remove(item, 1); - break; - } - } - } - } - } - } - - //load up liquids (disabled) - /* - if(payload.block().hasLiquids && liquids.total() >= 0.001f){ - Liquid liq = liquids.current(); - float total = liquids.currentAmount(); - float flow = Math.min(Math.min(liquidsLoaded * delta(), payload.block().liquidCapacity - payload.entity.liquids.get(liq) - 0.0001f), total); - if(payload.entity.acceptLiquid(payload.entity, liq, flow)){ - payload.entity.liquids.add(liq, flow); - liquids.remove(liq, flow); - } - }*/ - } - } - - public float fraction(){ - return payload == null ? 0f : payload.build.items.total() / (float)payload.build.block.itemCapacity; - } - - public boolean shouldExport(){ - return payload != null && - ((payload.block().hasLiquids && payload.build.liquids.total() >= payload.block().liquidCapacity - 0.001f) || - (payload.block().hasItems && payload.build.items.total() >= payload.block().itemCapacity)); - } } } diff --git a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java index 53d4df1b66..1c655318e3 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java @@ -1,67 +1,14 @@ package mindustry.world.blocks.experimental; -import mindustry.gen.*; -import mindustry.type.*; - -import static mindustry.Vars.*; - -public class BlockUnloader extends BlockLoader{ +@Deprecated +public class BlockUnloader extends mindustry.world.blocks.payloads.BlockUnloader{ public BlockUnloader(String name){ super(name); } - @Override - public boolean outputsItems(){ - return true; - } + @Deprecated + public class BlockUnloaderBuild extends mindustry.world.blocks.payloads.BlockUnloader.BlockUnloaderBuild{ - @Override - public boolean rotatedOutput(int x, int y){ - return false; - } - - public class BlockUnloaderBuild extends BlockLoaderBuild{ - - @Override - public boolean acceptItem(Building source, Item item){ - return false; - } - - @Override - public void updateTile(){ - if(shouldExport()){ - moveOutPayload(); - }else if(moveInPayload()){ - - //load up items - if(payload.block().hasItems && !full()){ - if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){ - //load up items a set amount of times - for(int j = 0; j < itemsLoaded && !full(); j++){ - for(int i = 0; i < items.length(); i++){ - if(payload.build.items.get(i) > 0){ - Item item = content.item(i); - payload.build.items.remove(item, 1); - items.add(item, 1); - break; - } - } - } - } - } - } - - dump(); - } - - public boolean full(){ - return items.total() >= itemCapacity; - } - - @Override - public boolean shouldExport(){ - return payload != null && (payload.block().hasItems && payload.build.items.empty()); - } } } diff --git a/core/src/mindustry/world/blocks/payloads/BlockLoader.java b/core/src/mindustry/world/blocks/payloads/BlockLoader.java new file mode 100644 index 0000000000..001f93712a --- /dev/null +++ b/core/src/mindustry/world/blocks/payloads/BlockLoader.java @@ -0,0 +1,147 @@ +package mindustry.world.blocks.payloads; + +import arc.*; +import arc.graphics.g2d.*; +import arc.util.*; +import mindustry.entities.units.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.type.*; +import mindustry.ui.*; + +import static mindustry.Vars.*; + +public class BlockLoader extends PayloadBlock{ + public final int timerLoad = timers++; + + public float loadTime = 2f; + public int itemsLoaded = 5; + public float liquidsLoaded = 5f; + public int maxBlockSize = 2; + + public BlockLoader(String name){ + super(name); + + hasItems = true; + itemCapacity = 25; + //liquidCapacity = 25; + update = true; + outputsPayload = true; + size = 3; + rotate = true; + } + + @Override + public TextureRegion[] icons(){ + return new TextureRegion[]{region, inRegion, outRegion, topRegion}; + } + + @Override + public boolean outputsItems(){ + return false; + } + + @Override + public void setBars(){ + super.setBars(); + + bars.add("progress", (BlockLoaderBuild entity) -> new Bar(() -> Core.bundle.format("bar.items", entity.payload == null ? 0 : entity.payload.build.items.total()), () -> Pal.items, entity::fraction)); + } + + @Override + public void drawRequestRegion(BuildPlan req, Eachable list){ + Draw.rect(region, req.drawx(), req.drawy()); + Draw.rect(inRegion, req.drawx(), req.drawy(), req.rotation * 90); + Draw.rect(outRegion, req.drawx(), req.drawy(), req.rotation * 90); + Draw.rect(topRegion, req.drawx(), req.drawy()); + } + + public class BlockLoaderBuild extends PayloadBlockBuild{ + + @Override + public boolean acceptPayload(Building source, Payload payload){ + return super.acceptPayload(source, payload) && + (payload instanceof BuildPayload build) && + ((build.build.block.hasItems && build.block().unloadable && build.block().itemCapacity >= 10 && build.block().size <= maxBlockSize)/* || + ((BlockPayload)payload).entity.block().hasLiquids && ((BlockPayload)payload).block().liquidCapacity >= 10f)*/); + } + + @Override + public boolean acceptItem(Building source, Item item){ + return items.total() < itemCapacity; + } + + @Override + public void draw(){ + Draw.rect(region, x, y); + + //draw input + boolean fallback = true; + for(int i = 0; i < 4; i++){ + if(blends(i) && i != rotation){ + Draw.rect(inRegion, x, y, (i * 90) - 180); + fallback = false; + } + } + if(fallback) Draw.rect(inRegion, x, y, rotation * 90); + + Draw.rect(outRegion, x, y, rotdeg()); + + Draw.z(Layer.blockOver); + drawPayload(); + + Draw.z(Layer.blockOver + 0.1f); + Draw.rect(topRegion, x, y); + } + + @Override + public void updateTile(){ + if(shouldExport()){ + moveOutPayload(); + }else if(moveInPayload()){ + + //load up items + if(payload.block().hasItems && items.any()){ + if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){ + //load up items a set amount of times + for(int j = 0; j < itemsLoaded && items.any(); j++){ + + for(int i = 0; i < items.length(); i++){ + if(items.get(i) > 0){ + Item item = content.item(i); + if(payload.build.acceptItem(payload.build, item)){ + payload.build.handleItem(payload.build, item); + items.remove(item, 1); + break; + } + } + } + } + } + } + + //load up liquids (disabled) + /* + if(payload.block().hasLiquids && liquids.total() >= 0.001f){ + Liquid liq = liquids.current(); + float total = liquids.currentAmount(); + float flow = Math.min(Math.min(liquidsLoaded * delta(), payload.block().liquidCapacity - payload.entity.liquids.get(liq) - 0.0001f), total); + if(payload.entity.acceptLiquid(payload.entity, liq, flow)){ + payload.entity.liquids.add(liq, flow); + liquids.remove(liq, flow); + } + }*/ + } + } + + public float fraction(){ + return payload == null ? 0f : payload.build.items.total() / (float)payload.build.block.itemCapacity; + } + + public boolean shouldExport(){ + return payload != null && + ((payload.block().hasLiquids && payload.build.liquids.total() >= payload.block().liquidCapacity - 0.001f) || + (payload.block().hasItems && payload.build.items.total() >= payload.block().itemCapacity)); + } + } +} diff --git a/core/src/mindustry/world/blocks/payloads/BlockUnloader.java b/core/src/mindustry/world/blocks/payloads/BlockUnloader.java new file mode 100644 index 0000000000..8f4a644fce --- /dev/null +++ b/core/src/mindustry/world/blocks/payloads/BlockUnloader.java @@ -0,0 +1,67 @@ +package mindustry.world.blocks.payloads; + +import mindustry.gen.*; +import mindustry.type.*; + +import static mindustry.Vars.*; + +public class BlockUnloader extends BlockLoader{ + + public BlockUnloader(String name){ + super(name); + } + + @Override + public boolean outputsItems(){ + return true; + } + + @Override + public boolean rotatedOutput(int x, int y){ + return false; + } + + public class BlockUnloaderBuild extends BlockLoaderBuild{ + + @Override + public boolean acceptItem(Building source, Item item){ + return false; + } + + @Override + public void updateTile(){ + if(shouldExport()){ + moveOutPayload(); + }else if(moveInPayload()){ + + //load up items + if(payload.block().hasItems && !full()){ + if(efficiency() > 0.01f && timer(timerLoad, loadTime / efficiency())){ + //load up items a set amount of times + for(int j = 0; j < itemsLoaded && !full(); j++){ + for(int i = 0; i < items.length(); i++){ + if(payload.build.items.get(i) > 0){ + Item item = content.item(i); + payload.build.items.remove(item, 1); + items.add(item, 1); + break; + } + } + } + } + } + } + + dump(); + } + + public boolean full(){ + return items.total() >= itemCapacity; + } + + @Override + public boolean shouldExport(){ + return payload != null && (payload.block().hasItems && payload.build.items.empty()); + } + } +} diff --git a/core/src/mindustry/world/blocks/payloads/PayloadMassDriver.java b/core/src/mindustry/world/blocks/payloads/PayloadMassDriver.java index 3bf83976ec..0d1821c2f6 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadMassDriver.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadMassDriver.java @@ -184,6 +184,7 @@ public class PayloadMassDriver extends PayloadBlock{ if(current != null && !( current instanceof PayloadDriverBuild entity && + current.isValid() && entity.consValid() && entity.block == block && entity.link == pos() && within(current, range) )){ diff --git a/core/src/mindustry/world/blocks/payloads/PayloadVoid.java b/core/src/mindustry/world/blocks/payloads/PayloadVoid.java index e1cb184f48..fa41218e3c 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadVoid.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadVoid.java @@ -29,7 +29,7 @@ public class PayloadVoid extends PayloadBlock{ return new TextureRegion[]{region, topRegion}; } - public class BlockLoaderBuild extends PayloadBlockBuild{ + public class PayloadVoidBuild extends PayloadBlockBuild{ @Override public void draw(){ diff --git a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java index 5295bf0703..1ef6010f2b 100644 --- a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -61,6 +61,8 @@ public class ItemLiquidGenerator extends PowerGenerator{ @Override public void init(){ + emitLight = true; + lightRadius = 65f * size; if(!defaults){ setDefaults(); } diff --git a/desktop/build.gradle b/desktop/build.gradle index 4c8a14f86f..347ffeee07 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -48,7 +48,7 @@ task dist(type: Jar, dependsOn: configurations.runtimeClasspath){ } } -if(!project.ext.hasSprites()){ +if(!project.ext.hasSprites() && System.getenv("JITPACK") != "true"){ println "Scheduling sprite packing." run.dependsOn ":tools:pack" dist.dependsOn ":tools:pack" diff --git a/gradle.properties b/gradle.properties index 34b13c8f1d..15947e3eac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,5 @@ org.gradle.daemon=true -#--illegal-access=permit -org.gradle.jvmargs=-Xms256m -Xmx1024m +org.gradle.jvmargs=-Xms256m -Xmx1024m --illegal-access=permit # Don't recompute annotations if sources haven't been changed kapt.incremental.apt = true # Multithreaded @@ -9,4 +8,6 @@ kapt.use.worker.api=true kapt.include.compile.classpath=false # I don't need to use the kotlin stdlib yet, so remove it to prevent extra bloat & method count issues kotlin.stdlib.default.dependency=false -archash=3926b785320fea0cd9ca597f6bfa9071263a5464 +#needed for android compilation +android.useAndroidX=true +archash=07ced971f4c8b8b5a61aa3a84b29c90aa497cb48 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 23334 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 WDWbsF$p{Gi@ZUasP|4|kdH)CXgbPdn delta 19998 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d9132ea..0f80bbf516 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 83f2acfdc3..4f906e0c81 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 9618d8d960..107acd32c4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/jitpack.yml b/jitpack.yml index c06db14182..c418d56017 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,4 +1,9 @@ +jdk: + - openjdk16 before_install: - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh - - source install-jdk.sh --feature 14 + - source install-jdk.sh --feature 16 - jshell --version +install: + - ./gradlew publishToMavenLocal + - sed -i 's/ --illegal-access=permit//' gradle.properties #remove extra flags after compilation \ No newline at end of file diff --git a/server/src/mindustry/server/ServerLauncher.java b/server/src/mindustry/server/ServerLauncher.java index 8c20047022..4d4d3d9aa1 100644 --- a/server/src/mindustry/server/ServerLauncher.java +++ b/server/src/mindustry/server/ServerLauncher.java @@ -2,7 +2,6 @@ package mindustry.server; import arc.*; import arc.backend.headless.*; -import arc.files.*; import arc.util.*; import mindustry.*; import mindustry.core.*; @@ -44,15 +43,6 @@ public class ServerLauncher implements ApplicationListener{ loadLocales = false; headless = true; - Fi plugins = Core.settings.getDataDirectory().child("plugins"); - if(plugins.isDirectory() && plugins.list().length > 0 && !plugins.sibling("mods").exists()){ - warn("[IMPORTANT NOTICE] &lrPlugins have been detected.&ly Automatically moving all contents of the plugin folder into the 'mods' folder. The original folder will not be removed; please do so manually."); - plugins.sibling("mods").mkdirs(); - for(Fi file : plugins.list()){ - file.copyTo(plugins.sibling("mods")); - } - } - Vars.loadSettings(); Vars.init(); content.createBaseContent(); diff --git a/servers_be.json b/servers_be.json index 6fcc7a4a4f..d22999dea0 100644 --- a/servers_be.json +++ b/servers_be.json @@ -13,8 +13,5 @@ }, { "address": "mindurka.tk:9999" - }, - { - "address": "mindustrypvp.ml:6000" } ] diff --git a/settings.gradle b/settings.gradle index ef9b57e54a..76eaa676a6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,5 @@ -if(JavaVersion.current().ordinal() < JavaVersion.VERSION_14.ordinal()){ - throw new GradleException("!!! YOU MUST USE JAVA 14 OR ABOVE TO COMPILE AND RUN MINDUSTRY !!! Read the README. Your version: ${System.properties["java.version"]}") +if(JavaVersion.current().ordinal() < JavaVersion.VERSION_16.ordinal()){ + throw new Exception("!!! YOU MUST USE JAVA 16 OR ABOVE TO COMPILE AND RUN MINDUSTRY !!! Read the README. Your version: ${System.properties["java.version"]}") } include 'desktop', 'core', 'server', 'ios', 'annotations', 'tools', 'tests' diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 8bb1a1524e..2ea226ab7c 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -1,10 +1,12 @@ import arc.*; import arc.backend.headless.*; +import arc.files.*; import arc.func.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; +import arc.util.io.*; import arc.util.serialization.*; import arc.util.serialization.JsonValue.*; import mindustry.*; @@ -16,21 +18,36 @@ import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.io.*; +import mindustry.io.SaveIO.*; import mindustry.maps.*; +import mindustry.mod.*; +import mindustry.mod.Mods.*; import mindustry.net.Net; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.storage.*; import org.junit.jupiter.api.*; +import org.junit.jupiter.params.*; +import org.junit.jupiter.params.provider.*; + +import java.nio.*; import static mindustry.Vars.*; import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.DynamicTest.*; public class ApplicationTests{ static Map testMap; static boolean initialized; + //core/assets + static final Fi testDataFolder = new Fi("../../tests/build/test_data"); @BeforeAll - static void launchApplication(){ + public static void launchApplication(){ + launchApplication(true); + } + + public static void launchApplication(boolean clear){ //only gets called once if(initialized) return; initialized = true; @@ -43,6 +60,12 @@ public class ApplicationTests{ ApplicationCore core = new ApplicationCore(){ @Override public void setup(){ + //clear older data + if(clear){ + ApplicationTests.testDataFolder.deleteDirectory(); + } + + Core.settings.setDataDirectory(testDataFolder); headless = true; net = new Net(null); tree = new FileTree(); @@ -55,12 +78,26 @@ public class ApplicationTests{ } }; content.createBaseContent(); + mods.loadScripts(); + content.createModContent(); add(logic = new Logic()); add(netServer = new NetServer()); content.init(); + mods.eachClass(Mod::init); + + if(mods.hasContentErrors()){ + for(LoadedMod mod : mods.list()){ + if(mod.hasContentErrors()){ + for(Content cont : mod.erroredContent){ + throw new RuntimeException("error in file: " + cont.minfo.sourceFile.path(), cont.minfo.baseError); + } + } + } + } + } @Override @@ -96,6 +133,55 @@ public class ApplicationTests{ state.set(State.menu); } + @ParameterizedTest + @NullSource + @ValueSource(strings = { + "asd asd asd asd asdagagasasjakbgeah;jwrej 23424234", + "这个服务器可以用自己的语言说话" + }) + void writeStringTest(String string){ + ByteBuffer buffer = ByteBuffer.allocate(500); + TypeIO.writeString(buffer, string); + buffer.position(0); + assertEquals(TypeIO.readString(buffer), string); + } + + @Test + void writeRules(){ + ByteBuffer buffer = ByteBuffer.allocate(500); + + Rules rules = new Rules(); + rules.attackMode = true; + rules.buildSpeedMultiplier = 99f; + + TypeIO.writeRules(new Writes(new ByteBufferOutput(buffer)), rules); + buffer.position(0); + Rules res = TypeIO.readRules(new Reads(new ByteBufferInput(buffer))); + + assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); + assertEquals(rules.attackMode, res.attackMode); + } + + @Test + void writeRules2(){ + Rules rules = new Rules(); + rules.attackMode = true; + rules.tags.put("blah", "bleh"); + rules.buildSpeedMultiplier = 99.1f; + + String str = JsonIO.write(rules); + Rules res = JsonIO.read(Rules.class, str); + + assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); + assertEquals(rules.attackMode, res.attackMode); + assertEquals(rules.tags.get("blah"), res.tags.get("blah")); + + String str2 = JsonIO.write(new Rules(){{ + attackMode = true; + }}); + Log.info(str2); + } + @Test void serverListJson(){ String[] files = {"servers.json", "servers_be.json", "servers_v6.json"}; @@ -730,6 +816,83 @@ public class ApplicationTests{ } } + @TestFactory + DynamicTest[] testSectorValidity(){ + Seq out = new Seq<>(); + if(world == null) world = new World(); + + for(SectorPreset zone : content.sectors()){ + + out.add(dynamicTest(zone.name, () -> { + Time.setDeltaProvider(() -> 1f); + + logic.reset(); + try{ + world.loadGenerator(zone.generator.map.width, zone.generator.map.height, zone.generator::generate); + }catch(SaveException e){ + //fails randomly and I don't care about fixing it + e.printStackTrace(); + return; + } + zone.rules.get(state.rules); + ObjectSet resources = new ObjectSet<>(); + boolean hasSpawnPoint = false; + + for(Tile tile : world.tiles){ + if(tile.drop() != null){ + resources.add(tile.drop()); + } + if(tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam){ + hasSpawnPoint = true; + } + } + + Seq spawns = state.rules.spawns; + + int bossWave = 0; + if(state.rules.winWave > 0){ + bossWave = state.rules.winWave; + }else{ + outer: + for(int i = 1; i <= 1000; i++){ + for(SpawnGroup spawn : spawns){ + if(spawn.effect == StatusEffects.boss && spawn.getSpawned(i) > 0){ + bossWave = i; + break outer; + } + } + } + } + + if(state.rules.attackMode){ + bossWave = 100; + }else{ + assertNotEquals(0, bossWave, "Sector doesn't have a boss wave."); + } + + //TODO check for difficulty? + for(int i = 1; i <= bossWave; i++){ + int total = 0; + for(SpawnGroup spawn : spawns){ + total += spawn.getSpawned(i); + } + + assertNotEquals(0, total, "Sector " + zone + " has no spawned enemies at wave " + i); + //TODO this is flawed and needs to be changed later + //assertTrue(total < 75, "Sector spawns too many enemies at wave " + i + " (" + total + ")"); + } + + assertEquals(1, Team.sharded.cores().size, "Sector must have one core: " + zone); + assertTrue(Team.sharded.core().items.total() < 1000, "Sector must not have starting resources: " + zone); + + assertTrue(hasSpawnPoint, "Sector \"" + zone.name + "\" has no spawn points."); + assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && state.rules.waveTeam.data().hasCore()), "Sector \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); + })); + } + + return out.toArray(DynamicTest.class); + } + void initBuilding(){ createMap(); diff --git a/tests/src/test/java/GenericModTest.java b/tests/src/test/java/GenericModTest.java new file mode 100644 index 0000000000..f703d53873 --- /dev/null +++ b/tests/src/test/java/GenericModTest.java @@ -0,0 +1,35 @@ +import arc.*; +import arc.Net.*; +import arc.util.io.*; +import mindustry.*; +import org.junit.jupiter.api.*; + +import java.io.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class GenericModTest{ + + /** grabs a mod and puts it in the mod folder */ + static void grabMod(String url){ + //clear older mods + ApplicationTests.testDataFolder.deleteDirectory(); + Core.net = new Net(); + Core.net.setBlock(true); + Core.net.http(new HttpRequest().url(url).method(HttpMethod.GET), httpResponse -> { + try{ + ApplicationTests.testDataFolder.child("mods").child("test_mod." + (url.endsWith("jar") ? "jar" : "zip")).writeBytes(Streams.copyBytes(httpResponse.getResultAsStream())); + }catch(IOException e){ + Assertions.fail(e); + } + }, Assertions::fail); + + ApplicationTests.launchApplication(false); + } + + static void checkExistence(String modName){ + assertNotEquals(Vars.mods, null); + assertNotEquals(Vars.mods.list().size, 0, "At least one mod must be loaded."); + assertEquals(Vars.mods.list().first().name, modName, modName + " must be loaded."); + } +} diff --git a/tests/src/test/java/IOTests.java b/tests/src/test/java/IOTests.java deleted file mode 100644 index d10774439a..0000000000 --- a/tests/src/test/java/IOTests.java +++ /dev/null @@ -1,63 +0,0 @@ -import arc.util.*; -import arc.util.io.*; -import mindustry.game.*; -import mindustry.io.*; -import org.junit.jupiter.api.*; -import org.junit.jupiter.params.*; -import org.junit.jupiter.params.provider.*; - -import java.nio.*; - -import static org.junit.jupiter.api.Assertions.*; - -public class IOTests{ - - @ParameterizedTest - @NullSource - @ValueSource(strings = { - "asd asd asd asd asdagagasasjakbgeah;jwrej 23424234", - "这个服务器可以用自己的语言说话" - }) - void writeStringTest(String string){ - ByteBuffer buffer = ByteBuffer.allocate(500); - TypeIO.writeString(buffer, string); - buffer.position(0); - assertEquals(TypeIO.readString(buffer), string); - } - - @Test - void writeRules(){ - ByteBuffer buffer = ByteBuffer.allocate(500); - - Rules rules = new Rules(); - rules.attackMode = true; - rules.buildSpeedMultiplier = 99f; - - TypeIO.writeRules(new Writes(new ByteBufferOutput(buffer)), rules); - buffer.position(0); - Rules res = TypeIO.readRules(new Reads(new ByteBufferInput(buffer))); - - assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); - assertEquals(rules.attackMode, res.attackMode); - } - - @Test - void writeRules2(){ - Rules rules = new Rules(); - rules.attackMode = true; - rules.tags.put("blah", "bleh"); - rules.buildSpeedMultiplier = 99.1f; - - String str = JsonIO.write(rules); - Rules res = JsonIO.read(Rules.class, str); - - assertEquals(rules.buildSpeedMultiplier, res.buildSpeedMultiplier); - assertEquals(rules.attackMode, res.attackMode); - assertEquals(rules.tags.get("blah"), res.tags.get("blah")); - - String str2 = JsonIO.write(new Rules(){{ - attackMode = true; - }}); - Log.info(str2); - } -} diff --git a/tests/src/test/java/ModTestBM.java b/tests/src/test/java/ModTestBM.java new file mode 100644 index 0000000000..a99969a188 --- /dev/null +++ b/tests/src/test/java/ModTestBM.java @@ -0,0 +1,39 @@ +import mindustry.*; +import mindustry.world.*; +import mindustry.world.meta.*; +import org.junit.jupiter.api.*; + +import static mindustry.Vars.*; +import static org.junit.jupiter.api.Assertions.*; + +//grabs a betamindy release and makes sure it initializes correctly +//this mod was chosen because: +//- it is one of the top java mods on the browser +//- it uses a variety of mindustry classes +//- it is popular enough to cause significant amounts of crashes when something breaks +//- I have some familiarity with its codebase +public class ModTestBM extends GenericModTest{ + + @Test + public void begin(){ + grabMod("https://github.com/sk7725/BetaMindy/releases/download/v0.955/BetaMindy.jar"); + + checkExistence("betamindy"); + + Block type = Vars.content.blocks().find(u -> u.name.equals("betamindy-piston")); + assertNotNull(type, "A mod block must be loaded."); + assertSame(type.buildVisibility, BuildVisibility.shown, "A mod block must be buildable."); + + world.loadMap(ApplicationTests.testMap); + Tile t = world.tile(3, 3); + + t.setBlock(type); + + //check for crash + t.build.update(); + + assertTrue(t.build.health > 0, "Block must be spawned and alive."); + assertSame(t.build.block, type, "Block must be spawned and alive."); + } + +} diff --git a/tests/src/test/java/ModTestExotic.java b/tests/src/test/java/ModTestExotic.java new file mode 100644 index 0000000000..c9e401f811 --- /dev/null +++ b/tests/src/test/java/ModTestExotic.java @@ -0,0 +1,40 @@ +import arc.util.*; +import mindustry.*; +import mindustry.gen.*; +import mindustry.type.*; +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.*; + +//grabs a version-locked exotic-mod commit and makes sure its content is parsed correctly +//this mod was chosen because: +//- it is written solely in (h)json +//- it is probably the mod with the most json, and as such covers a lot of classes +//- it is popular enough in the mod browser +//- I am somewhat familiar with its files & the type of content it adds +public class ModTestExotic extends GenericModTest{ + + @Test + public void begin(){ + grabMod("https://github.com/BlueWolf3682/Exotic-Mod/archive/08c861398ac9c3d1292132f9a110e17e06294a90.zip"); + checkExistence("exotic-mod"); + + UnitType type = Vars.content.units().find(u -> u.name.equals("exotic-mod-luminance")); + assertNotNull(type, "A mod unit must be loaded."); + assertTrue(type.weapons.size > 0, "A mod unit must have a weapon."); + + Vars.world.loadMap(ApplicationTests.testMap); + + Unit unit = type.spawn(0, 0); + + //check for crash + unit.update(); + + assertTrue(unit.health > 0, "Unit must be spawned and alive."); + assertTrue(Groups.unit.size() > 0, "Unit must be spawned and alive."); + + //just an extra sanity check + Log.info("Modded units: @", Vars.content.units().select(u -> u.minfo.mod != null)); + } + +} diff --git a/tests/src/test/java/ModTestHAI.java b/tests/src/test/java/ModTestHAI.java new file mode 100644 index 0000000000..c33f9262c9 --- /dev/null +++ b/tests/src/test/java/ModTestHAI.java @@ -0,0 +1,39 @@ +import arc.util.*; +import mindustry.*; +import mindustry.gen.*; +import mindustry.type.*; +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.*; + +//grabs a version-locked Heavy Armaments Industries commit and makes sure it initializes correctly +//this mod was chosen because: +//- it is one of the top JS mods, based on stars +//- it contains both JS and JSON, which can be used to test compatibility of the two +//- it can be used server-side (unlike FactoryDustry, which is a client-side texture pack that cannot be tested here) +public class ModTestHAI extends GenericModTest{ + + @Test + public void begin(){ + grabMod("https://github.com/Eschatologue/Heavy-Armaments-Industries/archive/d996e92dcf9a30a6acb7b3bfdfb6522dddc3804c.zip"); + checkExistence("heavy-armaments"); + + UnitType type = Vars.content.units().find(u -> u.name.equals("heavy-armaments-t3A_copter")); + assertNotNull(type, "A mod unit must be loaded."); + assertTrue(type.weapons.size > 0, "A mod unit must have a weapon."); + + Vars.world.loadMap(ApplicationTests.testMap); + + Unit unit = type.spawn(0, 0); + + //check for crash + unit.update(); + + assertTrue(unit.health > 0, "Unit must be spawned and alive."); + assertTrue(Groups.unit.size() > 0, "Unit must be spawned and alive."); + + //just an extra sanity check + Log.info("Modded units: @", Vars.content.units().select(u -> u.minfo.mod != null)); + } + +} diff --git a/tests/src/test/java/SectorTests.java b/tests/src/test/java/SectorTests.java deleted file mode 100644 index 8df675c04f..0000000000 --- a/tests/src/test/java/SectorTests.java +++ /dev/null @@ -1,105 +0,0 @@ -import arc.struct.*; -import arc.util.*; -import mindustry.content.*; -import mindustry.core.*; -import mindustry.core.GameState.*; -import mindustry.game.*; -import mindustry.io.SaveIO.*; -import mindustry.type.*; -import mindustry.world.*; -import mindustry.world.blocks.storage.*; -import org.junit.jupiter.api.*; - -import static mindustry.Vars.*; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.DynamicTest.dynamicTest; - -public class SectorTests{ - - @BeforeAll - static void launchApplication(){ - ApplicationTests.launchApplication(); - } - - @BeforeEach - void resetWorld(){ - Time.setDeltaProvider(() -> 1f); - logic.reset(); - state.set(State.menu); - } - - @TestFactory - DynamicTest[] testZoneValidity(){ - Seq out = new Seq<>(); - if(world == null) world = new World(); - - for(SectorPreset zone : content.sectors()){ - - out.add(dynamicTest(zone.name, () -> { - logic.reset(); - try{ - world.loadGenerator(zone.generator.map.width, zone.generator.map.height, zone.generator::generate); - }catch(SaveException e){ - //fails randomly and I don't care about fixing it - e.printStackTrace(); - return; - } - zone.rules.get(state.rules); - ObjectSet resources = new ObjectSet<>(); - boolean hasSpawnPoint = false; - - for(Tile tile : world.tiles){ - if(tile.drop() != null){ - resources.add(tile.drop()); - } - if(tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam){ - hasSpawnPoint = true; - } - } - - Seq spawns = state.rules.spawns; - - int bossWave = 0; - if(state.rules.winWave > 0){ - bossWave = state.rules.winWave; - }else{ - outer: - for(int i = 1; i <= 1000; i++){ - for(SpawnGroup spawn : spawns){ - if(spawn.effect == StatusEffects.boss && spawn.getSpawned(i) > 0){ - bossWave = i; - break outer; - } - } - } - } - - if(state.rules.attackMode){ - bossWave = 100; - }else{ - assertNotEquals(0, bossWave, "Sector doesn't have a boss wave."); - } - - //TODO check for difficulty? - for(int i = 1; i <= bossWave; i++){ - int total = 0; - for(SpawnGroup spawn : spawns){ - total += spawn.getSpawned(i); - } - - assertNotEquals(0, total, "Sector " + zone + " has no spawned enemies at wave " + i); - //TODO this is flawed and needs to be changed later - //assertTrue(total < 75, "Sector spawns too many enemies at wave " + i + " (" + total + ")"); - } - - assertEquals(1, Team.sharded.cores().size, "Sector must have one core: " + zone); - assertTrue(Team.sharded.core().items.total() < 1000, "Sector must not have starting resources: " + zone); - - assertTrue(hasSpawnPoint, "Sector \"" + zone.name + "\" has no spawn points."); - assertTrue(spawner.countSpawns() > 0 || (state.rules.attackMode && state.rules.waveTeam.data().hasCore()), "Sector \"" + zone.name + "\" has no enemy spawn points: " + spawner.countSpawns()); - })); - } - - return out.toArray(DynamicTest.class); - } -} diff --git a/tests/src/test/java/power/DirectConsumerTests.java b/tests/src/test/java/power/DirectConsumerTests.java index 1b8aa04a8d..48110ee4e9 100644 --- a/tests/src/test/java/power/DirectConsumerTests.java +++ b/tests/src/test/java/power/DirectConsumerTests.java @@ -1,9 +1,18 @@ package power; +import mindustry.content.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.power.PowerGenerator.*; +import mindustry.world.blocks.power.*; +import mindustry.world.blocks.production.*; +import org.junit.jupiter.api.*; + +import static org.junit.jupiter.api.Assertions.*; + /** Tests for direct power consumers. */ public class DirectConsumerTests extends PowerTestFixture{ - //TODO reimplement -/* + @Test void noPowerRequestedWithNoItems(){ testUnitFactory(0, 0, 0.08f, 0.08f, 1f); @@ -21,26 +30,26 @@ public class DirectConsumerTests extends PowerTestFixture{ } void testUnitFactory(int siliconAmount, int leadAmount, float producedPower, float requestedPower, float expectedSatisfaction){ - Tile consumerTile = createFakeTile(0, 0, new UnitFactory("fakefactory"){{ - entityType = UnitFactoryEntity::new; - unitType = UnitTypes.spirit; - produceTime = 60; + Tile ct = createFakeTile(0, 0, new GenericCrafter("fakefactory"){{ + hasPower = true; + hasItems = true; consumes.power(requestedPower); consumes.items(new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30)); }}); - consumerTile.entity.items.add(Items.silicon, siliconAmount); - consumerTile.entity.items.add(Items.lead, leadAmount); + ct.block().init(); + ct.build.items.add(Items.silicon, siliconAmount); + ct.build.items.add(Items.lead, leadAmount); Tile producerTile = createFakeTile(2, 0, createFakeProducerBlock(producedPower)); - producerTile.ent().productionEfficiency = 1f; + ((GeneratorBuild)producerTile.build).productionEfficiency = 1f; PowerGraph graph = new PowerGraph(); - graph.add(producerTile.entity); - graph.add(consumerTile.entity); + graph.add(producerTile.build); + graph.add(ct.build); - consumerTile.entity.update(); + ct.build.update(); graph.update(); - assertEquals(expectedSatisfaction, consumerTile.entity.power.status); - }*/ + assertEquals(expectedSatisfaction, ct.build.power.status); + } } diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index 71311cda10..2c58f974be 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -24,7 +24,6 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest; * Any expected power amount (produced, consumed, buffered) should be affected by FakeThreadHandler.fakeDelta but status should not! */ public class ItemLiquidGeneratorTests extends PowerTestFixture{ - private ItemLiquidGenerator generator; private Tile tile; private ItemLiquidGeneratorBuild entity; diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 626986b5ce..b97890fed3 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -176,7 +176,7 @@ public class Generators{ for(int x = 0; x < dim; x++){ for(int y = 0; y < dim; y++){ float dst = Mathf.dst((float)x/dim, (float)y/dim, 0.5f, 0.5f) * 2f; - if(dst < 1.2f && RidgedPerlin.noise2d(1, x, y, 3, 1f / 40f) - dst*(1f-fract) > 0.16f){ + if(dst < 1.2f && Ridged.noise2d(1, x, y, 3, 1f / 40f) - dst*(1f-fract) > 0.16f){ image.setRaw(x, y, Color.whiteRgba); } } @@ -220,7 +220,7 @@ public class Generators{ TextureRegion[] regions = block.getGeneratedIcons(); - if(block.variants > 0){ + if(block.variants > 0 || block instanceof Floor){ for(TextureRegion region : block.variantRegions()){ GenRegion gen = (GenRegion)region; if(gen.path == null) continue; @@ -488,7 +488,7 @@ public class Generators{ image.each((x, y) -> { //add darker cracks on top - boolean rValue = Math.max(RidgedPerlin.noise2d(1, x, y, 3, 1f / (20f + image.width/8f)), 0) > 0.16f; + boolean rValue = Math.max(Ridged.noise2d(1, x, y, 3, 1f / (20f + image.width/8f)), 0) > 0.16f; //cut out random chunks with voronoi boolean vval = vn.noise(x, y, 1f / (14f + image.width/40f)) > 0.47; @@ -601,14 +601,11 @@ public class Generators{ /** Generates a scorch pixmap based on parameters. Thread safe, unless multiple scorch generators are running in parallel. */ public static class ScorchGenerator{ - private static final Simplex sim = new Simplex(); - public int size = 80, seed = 0, color = Color.whiteRgba; public double scale = 18, pow = 2, octaves = 4, pers = 0.4, add = 2, nscl = 4.5f; public Pixmap generate(){ Pixmap pix = new Pixmap(size, size); - sim.setSeed(seed); pix.each((x, y) -> { double dst = Mathf.dst(x, y, size/2, size/2) / (size / 2f); @@ -621,7 +618,7 @@ public class Generators{ } private double noise(float angle){ - return Math.pow(sim.octaveNoise2D(octaves, pers, 1 / scale, Angles.trnsx(angle, size/2f) + size/2f, Angles.trnsy(angle, size/2f) + size/2f), pow); + return Math.pow(Simplex.noise2d(seed, octaves, pers, 1 / scale, Angles.trnsx(angle, size/2f) + size/2f, Angles.trnsy(angle, size/2f) + size/2f), pow); } }