Merge branch 'master' of https://github.com/Anuken/Mindustry into array-textures

# Conflicts:
#	gradle.properties
This commit is contained in:
Anuken
2026-07-02 10:15:54 -04:00
40 changed files with 269 additions and 157 deletions
+1
View File
@@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:enableOnBackInvokedCallback="false"
android:resizeableActivity="true"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
+1 -1
View File
@@ -43,7 +43,7 @@ allprojects{
if(!project.hasProperty("versionType")) versionType = 'official'
appName = 'Mindustry'
steamworksVersion = '0b86023401880bb5e586bc404bedbaae9b1f1c94'
rhinoVersion = '54b75cbd1207ef1fd5cff517cbd188e763c85baa'
rhinoVersion = 'e74ac129d2bff72c1deb536d7d99a0dbb7046d2e'
loadVersionProps = {
return new Properties().with{p -> p.load(file('../core/assets/version.properties').newReader()); return p }
+2 -1
View File
@@ -37,4 +37,5 @@ sector.siege.credit = hhh i 17
sector.ravine.credit = Bepis
#megabase center
sector.sector-serpulo-27.name = ᒆᐴᑫᑈᐴᐾᐶᒅᑜᒆ
sector.sector-serpulo-27.name = ᒆᐴᑫᑈᐴᐾᐶᒅᑜᒆ
threat.unreasonable = ᐰᐬᑀᐲᑚᑓᐭ
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -2680,6 +2680,7 @@ public class Blocks{
laserColor2 = Color.valueOf("ffd9c2");
laserScale = 0.8f;
scaledHealth = 130;
useLod = false;
}};
turbineCondenser = new ThermalGenerator("turbine-condenser"){{
+2
View File
@@ -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;
+5
View File
@@ -65,6 +65,11 @@ public abstract class Content implements Comparable<Content>{
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);
+1 -1
View File
@@ -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);
}
@@ -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;
+17
View File
@@ -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){
+5 -1
View File
@@ -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){
@@ -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) -> {
+4 -32
View File
@@ -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> T read(Class<T> type, T base, String string){
return jsonBase.fromBaseJson(type, base, string.replace("io.anuke.", ""));
public static <T> 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> T fromJson(Class<T> type, String json){
return fromBaseJson(type, null, json);
}
public <T> T fromBaseJson(Class<T> 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;
}
}
}
+1 -2
View File
@@ -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;
+1 -1
View File
@@ -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);
+13
View File
@@ -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;
}
}
+33 -17
View File
@@ -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{
@@ -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);
+5 -6
View File
@@ -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<DataAsset> assets = new Seq<>();
int amount = stream.readUnsignedByte();
+1 -1
View File
@@ -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<DataAsset> assets = new Seq<>();
+1
View File
@@ -62,6 +62,7 @@ public enum LAccess{
team,
type,
flag,
flying,
controlled,
controller,
name,
+3 -4
View File
@@ -100,9 +100,8 @@ public class Map implements Comparable<Map>, 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<Map>, 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();
+57 -53
View File
@@ -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);
+1
View File
@@ -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);
+7 -4
View File
@@ -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<String, ContentType> 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;
+5 -2
View File
@@ -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);
+3 -3
View File
@@ -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<Sector> 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.
@@ -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;
}
+1
View File
@@ -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;
@@ -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;
}
+31 -13
View File
@@ -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();
}
}
@@ -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;
@@ -376,10 +376,6 @@ public class PowerGraph{
if(entity != null) entity.remove();
}
public int getId(){
return graphID;
}
@Override
public String toString(){
return "PowerGraph{" +
@@ -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){
@@ -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);
}
});
}