diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index d5bd8e3c0c..d936e4b346 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -8,6 +8,7 @@ p.load(file('../core/assets/version.properties').newReader()); return p } diff --git a/core/assets/bundles/global.properties b/core/assets/bundles/global.properties index 6cee674379..fec3bb47db 100644 --- a/core/assets/bundles/global.properties +++ b/core/assets/bundles/global.properties @@ -37,4 +37,5 @@ sector.siege.credit = hhh i 17 sector.ravine.credit = Bepis #megabase center -sector.sector-serpulo-27.name = ᒆᐴᑫᑈᐴᐾᐶᒅᑜᒆ \ No newline at end of file +sector.sector-serpulo-27.name = ᒆᐴᑫᑈᐴᐾᐶᒅᑜᒆ +threat.unreasonable = ᐰᐬᑀᐲᑚᑓᐭ \ No newline at end of file diff --git a/core/assets/maps/serpulo/hidden/111.msav b/core/assets/maps/serpulo/hidden/111.msav index a1128616b9..1c06b2ba0c 100644 Binary files a/core/assets/maps/serpulo/hidden/111.msav and b/core/assets/maps/serpulo/hidden/111.msav differ diff --git a/core/assets/maps/serpulo/hidden/13.msav b/core/assets/maps/serpulo/hidden/13.msav index 6e97fea22d..0170bf609d 100644 Binary files a/core/assets/maps/serpulo/hidden/13.msav and b/core/assets/maps/serpulo/hidden/13.msav differ diff --git a/core/assets/maps/serpulo/hidden/6.msav b/core/assets/maps/serpulo/hidden/6.msav index 973faadbcb..804c456e3d 100644 Binary files a/core/assets/maps/serpulo/hidden/6.msav and b/core/assets/maps/serpulo/hidden/6.msav differ diff --git a/core/assets/maps/serpulo/littoralShipyard.msav b/core/assets/maps/serpulo/littoralShipyard.msav index bb83ca2d6b..3e72623fed 100644 Binary files a/core/assets/maps/serpulo/littoralShipyard.msav and b/core/assets/maps/serpulo/littoralShipyard.msav differ diff --git a/core/assets/maps/serpulo/overgrowth.msav b/core/assets/maps/serpulo/overgrowth.msav index 8b4983bf26..d4b154c65e 100644 Binary files a/core/assets/maps/serpulo/overgrowth.msav and b/core/assets/maps/serpulo/overgrowth.msav differ diff --git a/core/assets/maps/serpulo/weatheredChannels.msav b/core/assets/maps/serpulo/weatheredChannels.msav index aa02ffabf7..22721327b6 100644 Binary files a/core/assets/maps/serpulo/weatheredChannels.msav and b/core/assets/maps/serpulo/weatheredChannels.msav differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 49eabe420e..ae16aff021 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -2680,6 +2680,7 @@ public class Blocks{ laserColor2 = Color.valueOf("ffd9c2"); laserScale = 0.8f; scaledHealth = 130; + useLod = false; }}; turbineCondenser = new ThermalGenerator("turbine-condenser"){{ diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 896afe4388..557351b094 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -401,6 +401,8 @@ public class Control implements ApplicationListener, Loadable{ ui.loadAnd(() -> { logic.reset(); world.loadMap(map, rules); + var oldRules = state.rules; + rules.retainContentFields(oldRules); state.rules = rules; if(playtest) state.playtestingMap = map; state.rules.sector = null; diff --git a/core/src/mindustry/ctype/Content.java b/core/src/mindustry/ctype/Content.java index 7965d8f754..312152e17c 100644 --- a/core/src/mindustry/ctype/Content.java +++ b/core/src/mindustry/ctype/Content.java @@ -65,6 +65,11 @@ public abstract class Content implements Comparable{ return !isVanilla(); } + /** @return whether this content is from a map data patch. */ + public boolean isPatchContent(){ + return minfo.mod == DataPatcher.dpMod; + } + @Override public int compareTo(Content c){ return Integer.compare(id, c.id); diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index f82eae6291..61bc01c95a 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -107,9 +107,9 @@ public class Damage{ float damagePerWave = explosiveness / 2f; for(int i = 0; i < waves; i++){ - var shields = ignoreTeam == null ? null : indexer.getEnemy(ignoreTeam, BlockFlag.shield); int f = i; Time.run(i * 2f, () -> { + var shields = ignoreTeam == null ? null : indexer.getEnemy(ignoreTeam, BlockFlag.shield); if(shields == null || shields.isEmpty() || !shields.contains(b -> b instanceof ExplosionShield s && s.absorbExplosion(x, y, damagePerWave))){ damage(ignoreTeam, x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), damagePerWave, false); } diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 1f78d6f3ee..c8778bd566 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -269,6 +269,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I case health -> health; case shield -> shield; case maxHealth -> maxHealth; + case flying -> isFlying() ? 1f : 0f; case x -> World.conv(x); case y -> World.conv(y); case velocityX -> vel.x * 60f / tilesize; diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 5216a90b36..7af81b00ca 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -245,6 +245,23 @@ public class Rules{ return JsonIO.copy(this); } + /** + * When a map is played, it uses rules from the rules dialog, which cannot contain patched content, since it doesn't exist at that point in time. + * This means that any existing rules containing patched content will contain garbage or empty data. + * This function copies original map rule data from {@param source} (obtained after map load) that may contain new content into this ruleset. + * */ + public void retainContentFields(Rules source){ + //these fields can't be modified in the custom rules anyway, so force-overwriting them is fine + spawns = source.spawns; + objectives = source.objectives; + weather = source.weather; + + //TODO: this overwrites banned blocks/units and loadouts if someone set it in custom rules when playing; there isn't a good way to avoid this + if(Seq.with(source.bannedBlocks).contains(Content::isPatchContent)) bannedBlocks = source.bannedBlocks; + if(Seq.with(source.bannedUnits).contains(Content::isPatchContent)) bannedUnits = source.bannedUnits; + if(source.loadout.contains(i -> i.item.isPatchContent())) loadout = source.loadout; + } + /** Returns the gamemode that best fits these rules. */ public Gamemode mode(){ if(pvp){ diff --git a/core/src/mindustry/graphics/Drawf.java b/core/src/mindustry/graphics/Drawf.java index 56e1333980..377b15c9e2 100644 --- a/core/src/mindustry/graphics/Drawf.java +++ b/core/src/mindustry/graphics/Drawf.java @@ -515,9 +515,13 @@ public class Drawf{ } public static void laser(TextureRegion line, TextureRegion start, TextureRegion end, float x, float y, float x2, float y2, float scale, boolean light){ + laser(line, start, end, x, y, x2, y2, scale, light, true); + } + + public static void laser(TextureRegion line, TextureRegion start, TextureRegion end, float x, float y, float x2, float y2, float scale, boolean light, boolean useLod){ float scl = 8f * scale * Draw.scl, rot = Mathf.angle(x2 - x, y2 - y); float vx = Mathf.cosDeg(rot) * scl, vy = Mathf.sinDeg(rot) * scl; - float lod = start.width * scale * start.scl() < 10f ? Lod.alpha1 : Lod.alpha2; + float lod = useLod ? (start.width * scale * start.scl() < 10f ? Lod.alpha1 : Lod.alpha2) : 1f; float a = Draw.getColorAlpha(); if(a >= 1f/255f){ diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 742216ba65..47ccd0ed5d 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -242,6 +242,7 @@ public class MenuRenderer implements Disposable{ flyerType.sample.elevation = 1f; flyerType.sample.team = Team.sharded; flyerType.sample.rotation = flyerRot; + flyerType.sample.setType(flyerType); flyerType.sample.heal(); flyers((x, y) -> { diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index c612eccd13..56cc9bf4a9 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -20,11 +20,7 @@ import java.io.*; @SuppressWarnings("unchecked") public class JsonIO{ - private static final CustomJson jsonBase = new CustomJson(); - public static final Json json = new Json(){ - { apply(this); } - @Override public void writeValue(Object value, Class knownType, Class elementType){ if(value instanceof MappableContent c){ @@ -80,8 +76,9 @@ public class JsonIO{ return json.fromJson(type, string.replace("io.anuke.", "")); } - public static T read(Class type, T base, String string){ - return jsonBase.fromBaseJson(type, base, string.replace("io.anuke.", "")); + public static T read(T base, String string){ + json.readFields(base, new JsonReader().parse(string.replace("io.anuke.", ""))); + return base; } public static String print(String in){ @@ -90,10 +87,9 @@ public class JsonIO{ public static void classTag(String tag, Class type){ json.addClassTag(tag, type); - jsonBase.addClassTag(tag, type); } - static void apply(Json json){ + static{ json.setElementType(Rules.class, "spawns", SpawnGroup.class); json.setElementType(Rules.class, "loadout", ItemStack.class); @@ -356,28 +352,4 @@ public class JsonIO{ json.addClassTag(Strings.camelize(i.getClass().getSimpleName().replace("Filter", "")), i.getClass()); } } - - static class CustomJson extends Json{ - private Object baseObject; - - { apply(this); } - - @Override - public T fromJson(Class type, String json){ - return fromBaseJson(type, null, json); - } - - public T fromBaseJson(Class type, T base, String json){ - this.baseObject = base; - return readValue(type, null, new JsonReader().parse(json)); - } - - @Override - protected Object newInstance(Class type){ - if(baseObject == null || baseObject.getClass() != type){ - return super.newInstance(type); - } - return baseObject; - } - } } \ No newline at end of file diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index ff1523aef4..52084a9cbc 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -3,7 +3,6 @@ package mindustry.io; import arc.struct.*; import arc.struct.ObjectMap.*; import arc.util.io.*; -import mindustry.world.*; import java.io.*; @@ -190,7 +189,7 @@ public abstract class SaveFileReader{ return map; } - public abstract void read(DataInputStream stream, CounterInputStream counter, WorldContext context) throws IOException; + public abstract void read(DataInputStream stream, CounterInputStream counter, SaveReadState state) throws IOException; public abstract void write(DataOutputStream stream, SaveOptions options) throws IOException; diff --git a/core/src/mindustry/io/SaveIO.java b/core/src/mindustry/io/SaveIO.java index d697b73c7c..8aec7acaef 100644 --- a/core/src/mindustry/io/SaveIO.java +++ b/core/src/mindustry/io/SaveIO.java @@ -169,7 +169,7 @@ public class SaveIO{ if(ver == null) throw new IOException("Unknown save version: " + version + ". Are you trying to load a save from a newer version?"); - ver.read(stream, counter, context); + ver.read(stream, counter, new SaveReadState(context)); Events.fire(new SaveLoadEvent(context.isMap())); }catch(Throwable e){ throw new SaveException(e); diff --git a/core/src/mindustry/io/SaveReadState.java b/core/src/mindustry/io/SaveReadState.java new file mode 100644 index 0000000000..81e1f95f6a --- /dev/null +++ b/core/src/mindustry/io/SaveReadState.java @@ -0,0 +1,13 @@ +package mindustry.io; + +import arc.util.*; +import mindustry.world.*; + +public class SaveReadState{ + public final WorldContext context; + public @Nullable String ruleString; + + public SaveReadState(WorldContext context){ + this.context = context; + } +} diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index dc7dd9162e..777afe9080 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -60,13 +60,13 @@ public abstract class SaveVersion extends SaveFileReader{ } @Override - public void read(DataInputStream stream, CounterInputStream counter, WorldContext context) throws IOException{ - readRegion("meta", stream, counter, in -> readMeta(in, context)); - if(version >= 12) readRegion("patches", stream, counter, this::readDataPatches); + public void read(DataInputStream stream, CounterInputStream counter, SaveReadState saveState) throws IOException{ + readRegion("meta", stream, counter, in -> readMeta(in, saveState)); + if(version >= 12) readRegion("patches", stream, counter, in -> readDataPatches(in, saveState)); try{ readRegion("content", stream, counter, this::readContentHeader); - readRegion("map", stream, counter, in -> readMap(in, context)); + readRegion("map", stream, counter, in -> readMap(in, saveState.context)); readRegion("entities", stream, counter, this::readEntities); if(version >= 8) readRegion("markers", stream, counter, this::readMarkers); readRegion("custom", stream, counter, this::readCustomChunks); @@ -75,6 +75,7 @@ public abstract class SaveVersion extends SaveFileReader{ } } + @Override public void write(DataOutputStream stream, SaveOptions options) throws IOException{ writeRegion("meta", stream, out -> writeMeta(out, options.extraTags)); writeRegion("patches", stream, out -> writeDataPatches(out, options.embedAssets)); @@ -148,27 +149,20 @@ public abstract class SaveVersion extends SaveFileReader{ ))); } - public void readMeta(DataInput stream, WorldContext context) throws IOException{ + public void readMeta(DataInput stream, SaveReadState saveState) throws IOException{ StringMap map = readStringMap(stream); state.wave = map.getInt("wave"); state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing); state.tick = map.getFloat("tick"); state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}")); - state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); state.mapLocales = JsonIO.read(MapLocales.class, map.get("locales", "{}")); - if(state.rules.spawns.isEmpty()) state.rules.spawns = waves.get(); - if(context.getSector() != null){ - state.rules.sector = context.getSector(); - if(state.rules.sector != null){ - state.rules.sector.planet.applyRules(state.rules); - } - } + saveState.ruleString = map.get("rules", "{}"); - //replace the default serpulo env with erekir - if(state.rules.planet == Planets.serpulo && state.rules.hasEnv(Env.scorching)){ - state.rules.planet = Planets.erekir; + //for versions >= 13, rules are parsed after data patches are loaded + if(version < 13){ + readRules(saveState); } if(!headless){ @@ -196,6 +190,25 @@ public abstract class SaveVersion extends SaveFileReader{ )) : worldmap; } + public void readRules(SaveReadState saveState){ + if(saveState.ruleString == null) return; //in NetworkIO, rules are null, not read here + state.rules = JsonIO.read(Rules.class, saveState.ruleString); + + if(state.rules.spawns.isEmpty()) state.rules.spawns = waves.get(); + + if(saveState.context.getSector() != null){ + state.rules.sector = saveState.context.getSector(); + if(state.rules.sector != null){ + state.rules.sector.planet.applyRules(state.rules); + } + } + + //replace the default serpulo env with erekir + if(state.rules.planet == Planets.serpulo && state.rules.hasEnv(Env.scorching)){ + state.rules.planet = Planets.erekir; + } + } + public void writeMap(DataOutput stream) throws IOException{ //write world size stream.writeShort(world.width()); @@ -527,7 +540,7 @@ public abstract class SaveVersion extends SaveFileReader{ readWorldEntities(stream, mapping); } - public void readDataPatches(DataInput stream) throws IOException{ + public void readDataPatches(DataInput stream, SaveReadState saveState) throws IOException{ stream.readInt(); //version - ignored for now int total = stream.readInt(); @@ -563,6 +576,9 @@ public abstract class SaveVersion extends SaveFileReader{ Events.fire(new DataPatchLoadEvent(assets)); state.data.load(assets); + + //now that patches are loaded, the rules can actually be read + readRules(saveState); } public void writeDataPatches(DataOutput stream, boolean forceEmbed) throws IOException{ diff --git a/core/src/mindustry/io/versions/LegacyRegionSaveVersion.java b/core/src/mindustry/io/versions/LegacyRegionSaveVersion.java index 4623352df2..f34a519ab4 100644 --- a/core/src/mindustry/io/versions/LegacyRegionSaveVersion.java +++ b/core/src/mindustry/io/versions/LegacyRegionSaveVersion.java @@ -1,7 +1,7 @@ package mindustry.io.versions; import arc.util.io.*; -import mindustry.world.*; +import mindustry.io.*; import java.io.*; @@ -15,12 +15,12 @@ public class LegacyRegionSaveVersion extends ShortChunkSaveVersion{ } @Override - public void read(DataInputStream stream, CounterInputStream counter, WorldContext context) throws IOException{ - readRegion("meta", stream, counter, in -> readMeta(in, context)); + public void read(DataInputStream stream, CounterInputStream counter, SaveReadState saveState) throws IOException{ + readRegion("meta", stream, counter, in -> readMeta(in, saveState)); readRegion("content", stream, counter, this::readContentHeader); try{ - readRegion("map", stream, counter, in -> readMap(in, context)); + readRegion("map", stream, counter, in -> readMap(in, saveState.context)); readRegion("entities", stream, counter, this::readEntities); }finally{ content.setTemporaryMapper(null); diff --git a/core/src/mindustry/io/versions/Save11.java b/core/src/mindustry/io/versions/Save11.java index ddf77c6b61..898d5dc405 100644 --- a/core/src/mindustry/io/versions/Save11.java +++ b/core/src/mindustry/io/versions/Save11.java @@ -7,7 +7,6 @@ import arc.util.io.*; import mindustry.game.EventType.*; import mindustry.io.*; import mindustry.mod.data.*; -import mindustry.world.*; import java.io.*; @@ -23,13 +22,13 @@ public class Save11 extends SaveVersion{ } @Override - public void read(DataInputStream stream, CounterInputStream counter, WorldContext context) throws IOException{ - readRegion("meta", stream, counter, in -> readMeta(in, context)); + public void read(DataInputStream stream, CounterInputStream counter, SaveReadState saveState) throws IOException{ + readRegion("meta", stream, counter, in -> readMeta(in, saveState)); readRegion("content", stream, counter, this::readContentHeader); try{ - readRegion("patches", stream, counter, this::readDataPatches); - readRegion("map", stream, counter, in -> readMap(in, context)); + readRegion("patches", stream, counter, in -> readDataPatches(in, saveState)); + readRegion("map", stream, counter, in -> readMap(in, saveState.context)); readRegion("entities", stream, counter, this::readEntities); readRegion("markers", stream, counter, this::readMarkers); readRegion("custom", stream, counter, this::readCustomChunks); @@ -40,7 +39,7 @@ public class Save11 extends SaveVersion{ //old, simplified string-only data patches @Override - public void readDataPatches(DataInput stream) throws IOException{ + public void readDataPatches(DataInput stream, SaveReadState saveState) throws IOException{ Seq assets = new Seq<>(); int amount = stream.readUnsignedByte(); diff --git a/core/src/mindustry/io/versions/Save12.java b/core/src/mindustry/io/versions/Save12.java index b3f117820f..b0e41f429e 100644 --- a/core/src/mindustry/io/versions/Save12.java +++ b/core/src/mindustry/io/versions/Save12.java @@ -19,7 +19,7 @@ public class Save12 extends SaveVersion{ } @Override - public void readDataPatches(DataInput stream) throws IOException{ + public void readDataPatches(DataInput stream, SaveReadState saveState) throws IOException{ stream.readInt(); //version - ignored for now Seq assets = new Seq<>(); diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java index be03d5cbfa..4173784ef2 100644 --- a/core/src/mindustry/logic/LAccess.java +++ b/core/src/mindustry/logic/LAccess.java @@ -62,6 +62,7 @@ public enum LAccess{ team, type, flag, + flying, controlled, controller, name, diff --git a/core/src/mindustry/maps/Map.java b/core/src/mindustry/maps/Map.java index 758b31aa04..fd607af2ff 100644 --- a/core/src/mindustry/maps/Map.java +++ b/core/src/mindustry/maps/Map.java @@ -100,9 +100,8 @@ public class Map implements Comparable, Publishable{ public Rules rules(Rules base){ try{ - //this replacement is a MASSIVE hack but it fixes some incorrect overwriting of team-specific rules. - //may need to be tweaked later - Rules result = JsonIO.read(Rules.class, base, tags.get("rules", "{}").replace("teams:{2:{infiniteAmmo:true}},", "")); + Rules result = JsonIO.read(base, tags.get("rules", "{}")); + //replace the default serpulo env with erekir if(result.planet == Planets.serpulo && result.hasEnv(Env.scorching)){ result.planet = Planets.erekir; @@ -110,7 +109,7 @@ public class Map implements Comparable, Publishable{ if(result.planet == null) result.planet = Planets.serpulo; if(result.spawns.isEmpty()) result.spawns = Vars.waves.get(); return result; - }catch(Exception e){ + }catch(Throwable e){ //error reading rules. ignore? Log.err(e); return new Rules(); diff --git a/core/src/mindustry/maps/SectorSubmissions.java b/core/src/mindustry/maps/SectorSubmissions.java index 5a32281406..92e6e29454 100644 --- a/core/src/mindustry/maps/SectorSubmissions.java +++ b/core/src/mindustry/maps/SectorSubmissions.java @@ -6,6 +6,7 @@ import mindustry.content.*; import mindustry.type.*; import static mindustry.content.Planets.*; +import static mindustry.type.SectorDifficulty.*; /** Class for temporarily (?) storing links to map submissions on Discord. */ public class SectorSubmissions{ @@ -24,59 +25,58 @@ public class SectorSubmissions{ } public static void registerSectors(){ - registerSerpuloSector(76, "Tyrant-classZzz", "https://discord.com/channels/391020510269669376/1379926833411391580/1479890094486716499", -1, 8f); - registerSerpuloSector(47, "tinport", "https://discord.com/channels/391020510269669376/1379926802591645820/1481778410018570274"); - registerSerpuloSector(225, "Summi", "https://discord.com/channels/391020510269669376/1379926925719376152/1419026814826709103"); - //111 has an alternate submission https://discord.com/channels/391020510269669376/1379926842659569864/1404825715244793938 - registerSerpuloSector(111, "gausofid", "https://discord.com/channels/391020510269669376/1379926842659569864/1422257393042985114"); - registerSerpuloSector(176, "wpx", "https://discord.com/channels/391020510269669376/1379926887203213353/1419025548696621209"); - registerSerpuloSector(13, "hoijlhj", "https://discord.com/channels/391020510269669376/1379926785164312810/1402569635299065948"); - registerSerpuloSector(259, "tinport", "https://discord.com/channels/391020510269669376/1379928048245280871/1381300770866987049"); - registerSerpuloSector(192, "Skeledragon", "https://discord.com/channels/391020510269669376/1379926914122256449/1380767793989029923"); - registerSerpuloSector(127, "playfree", "https://discord.com/channels/391020510269669376/1379926869465632829/1380253194428354602"); - registerSerpuloSector(207, "cyan", "https://discord.com/channels/391020510269669376/1379926923370827827/1405919087883976837"); - registerSerpuloSector(94, "Wine", "https://discord.com/channels/391020510269669376/1379926838079393802/1433736458174468197"); - registerSerpuloSector(16, "Namero", "https://discord.com/channels/391020510269669376/1379926788280680579/1409970152283312352"); - registerSerpuloSector(116, "Jamespire", "https://discord.com/channels/391020510269669376/1379926845058711734/1483297088426082336"); - registerSerpuloSector(69, "Oct", "https://discord.com/channels/391020510269669376/1379926831326822610/1406230980120940556"); - registerSerpuloSector(92, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926835621527615/1484550444369051772"); - registerSerpuloSector(197, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926916911599676/1423257237341863966"); - registerSerpuloSector(67, "Ếch ngồi đáy giếng", "https://discord.com/channels/391020510269669376/1379926828696866898/1389981795386396768"); + register(76, "Tyrant-classZzz", "https://discord.com/channels/391020510269669376/1379926833411391580/1479890094486716499", extreme); + register(47, "tinport", "https://discord.com/channels/391020510269669376/1379926802591645820/1481778410018570274", extreme); + register(225, "Summi", "https://discord.com/channels/391020510269669376/1379926925719376152/1419026814826709103", extreme); + register(111, "enwyz", "https://discord.com/channels/391020510269669376/1379926842659569864/1517216621616169084", extreme); + register(176, "wpx", "https://discord.com/channels/391020510269669376/1379926887203213353/1419025548696621209", extreme); + register(13, "chocomint", "https://discord.com/channels/391020510269669376/1379926785164312810/1518092246300229677", extreme); + register(259, "tinport", "https://discord.com/channels/391020510269669376/1379928048245280871/1381300770866987049", extreme); + register(192, "Skeledragon", "https://discord.com/channels/391020510269669376/1379926914122256449/1380767793989029923", extreme); + register(127, "playfree", "https://discord.com/channels/391020510269669376/1379926869465632829/1380253194428354602", extreme); + register(207, "cyan", "https://discord.com/channels/391020510269669376/1379926923370827827/1405919087883976837", extreme); + register(94, "Wine", "https://discord.com/channels/391020510269669376/1379926838079393802/1433736458174468197", high); + register(16, "Namero", "https://discord.com/channels/391020510269669376/1379926788280680579/1409970152283312352", high); + register(116, "Jamespire", "https://discord.com/channels/391020510269669376/1379926845058711734/1483297088426082336", high); + register(69, "Oct", "https://discord.com/channels/391020510269669376/1379926831326822610/1406230980120940556", high); + register(92, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926835621527615/1484550444369051772", high); + register(197, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926916911599676/1423257237341863966", extreme); + register(67, "Ếch ngồi đáy giếng", "https://discord.com/channels/391020510269669376/1379926828696866898/1389981795386396768", extreme); //180 has an alternate submission that may be more appropriate in terms of difficulty: https://discord.com/channels/391020510269669376/1379926889648619580/1411534650412892185 - registerSerpuloSector(180, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926889648619580/1426523800815538178"); - registerSerpuloSector(55, "Amomogus391", "https://discord.com/channels/391020510269669376/1379926823277695189/1478733623829200910"); - registerSerpuloSector(19, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926792479183019/1424375936169545730"); - registerSerpuloSector(200, "Axye", "https://discord.com/channels/391020510269669376/1379926918429806755/1419180347232485448"); + register(180, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926889648619580/1426523800815538178", extreme); + register(55, "Amomogus391", "https://discord.com/channels/391020510269669376/1379926823277695189/1478733623829200910", eradication); + register(19, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926792479183019/1424375936169545730", extreme); + register(200, "Axye", "https://discord.com/channels/391020510269669376/1379926918429806755/1419180347232485448", medium); //191 has several alternate submissions - registerSerpuloSector(191, "tinport", "https://discord.com/channels/391020510269669376/1379926912004001914/1421139764819660884"); + register(191, "tinport", "https://discord.com/channels/391020510269669376/1379926912004001914/1421139764819660884", eradication); //alternate, more difficult submission: https://discord.com/channels/391020510269669376/1379926782966497322/1416145231853781022 - registerSerpuloSector(6, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926782966497322/1437001083221184535", -1, 9f); - registerSerpuloSector(265, "Dem0", "https://discord.com/channels/391020510269669376/1379928052921929891/1450757980206137359"); - registerSerpuloSector(161, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926882203730024/1416686287204782217"); - registerSerpuloSector(24, "Stormrider", "https://discord.com/channels/391020510269669376/1379926797042581716/1419213541512187935"); - registerSerpuloSector(263, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379928050010951694/1483982628268019916"); - registerSerpuloSector(66, "quad", "https://discord.com/channels/391020510269669376/1379926825941078128/1419165493008535706"); - registerSerpuloSector(248, "iqtik123", "https://discord.com/channels/391020510269669376/1379926979129774151/1417864622412922890"); - registerSerpuloSector(133, "wpx", "https://discord.com/channels/391020510269669376/1379926871227240770/1419018550932279440"); - registerSerpuloSector(185, "quad", "https://discord.com/channels/391020510269669376/1379926892181983283/1419231958336016458"); + register(6, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926782966497322/1516634498307985460", extreme); + register(265, "Dem0", "https://discord.com/channels/391020510269669376/1379928052921929891/1450757980206137359", extreme); + register(161, "Hengryton Luck", "https://discord.com/channels/391020510269669376/1379926882203730024/1416686287204782217", extreme); + register(24, "Stormrider", "https://discord.com/channels/391020510269669376/1379926797042581716/1419213541512187935", eradication); + register(263, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379928050010951694/1518065606161862710", eradication); + register(66, "quad", "https://discord.com/channels/391020510269669376/1379926825941078128/1419165493008535706", extreme); + register(248, "iqtik123", "https://discord.com/channels/391020510269669376/1379926979129774151/1417864622412922890", high); + register(133, "wpx", "https://discord.com/channels/391020510269669376/1379926871227240770/1419018550932279440", extreme); + register(185, "quad", "https://discord.com/channels/391020510269669376/1379926892181983283/1419231958336016458", high); //alternate submission: https://discord.com/channels/391020510269669376/1379928045577703424/1426592904767475745 - registerSerpuloSector(254, "wpx", "https://discord.com/channels/391020510269669376/1379928045577703424/1420456601667502193"); - registerSerpuloSector(0, "iqtik123", "https://discord.com/channels/391020510269669376/1379926780860698784/1482671494268977341"); - registerSerpuloSector(30, "cyan", "https://discord.com/channels/391020510269669376/1379926800854945823/1423932799647481910"); - registerSerpuloSector(20, "Namero", "https://discord.com/channels/391020510269669376/1379926794114961634/1406768731471872162"); - registerSerpuloSector(162, "Bravo Tizmo", "https://discord.com/channels/391020510269669376/1379926884606808247/1443239231366500415"); - registerSerpuloSector(230, "Jamespire", "https://discord.com/channels/391020510269669376/1379926927585841163/1483113630202335447"); - registerSerpuloSector(240, "hhhi17", "https://discord.com/channels/391020510269669376/1253758616117186590/1253758616117186590", -1, 8f); - registerSerpuloSector(202, "D&X", "https://discord.com/channels/391020510269669376/1253760205091635201/1253760205091635201", 33, 6f); + register(254, "wpx", "https://discord.com/channels/391020510269669376/1379928045577703424/1420456601667502193", eradication); + register(0, "iqtik123", "https://discord.com/channels/391020510269669376/1379926780860698784/1482671494268977341", extreme); + register(30, "cyan", "https://discord.com/channels/391020510269669376/1379926800854945823/1423932799647481910", eradication); + register(20, "Namero", "https://discord.com/channels/391020510269669376/1379926794114961634/1406768731471872162", extreme); + register(162, "Bravo Tizmo", "https://discord.com/channels/391020510269669376/1379926884606808247/1443239231366500415", eradication); + register(230, "Jamespire", "https://discord.com/channels/391020510269669376/1379926927585841163/1483113630202335447", high); + register(240, "hhhi17", "https://discord.com/channels/391020510269669376/1253758616117186590/1253758616117186590", extreme); + registerSurvival(202, "D&X", "https://discord.com/channels/391020510269669376/1253760205091635201/1253760205091635201", 33, high); //megabases - registerSerpuloSector(246, "enwyz", "https://discord.com/channels/391020510269669376/1379926839559979030/1429203869514207255"); - registerSerpuloSector(244, "Chocomint", "https://discord.com/channels/391020510269669376/1379926929636851812/1474447354982563840"); - registerSerpuloSector(242, "cyan", "https://discord.com/channels/391020510269669376/1379926873152164004/1470268689201889464"); - registerSerpuloSector(243, "Jamespire", "https://discord.com/channels/391020510269669376/1379926876457537547/1484013941477609543"); - registerSerpuloSector(247, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926976361533752/1431827990295220266"); - registerSerpuloSector(245, "Grushashusha", "https://discord.com/channels/391020510269669376/1379926971286290584/1485245072034365462"); - registerSerpuloSector(27, "Stormrider", "https://discord.com/channels/391020510269669376/1379926798833287289/1451252137224044722", -1, 10) + register(246, "enwyz", "https://discord.com/channels/391020510269669376/1379926839559979030/1429203869514207255", eradication); + register(244, "Chocomint", "https://discord.com/channels/391020510269669376/1379926929636851812/1474447354982563840", eradication); + register(242, "cyan", "https://discord.com/channels/391020510269669376/1379926873152164004/1470268689201889464", eradication); + register(243, "Jamespire", "https://discord.com/channels/391020510269669376/1379926876457537547/1484013941477609543", eradication); + register(247, "Locla^Glass", "https://discord.com/channels/391020510269669376/1379926976361533752/1431827990295220266", eradication); + register(245, "Grushashusha", "https://discord.com/channels/391020510269669376/1379926971286290584/1485245072034365462", eradication); + register(27, "Stormrider", "https://discord.com/channels/391020510269669376/1379926798833287289/1451252137224044722", unreasonable) .showHidden = true; Planets.serpulo.sectors.get(27).preset.shieldSectors.addAll(Planets.serpulo.sectors.get(246), Planets.serpulo.sectors.get(244), Planets.serpulo.sectors.get(242)); @@ -86,18 +86,18 @@ public class SectorSubmissions{ requireUnlock = false; //showHidden = true; captureWave = 70; - difficulty = 9; + difficulty = extreme; }}; new SectorPreset("geothermalStronghold", serpulo, 264){{ requireUnlock = false; - difficulty = 10; + difficulty = eradication; //showHidden = true; }}; new SectorPreset("cruxscape", serpulo, 54){{ requireUnlock = false; - difficulty = 10; + difficulty = eradication; //showHidden = true; }}; @@ -113,11 +113,15 @@ public class SectorSubmissions{ );*/ } - static SectorPreset registerSerpuloSector(int id, String author, String mapFileLink){ - return registerSerpuloSector(id, author, mapFileLink, -1, 0f); + static SectorPreset register(int id, String author, String mapFileLink, int difficulty){ + return registerSector(id, author, mapFileLink, -1, difficulty); } - static SectorPreset registerSerpuloSector(int id, String author, String mapFileLink, int captureWave, float difficulty){ + static SectorPreset registerSurvival(int id, String author, String mapFileLink, int captureWave, float difficulty){ + return registerSector(id, author, mapFileLink, captureWave, difficulty); + } + + static SectorPreset registerSector(int id, String author, String mapFileLink, int captureWave, float difficulty){ Planet planet = Planets.serpulo; Sector sector = planet.sectors.get(id); MapSubmission sub = threadMap.get(sector, MapSubmission::new); diff --git a/core/src/mindustry/mod/ClassMap.java b/core/src/mindustry/mod/ClassMap.java index 0fea69fed6..d26b654bf3 100644 --- a/core/src/mindustry/mod/ClassMap.java +++ b/core/src/mindustry/mod/ClassMap.java @@ -117,6 +117,7 @@ public class ClassMap{ classes.put("Publishable", mindustry.type.Publishable.class); classes.put("Sector", mindustry.type.Sector.class); classes.put("SectorRect", mindustry.type.Sector.SectorRect.class); + classes.put("SectorDifficulty", mindustry.type.SectorDifficulty.class); classes.put("SectorPreset", mindustry.type.SectorPreset.class); classes.put("StatusEffect", mindustry.type.StatusEffect.class); classes.put("TransitionHandler", mindustry.type.StatusEffect.TransitionHandler.class); diff --git a/core/src/mindustry/mod/DataPatcher.java b/core/src/mindustry/mod/DataPatcher.java index 773ccfdf11..e4775905d2 100644 --- a/core/src/mindustry/mod/DataPatcher.java +++ b/core/src/mindustry/mod/DataPatcher.java @@ -29,6 +29,12 @@ import java.util.*; /** The current implementation is awful. Consider it a proof of concept. */ @SuppressWarnings("unchecked") public class DataPatcher{ + private static ModMeta dpModMeta = new ModMeta(){{ + name = internalName = "dp"; + }}; + + public static final LoadedMod dpMod = new LoadedMod(new Fi("dp"), new Fi(""), null, null, dpModMeta); + public static final int maxImageSize = 2000; public static final int patchFormatVersion = 2; @@ -37,10 +43,7 @@ public class DataPatcher{ private static final ObjectMap nameToType = new ObjectMap<>(); private static DataPatcher currentDataPatcher; private static ContentParser parser = createParser(); - private static ModMeta dpModMeta = new ModMeta(){{ - name = internalName = "dp"; - }}; - private static LoadedMod dpMod = new LoadedMod(new Fi("dp"), new Fi(""), null, null, dpModMeta); + private boolean applied; private ContentLoader contentLoader; diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index 5d9dd46ac9..ac8eec8209 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -42,6 +42,9 @@ public class NetworkIO{ } } + //data patches must be first, as rules can involve patched content + SaveIO.getSaveWriter().writeDataPatches(stream, false); + stream.writeUTF(JsonIO.write(state.rules)); stream.writeUTF(JsonIO.write(state.mapLocales)); SaveIO.getSaveWriter().writeStringMap(stream, state.map.tags); @@ -55,7 +58,6 @@ public class NetworkIO{ stream.writeInt(player.id); player.write(new Writes(stream)); - SaveIO.getSaveWriter().writeDataPatches(stream, false); SaveIO.getSaveWriter().writeContentHeader(stream); SaveIO.getSaveWriter().writeMap(stream); SaveIO.getSaveWriter().writeTeamBlocks(stream); @@ -70,6 +72,8 @@ public class NetworkIO{ try(DataInputStream stream = new DataInputStream(is)){ Time.clear(); + SaveIO.getSaveWriter().readDataPatches(stream, new SaveReadState(world.context)); + state.rules = JsonIO.read(Rules.class, stream.readUTF()); state.mapLocales = JsonIO.read(MapLocales.class, stream.readUTF()); state.map = new Map(SaveIO.getSaveWriter().readStringMap(stream)); @@ -89,7 +93,6 @@ public class NetworkIO{ player.id = id; player.add(); - SaveIO.getSaveWriter().readDataPatches(stream); SaveIO.getSaveWriter().readContentHeader(stream); SaveIO.getSaveWriter().readMap(stream, world.context); SaveIO.getSaveWriter().readTeamBlocks(stream); diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index b76fceb312..9219281b72 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -21,6 +21,7 @@ import static mindustry.Vars.*; /** A small section of a planet. */ public class Sector{ + static final String[] threats = {"low", "medium", "high", "extreme", "eradication"}; private static final Seq tmpSeq1 = new Seq<>(); public final SectorRect rect; @@ -79,9 +80,8 @@ public class Sector{ public String displayThreat(){ float step = 0.25f; String color = Tmp.c1.set(Color.white).lerp(Color.scarlet, Mathf.round(threat, step)).toString(); - String[] threats = {"low", "medium", "high", "extreme", "eradication"}; - int index = Math.min((int)(threat / step), threats.length - 1); - return "[#" + color + "]" + Core.bundle.get("threat." + threats[index]); + //TODO: rework this in the future + return "[#" + color + "]" + Core.bundle.get("threat." + (preset != null && Mathf.equal(preset.difficulty, SectorDifficulty.unreasonable) ? "unreasonable" : threats[Math.min((int)(threat / step), threats.length - 1)])); } /** @return whether this sector can be landed on at all. diff --git a/core/src/mindustry/type/SectorDifficulty.java b/core/src/mindustry/type/SectorDifficulty.java new file mode 100644 index 0000000000..c5d05612d3 --- /dev/null +++ b/core/src/mindustry/type/SectorDifficulty.java @@ -0,0 +1,14 @@ +package mindustry.type; + +/** Note: Don't use this class; difficulty will be reworked in v9 to use specific discrete values instead of arbitrary numbers. */ +public class SectorDifficulty{ + /** Note that these values represent the minimum integer value. Thus, low would be 0-2, medium would be 3-4, etc. */ + public static final int + low = 0, + medium = 3, + high = 5, + extreme = 8, + eradication = 10, + //special difficulty reserved for 27 + unreasonable = 13; +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 9f5953937f..f4053e1235 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -1435,6 +1435,7 @@ public class UnitType extends UnlockableContent implements Senseable{ case armor -> armor; case range -> World.conv(maxRange); case size -> hitSize / tilesize; + case flying -> flying ? 1f : 0f; case itemCapacity -> itemCapacity; case speed -> speed * 60f / tilesize; case payloadCapacity -> sample instanceof Payloadc ? payloadCapacity / tilePayload : 0f; diff --git a/core/src/mindustry/ui/dialogs/ResearchDialog.java b/core/src/mindustry/ui/dialogs/ResearchDialog.java index d3ffe9546d..46bc62f21b 100644 --- a/core/src/mindustry/ui/dialogs/ResearchDialog.java +++ b/core/src/mindustry/ui/dialogs/ResearchDialog.java @@ -248,19 +248,24 @@ public class ResearchDialog extends BaseDialog{ public void add(Item item, int amount){ //only have custom removal logic for when the sequence gets items taken out of it (e.g. research) if(amount < 0){ + Sector curSector = state.isCampaign() ? state.rules.sector : null; //remove items from each sector's storage, one by one //negate amount since it's being *removed* - this makes it positive amount = -amount; - //% that gets removed from each sector - double percentage = (double)amount / get(item); + //% that gets removed from each sector except the current one + double percentage = (double)amount / Math.max(get(item) - (curSector != null && cache.get(curSector) != null ? cache.get(curSector).get(item) : 0), 1); int[] counter = {amount}; + cache.each((sector, seq) -> { - if(counter[0] == 0) return; + if(counter[0] == 0 || sector == curSector) return; + + int available = seq.get(item); + if(available <= 0) return; //amount that will be removed - int toRemove = Math.min((int)Math.ceil(percentage * seq.get(item)), counter[0]); + int toRemove = Math.min(counter[0], Math.min((int)Math.ceil(percentage * available), available)); //actually remove it from the sector sector.removeItem(item, toRemove); @@ -269,6 +274,19 @@ public class ResearchDialog extends BaseDialog{ counter[0] -= toRemove; }); + //only consume from the active sector last + if(counter[0] > 0 && curSector != null){ + var seq = cache.get(curSector); + if(seq != null){ + int toRemove = Math.min(seq.get(item), counter[0]); + + curSector.removeItem(item, toRemove); + seq.remove(item, toRemove); + + counter[0] -= toRemove; + } + } + //negate again to display correct number amount = -amount; } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index f3d0ac485c..3db5a8ebcd 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -810,38 +810,56 @@ public class Tile implements Position, QuadTreeObject, Displayable{ if(positions == null) return; staleGraphs.clear(); + tileSet.clear(); for(int pos : positions){ var build = world.build(pos); if(build != null){ + var power = build.power; if(build.power != null){ staleGraphs.add(build.power.graph.getID()); + + for(int i = 0; i < power.links.size; i++){ + var other = world.build(power.links.items[i]); + if(other != null && other.power != null){ + tileSet.add(other); + staleGraphs.add(other.power.graph.getID()); + } + } } build.changeTeam(team, false); } } + for(var external : tileSet){ + reflowPower(team, external); + } + //update power graphs in a second pass for(int pos : positions){ var build = world.build(pos); - if(build != null && build.power != null && staleGraphs.contains(build.power.graph.getID())){ - for(int i = 0; i < build.power.links.size; i++){ - var other = world.build(build.power.links.items[i]); + reflowPower(team, build); + } + } - //only reflow links that were connected to the old power graph; ones that have a new one were already covered. - if(other != null && other.team != team && other.power != null && staleGraphs.contains(other.power.graph.getID())){ - build.power.links.removeIndex(i); - other.power.links.removeValue(build.pos()); + private static void reflowPower(Team team, Building build){ + if(build != null && build.power != null && staleGraphs.contains(build.power.graph.getID())){ + for(int i = 0; i < build.power.links.size; i++){ + var other = world.build(build.power.links.items[i]); - new PowerGraph().reflow(other); + //only reflow links that were connected to the old power graph; ones that have a new one were already covered. + if(other != null && other.team != team && other.power != null && staleGraphs.contains(other.power.graph.getID())){ + build.power.links.removeIndex(i); + other.power.links.removeValue(build.pos()); - i --; - } + new PowerGraph().reflow(other); + + i --; } - new PowerGraph().reflow(build); - - build.updatePowerGraph(); } + new PowerGraph().reflow(build); + + build.updatePowerGraph(); } } diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index 7872afbca5..983b85c392 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -514,6 +514,7 @@ public class LogicBlock extends Block{ var cur = world.build(l.x, l.y); boolean valid = validLink(cur); + Block lastBlock = (l.lastBuild == null ? null : l.lastBuild.block); if(l.lastBuild == null) l.lastBuild = cur; if(valid != l.valid || l.lastBuild != cur){ l.lastBuild = cur; @@ -523,6 +524,13 @@ public class LogicBlock extends Block{ l.trySet(executor, null); //always clear old variable, it may get a new name if(valid){ + + if(lastBlock != null && cur.block != lastBlock){ + l.logicVar = null; //name was reassigned because block type changed, the old cached logic var is no longer relevant + l.name = ""; + l.name = findLinkName(cur.block); + } + //remove redundant links links.removeAll(o -> { boolean remove = world.build(o.x, o.y) == cur && o != l; diff --git a/core/src/mindustry/world/blocks/power/PowerGraph.java b/core/src/mindustry/world/blocks/power/PowerGraph.java index dd86bec9c9..f37fa08a66 100644 --- a/core/src/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/mindustry/world/blocks/power/PowerGraph.java @@ -376,10 +376,6 @@ public class PowerGraph{ if(entity != null) entity.remove(); } - public int getId(){ - return graphID; - } - @Override public String toString(){ return "PowerGraph{" + diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 9b91313ea4..56cf029aeb 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -34,6 +34,7 @@ public class PowerNode extends PowerBlock{ public int maxNodes = 3; public boolean autolink = true, drawRange = true, sameBlockConnection = false; public float laserScale = 0.25f; + public boolean useLod = true; public float powerLayer = Layer.power; public Color laserColor1 = Color.white; public Color laserColor2 = Pal.powerLight; @@ -180,7 +181,7 @@ public class PowerNode extends PowerBlock{ } protected void setupColor(float satisfaction){ - Draw.color(Tmp.c1.set(laserColor1).lerp(laserColor2, (1f - satisfaction) * 0.86f + Mathf.absin(3f, 0.1f)).a(Renderer.laserOpacity * Lod.alpha2)); + Draw.color(Tmp.c1.set(laserColor1).lerp(laserColor2, (1f - satisfaction) * 0.86f + Mathf.absin(3f, 0.1f)).a(Renderer.laserOpacity * (useLod ? Lod.alpha2 : 1f))); } public void drawLaser(float x1, float y1, float x2, float y2, int size1, int size2){ @@ -192,7 +193,7 @@ public class PowerNode extends PowerBlock{ vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1), len1 = size1 * tilesize / 2f - 1.5f, len2 = size2 * tilesize / 2f - 1.5f; - Drawf.laser(laser, laserEnd, laserEnd, x1 + vx*len1, y1 + vy*len1, x2 - vx*len2, y2 - vy*len2, laserScale, light); + Drawf.laser(laser, laserEnd, laserEnd, x1 + vx*len1, y1 + vy*len1, x2 - vx*len2, y2 - vy*len2, laserScale, light, useLod); } protected boolean overlaps(float srcx, float srcy, Tile other, Block otherBlock, float range){ diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index f97249c6c7..29c5cda7bc 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -318,7 +318,20 @@ public class DesktopLauncher extends ClientLauncher{ CrashHandler.handle(e, file -> { Throwable fc = Strings.getFinalCause(e); if(!fbgp){ - message(causeString + "\nThe logs have been saved in:\n" + file.getAbsolutePath() + "\n" + fc.getClass().getSimpleName().replace("Exception", "") + (fc.getMessage() == null ? "" : ":\n" + fc.getMessage())); + String firstStackTraces = ""; + + try{ + var s = Seq.with(fc.getStackTrace()); + s.removeAll(st -> st.getClassName().contains("MethodAccessor") || st.getClassName().substring(st.getClassName().lastIndexOf(".") + 1).equals("Method")); + s.truncate(3); + firstStackTraces = "\n" + s.toString("\n", st -> { + String className = st.getClassName(); + return className.substring(className.lastIndexOf(".") + 1) + "." + st.getMethodName() + ": " + st.getLineNumber(); + }); + }catch(Throwable ignored){ + } + + message(causeString + "\nThe logs have been saved in:\n" + file.getAbsolutePath() + "\n" + fc.getClass().getSimpleName().replace("Exception", "") + (fc.getMessage() == null ? "" : ":\n" + fc.getMessage()) + firstStackTraces); } }); }