From 93f630bb6917450d2a59b10b0f5df52f784fab18 Mon Sep 17 00:00:00 2001 From: GlennFolker <63218676+GlennFolker@users.noreply.github.com> Date: Sun, 8 Jan 2023 01:48:28 +0700 Subject: [PATCH] Make custom Env flag reliably possible (#8019) * Make custom Env flag reliably possible * screw you * "compatibility" for mods that don't use add() --- core/src/mindustry/io/JsonIO.java | 25 ++++++++ core/src/mindustry/world/meta/Env.java | 73 ++++++++++++++++++++--- tests/src/test/java/ApplicationTests.java | 4 +- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 0102151cf9..139be6c8c6 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -2,6 +2,7 @@ package mindustry.io; import arc.graphics.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import arc.util.serialization.*; import arc.util.serialization.Json.*; @@ -78,6 +79,30 @@ public class JsonIO{ json.setElementType(Rules.class, "spawns", SpawnGroup.class); json.setElementType(Rules.class, "loadout", ItemStack.class); + json.setSerializer(Rules.class, new Serializer<>(){ + @Override + public void write(Json json, Rules object, Class knownType){ + json.writeObjectStart(); + json.writeFields(object); + json.writeValue("envMapping", Env.idToName, IntMap.class); + json.writeObjectEnd(); + } + + @Override + public Rules read(Json json, JsonValue jsonData, Class type){ + Rules out = new Rules(); + json.readFields(out, jsonData); + + // Older Rules data doesn't have env mapping. + if(jsonData.has("envMapping")){ + IntMap idToName = json.readValue(IntMap.class, jsonData.get("envMapping")); + out.env = Env.remap(out.env, idToName); + } + + return out; + } + }); + json.setSerializer(Color.class, new Serializer<>(){ @Override public void write(Json json, Color object, Class knownType){ diff --git a/core/src/mindustry/world/meta/Env.java b/core/src/mindustry/world/meta/Env.java index ba7d0fa1ce..7ea5010a54 100644 --- a/core/src/mindustry/world/meta/Env.java +++ b/core/src/mindustry/world/meta/Env.java @@ -1,26 +1,83 @@ package mindustry.world.meta; +import arc.struct.*; +import arc.util.*; + /** Environmental flags for different types of locations. */ public class Env{ public static final int //is on a planet - terrestrial = 1, + terrestrial, //is in space, no atmosphere - space = 1 << 1, + space, //is underwater, on a planet - underwater = 1 << 2, + underwater, //has a spores - spores = 1 << 3, + spores, //has a scorching env effect - scorching = 1 << 4, + scorching, //has oil reservoirs - groundOil = 1 << 5, + groundOil, //has water reservoirs - groundWater = 1 << 6, + groundWater, //has oxygen in the atmosphere - oxygen = 1 << 7, + oxygen, //all attributes combined, only used for bitmasking purposes any = 0xffffffff, //no attributes (0) none = 0; + + //do NOT modify directly! + public static final ObjectIntMap nameToId; + public static final IntMap idToName; + + static{ + //last time i didn't use a static initializer i got a null pointer. + //i can probably just move the fields around, but i don't trust java enough for that + nameToId = new ObjectIntMap<>(); + idToName = new IntMap<>(); + + terrestrial = add("terrestrial"); + space = add("space"); + underwater = add("underwater"); + spores = add("spores"); + scorching = add("scorching"); + groundOil = add("groundOil"); + groundWater = add("groundWater"); + oxygen = add("oxygen"); + } + + public static int add(String key){ + if(nameToId.containsKey(key)) throw new IllegalArgumentException("'" + key + "' env already exists."); + if(nameToId.size >= 32) throw new IllegalStateException("Max env count 32 exceeded."); + + int id = 1 << nameToId.size; + nameToId.put(key, id); + idToName.put(id, key); + return id; + } + + public static int remap(int mask, IntMap idToName){ + int out = 0; + for(int i = 0; i < 32; i++){ + int key = 1 << i; + if((mask & key) == key){ + String name = idToName.get(key); + if(name == null){ + //if it's unmapped it's probably just some mods using constant value + out |= key; + continue; + } + + int id = nameToId.get(name, -1); + if(id == -1){ + Log.warn("Ignoring '@' env key.", name); + }else{ + out |= id; + } + } + } + + return out; + } } diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index b5ace3cd55..1885a31d94 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -190,7 +190,7 @@ public class ApplicationTests{ @Test void writeRules(){ - ByteBuffer buffer = ByteBuffer.allocate(500); + ByteBuffer buffer = ByteBuffer.allocate(1000); Rules rules = new Rules(); rules.attackMode = true; @@ -981,4 +981,4 @@ public class ApplicationTests{ tile.build.handleStack(item, 1, unit); assertEquals(capacity, tile.build.items.get(item)); } -} \ No newline at end of file +}