This commit is contained in:
Daniel Mills 2020-01-11 03:54:51 -05:00
parent 1c3ad6a925
commit acaf95c017
28 changed files with 624 additions and 70 deletions

View File

@ -2,7 +2,6 @@ package ninja.bytecode.iris;
import java.io.File;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Sound;
import org.bukkit.World;
@ -112,7 +111,7 @@ public class CommandIris implements CommandExecutor
if(args[0].equalsIgnoreCase("reload"))
{
msg(sender, "Reloading Iris...");
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> Iris.instance.reload());
Iris.instance.reload();
}
if(args[0].equalsIgnoreCase("clean"))

View File

@ -63,8 +63,10 @@ public class Iris extends JavaPlugin implements Listener
public void reload()
{
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
onDisable();
onEnable();
});
}
@SuppressWarnings("unchecked")

View File

@ -1,6 +1,7 @@
package ninja.bytecode.iris;
import ninja.bytecode.iris.util.PerformanceMode;
import ninja.bytecode.iris.util.PlacerType;
public class Settings
{
@ -10,11 +11,12 @@ public class Settings
public static class PerformanceSettings
{
public PerformanceMode performanceMode = PerformanceMode.DOUBLE_CPU;
public int threadCount = 1;
public PlacerType placerType = PlacerType.BUKKIT_NO_PHYSICS;
public int threadPriority = Thread.MIN_PRIORITY;
public int compilerPriority = Thread.MIN_PRIORITY;
public int threadCount = 1;
public boolean debugMode = true;
public int compilerThreads = 12;
public int compilerPriority = Thread.MAX_PRIORITY;
public int decorationAccuracy = 1;
}

View File

@ -7,7 +7,9 @@ import org.bukkit.World;
import org.bukkit.entity.Player;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.IrisController;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.execution.J;
@ -35,6 +37,15 @@ public class DebugController implements IrisController
if(Iris.settings.performance.debugMode)
{
GSet<String> ws = new GSet<>();
GList<World> destroy = new GList<>();
for(World i : Bukkit.getWorlds())
{
if(i.getGenerator() instanceof IrisGenerator)
{
destroy.add(i);
}
}
World w = Iris.getController(WorldController.class).createIrisWorld(null, 0, true);
for(Player i : Bukkit.getOnlinePlayers())
@ -50,6 +61,13 @@ public class DebugController implements IrisController
{
Bukkit.unloadWorld(i, false);
}
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
for(World i : destroy.copy())
{
Bukkit.unloadWorld(i, false);
}
}, 20);
}
}, 1);
});

View File

@ -201,6 +201,13 @@ public class PackController implements IrisController
else
{
L.f(ChatColor.RED + "Cannot find Resource: " + ChatColor.YELLOW + internal.getAbsolutePath());
if(internal.getName().equals("manifest.json"))
{
L.f(ChatColor.RED + "Reloading Iris to fix manifest jar issues");
Iris.instance.reload();
}
return null;
}
}

View File

@ -35,7 +35,7 @@ public class WandController implements IrisController
@Override
public void onStart()
{
//TODO: Optimize
// TODO: Optimize
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
for(Player i : Bukkit.getOnlinePlayers())
@ -167,7 +167,7 @@ public class WandController implements IrisController
public static void pasteSchematic(GenObject s, Location at)
{
s.place(at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ());
s.place(at);
}
@SuppressWarnings("deprecation")
@ -196,9 +196,7 @@ public class WandController implements IrisController
byte data = b.getData();
BlockVector bv = b.getLocation().subtract(c.getCenter()).toVector().toBlockVector();
s.put(bv.getBlockX(),
bv.getBlockY(),
bv.getBlockZ(),
s.put(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(),
new MB(b.getType(), data));
}

View File

@ -31,6 +31,11 @@ public class WorldController implements IrisController
});
}
public boolean isChunkGenerated(World w, int x, int z)
{
return w.loadChunk(x, z, false);
}
@Override
public void onStop()
{

View File

@ -11,11 +11,12 @@ import java.util.zip.GZIPInputStream;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.util.Direction;
import ninja.bytecode.iris.util.IPlacer;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.VectorMath;
import ninja.bytecode.shuriken.collections.GList;
@ -203,10 +204,19 @@ public class GenObject
return g % 2 == 0 ? m : m + 1;
}
@SuppressWarnings("deprecation")
public void place(World source, int wx, int wy, int wz)
public void place(Location l)
{
Location start = new Location(source, wx, wy, wz).clone().add(sh(w), sh(h) + 1, sh(d));
place(l, Iris.settings.performance.placerType.get(l.getWorld()));
}
public void place(Location l, IPlacer placer)
{
place(l.getBlockX(), l.getBlockY(), l.getBlockZ(), placer);
}
public void place(int wx, int wy, int wz, IPlacer placer)
{
Location start = new Location(placer.getWorld(), wx, wy, wz).clone().add(sh(w), sh(h) + 1, sh(d));
if(mount == null)
{
@ -215,7 +225,7 @@ public class GenObject
start.subtract(mount);
int highestY = source.getHighestBlockYAt(start);
int highestY = placer.getHighestY(start);
if(start.getBlockY() + mountHeight > highestY)
{
@ -236,11 +246,12 @@ public class GenObject
Location f = start.clone().add(i);
if(i.getBlockY() == mountHeight && f.clone().subtract(0, 1, 0).getBlock().isLiquid())
Material m = placer.get(f.clone().subtract(0, 1, 0)).material;
if(i.getBlockY() == mountHeight && (m.equals(Material.WATER) || m.equals(Material.STATIONARY_WATER) || m.equals(Material.LAVA) || m.equals(Material.STATIONARY_LAVA)))
{
for(Location j : undo.k())
{
source.getBlockAt(j.getBlockX(), j.getBlockY(), j.getBlockZ()).setTypeIdAndData(undo.get(j).material.getId(), undo.get(j).data, false);
placer.set(j, undo.get(j));
}
return;
@ -253,8 +264,8 @@ public class GenObject
try
{
undo.put(f, MB.of(f.getBlock().getType(), f.getBlock().getData()));
source.getBlockAt(f.getBlockX(), f.getBlockY(), f.getBlockZ()).setTypeIdAndData(b.material.getId(), b.data, false);
undo.put(f, placer.get(f));
placer.set(f, b);
}
catch(Throwable e)

View File

@ -16,6 +16,7 @@ import ninja.bytecode.iris.controller.PackController;
import ninja.bytecode.iris.controller.TimingsController;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.IPlacer;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.collections.GSet;
import ninja.bytecode.shuriken.logging.L;
@ -25,6 +26,7 @@ public class GenObjectDecorator extends BlockPopulator
{
private GMap<Biome, IrisBiome> biomeMap;
private GMap<Biome, GMap<GenObjectGroup, Double>> populationCache;
private IPlacer placer;
public GenObjectDecorator(IrisGenerator generator)
{
@ -109,7 +111,12 @@ public class GenObjectDecorator extends BlockPopulator
return;
}
i.getSchematics().get(random.nextInt(i.getSchematics().size())).place(world, x, b.getY(), z);
if(placer == null)
{
placer = Iris.settings.performance.placerType.get(world);
}
i.getSchematics().get(random.nextInt(i.getSchematics().size())).place(x, b.getY(), z, placer);
}
}
}

View File

@ -0,0 +1,38 @@
package ninja.bytecode.iris.util;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
public class BukkitPlacer extends Placer
{
private final boolean applyPhysics;
public BukkitPlacer(World world, boolean applyPhysics)
{
super(world);
this.applyPhysics = applyPhysics;
}
@SuppressWarnings("deprecation")
@Override
public MB get(Location l)
{
Block b = world.getBlockAt(l);
return MB.of(b.getType(), b.getData());
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
Block b = world.getBlockAt(l);
b.setTypeIdAndData(mb.material.getId(), mb.data, applyPhysics);
}
@Override
public int getHighestY(Location l)
{
return world.getHighestBlockYAt(l);
}
}

View File

@ -0,0 +1,15 @@
package ninja.bytecode.iris.util;
import org.bukkit.Location;
import org.bukkit.World;
public interface IPlacer
{
public World getWorld();
public MB get(Location l);
public void set(Location l, MB mb);
public int getHighestY(Location l);
}

View File

@ -0,0 +1,102 @@
package ninja.bytecode.iris.util;
public class MCAPos
{
private int x;
private int z;
public static MCAPos fromChunk(int x, int z)
{
return new MCAPos(x >> 5, z >> 5);
}
public MCAPos(String name)
{
fromFileName(name);
}
public MCAPos(int x, int z)
{
this.x = x;
this.z = z;
}
public void fromFileName(String n)
{
String[] f = n.split("\\Q.\\E");
x = Integer.valueOf(f[0]);
z = Integer.valueOf(f[1]);
}
public String toFileName()
{
return x + "." + z + ".imc";
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public int getZ()
{
return z;
}
public void setZ(int z)
{
this.z = z;
}
public int getMinChunkX()
{
return x << 5;
}
public int getMinChunkZ()
{
return z << 5;
}
public int getMaxChunkX()
{
return getMinChunkX() + 32;
}
public int getMaxChunkZ()
{
return getMinChunkZ() + 32;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + z;
return result;
}
@Override
public boolean equals(Object obj)
{
if(this == obj)
return true;
if(obj == null)
return false;
if(getClass() != obj.getClass())
return false;
MCAPos other = (MCAPos) obj;
if(x != other.x)
return false;
if(z != other.z)
return false;
return true;
}
}

View File

@ -0,0 +1,80 @@
package ninja.bytecode.iris.util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import ninja.bytecode.shuriken.math.M;
public class MCAState
{
private boolean[] decorated;
private boolean dirty;
private long lastUsed;
public MCAState()
{
lastUsed = M.ms();
this.decorated = new boolean[1024];
}
public boolean isInUse()
{
return M.ms() - lastUsed < 30000;
}
public void setDirty()
{
lastUsed = M.ms();
this.dirty = true;
}
public void saved()
{
lastUsed = M.ms();
this.dirty = false;
}
public boolean isDirty()
{
return dirty;
}
public boolean isDecorated(int rcx, int rcz)
{
lastUsed = M.ms();
return decorated[rcx + (32 * rcz)];
}
public void setDecorated(int rcx, int rcz, boolean decorated)
{
lastUsed = M.ms();
this.decorated[rcx + (32 * rcz)] = decorated;
}
public void read(InputStream in) throws IOException
{
DataInputStream din = new DataInputStream(in);
for(int i = 0; i < 1024; i++)
{
decorated[i] = din.readBoolean();
}
din.close();
}
public void write(OutputStream out) throws IOException
{
DataOutputStream dos = new DataOutputStream(out);
for(int i = 0; i < 1024; i++)
{
dos.writeBoolean(decorated[i]);
}
dos.close();
}
}

View File

@ -0,0 +1,73 @@
package ninja.bytecode.iris.util;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_12_R1.CraftWorld;
import net.minecraft.server.v1_12_R1.Block;
import net.minecraft.server.v1_12_R1.Chunk;
import net.minecraft.server.v1_12_R1.ChunkSection;
import net.minecraft.server.v1_12_R1.IBlockData;
import net.minecraft.server.v1_12_R1.WorldServer;
public class NMSPlacer12 extends Placer
{
private CraftWorld craftWorld;
private WorldServer worldServer;
public NMSPlacer12(World world)
{
super(world);
craftWorld = (CraftWorld) world;
worldServer = craftWorld.getHandle();
}
@SuppressWarnings("deprecation")
@Override
public MB get(Location l)
{
Chunk c = worldServer.getChunkAt(l.getBlockX() >> 4, l.getBlockZ() >> 4);
ChunkSection s = c.getSections()[l.getBlockY() >> 4];
if(s == null)
{
return MB.of(Material.AIR);
}
IBlockData d = s.getType(l.getBlockX() & 15, l.getBlockY() & 15, l.getBlockZ() & 15);
Block block = d.getBlock();
return MB.of(Material.getMaterial(Block.getId(block)), block.toLegacyData(d) << 12);
}
@SuppressWarnings("deprecation")
@Override
public void set(Location l, MB mb)
{
Chunk c = worldServer.getChunkAt(l.getBlockX() >> 4, l.getBlockZ() >> 4);
int combined = mb.material.getId() + (mb.data << 12);
IBlockData ibd = net.minecraft.server.v1_12_R1.Block.getByCombinedId(combined);
if(c.getSections()[l.getBlockY() >> 4] == null)
{
c.getSections()[l.getBlockY() >> 4] = new net.minecraft.server.v1_12_R1.ChunkSection(l.getBlockY() >> 4 << 4, c.world.worldProvider.m());
}
int h = c.b(l.getBlockX() & 15, l.getBlockZ() & 15);
if(l.getBlockY() > h)
{
c.heightMap[(l.getBlockZ() & 15) << 4 | (l.getBlockX() & 15)] = l.getBlockY();
}
net.minecraft.server.v1_12_R1.ChunkSection sec = c.getSections()[l.getBlockY() >> 4];
sec.setType(l.getBlockX() & 15, l.getBlockY() & 15, l.getBlockZ() & 15, ibd);
c.markDirty();
}
@Override
public int getHighestY(Location l)
{
return worldServer.getChunkAt(l.getBlockX() >> 4, l.getBlockZ() >> 4)
.b(l.getBlockX() & 15, l.getBlockZ() & 15);
}
}

View File

@ -14,6 +14,7 @@ import ninja.bytecode.shuriken.execution.ChronoLatch;
import ninja.bytecode.shuriken.execution.TaskExecutor;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskGroup;
import ninja.bytecode.shuriken.execution.TaskExecutor.TaskResult;
import ninja.bytecode.shuriken.logging.L;
import ninja.bytecode.shuriken.math.RollingSequence;
import ninja.bytecode.shuriken.reaction.O;
@ -44,6 +45,8 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
}
public ChunkData generateChunkData(World world, Random random, int x, int z, BiomeGrid biome)
{
try
{
Iris.getController(TimingsController.class).started("terrain");
if(genPool == null)
@ -52,9 +55,6 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
}
this.world = world;
data = new AtomicChunkData(world);
try
{
if(!ready)
{
onInit(world, random);
@ -83,6 +83,7 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
onPostChunk(world, x, z, random, data, plan.get());
rs.put(r.timeElapsed);
cg++;
Iris.getController(TimingsController.class).stopped("terrain");
}
catch(Throwable e)
@ -99,9 +100,9 @@ public abstract class ParallelChunkGenerator extends ChunkGenerator
data.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA);
}
}
}
Iris.getController(TimingsController.class).stopped("terrain");
L.ex(e);
}
return data.toChunkData();
}

View File

@ -0,0 +1,19 @@
package ninja.bytecode.iris.util;
import org.bukkit.World;
public abstract class Placer implements IPlacer
{
protected final World world;
public Placer(World world)
{
this.world = world;
}
@Override
public World getWorld()
{
return world;
}
}

View File

@ -0,0 +1,24 @@
package ninja.bytecode.iris.util;
import java.util.function.Function;
import org.bukkit.World;
public enum PlacerType
{
BUKKIT((w) -> new BukkitPlacer(w, true)),
BUKKIT_NO_PHYSICS((w) -> new BukkitPlacer(w, false)),
NMS((w) -> new NMSPlacer12(w));
private Function<World, IPlacer> placer;
private PlacerType(Function<World, IPlacer> placer)
{
this.placer = placer;
}
public IPlacer get(World world)
{
return placer.apply(world);
}
}

View File

@ -0,0 +1,132 @@
package ninja.bytecode.iris.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import net.md_5.bungee.api.ChatColor;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.io.CustomOutputStream;
import ninja.bytecode.shuriken.logging.L;
public class WorldState implements Listener
{
private int taskId;
private GMap<MCAPos, MCAState> stateCache;
private World world;
@SuppressWarnings("deprecation")
public WorldState(World world)
{
this.world = world;
taskId = Bukkit.getScheduler().scheduleAsyncRepeatingTask(Iris.instance, this::tick, 20, 20 * 18);
Bukkit.getPluginManager().registerEvents(this, Iris.instance);
}
public void tick()
{
for(MCAPos i : stateCache.k())
{
MCAState state = stateCache.get(i);
if(state.isDirty())
{
try
{
saveMCAState(i, state);
}
catch(IOException e)
{
L.f(ChatColor.RED + "Failed to save MCA State " + i.toFileName());
L.ex(e);
}
}
}
}
public void close()
{
HandlerList.unregisterAll(this);
Bukkit.getScheduler().cancelTask(taskId);
for(MCAPos i : stateCache.k())
{
try
{
saveMCAState(i, stateCache.get(i));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
public void unloadState(MCAPos pos)
{
stateCache.remove(pos);
L.v(ChatColor.GRAY + "Unloaded MCA State " + pos.toFileName());
}
public MCAState getState(MCAPos pos)
{
if(!stateCache.containsKey(pos))
{
try
{
stateCache.put(pos, loadMCAState(pos));
}
catch(IOException e)
{
L.f(ChatColor.RED + "Failed to read MCA State " + pos.toFileName());
L.ex(e);
L.w(ChatColor.YELLOW + "Created Fallback MCA State " + pos.toString());
stateCache.put(pos, new MCAState());
}
}
return stateCache.get(pos);
}
private void saveMCAState(MCAPos pos, MCAState state) throws IOException
{
File file = new File(world.getWorldFolder(), "iris/state/" + pos.toFileName());
file.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(file);
CustomOutputStream cos = new CustomOutputStream(fos, 9);
state.write(cos);
state.saved();
L.v(ChatColor.GRAY + "Saved MCA State " + pos.toString());
}
private MCAState loadMCAState(MCAPos pos) throws IOException
{
MCAState state = new MCAState();
File file = new File(world.getWorldFolder(), "iris/state/" + pos.toFileName());
if(!file.exists())
{
file.getParentFile().mkdirs();
state.setDirty();
L.v(ChatColor.GRAY + "Created MCA State " + pos.toString());
return state;
}
FileInputStream fin = new FileInputStream(file);
GZIPInputStream gzi = new GZIPInputStream(fin);
state.read(gzi);
L.v(ChatColor.GRAY + "Loaded MCA State " + pos.toString());
return state;
}
}

View File

@ -6,10 +6,12 @@
"LONG_GRASS:2=0.13"
],
"objects": [
"tree/oak/medium=0.33",
"tree/oak/small=2.2",
"tree/oak/medium=0.83",
"tree/oak/small=3.2",
"colossal/oak/massive=0.001",
"colossal/oak/superlarge=0.0004",
"colossal/oak/supermassive=0.0001"
"colossal/oak/supermassive=0.0001",
"tree/fantasyoak/large=0.18",
"tree/fantasyoak/medium=0.18"
]
}

View File

@ -6,8 +6,8 @@
"LONG_GRASS:2=0.13"
],
"objects": [
"tree/birch/medium=0.33",
"tree/birch/large=0.42",
"tree/birch/small=2.2"
"tree/birch/medium=0.63",
"tree/birch/large=0.32",
"tree/birch/small=3.2"
]
}

View File

@ -5,9 +5,10 @@
"LONG_GRASS:1=0.23",
"LONG_GRASS:2=0.13"
],
"height": 0.14,
"objects": [
"tree/birch/medium=0.33",
"tree/birch/large=0.42",
"tree/birch/small=2.2"
"tree/birch/medium=0.63",
"tree/birch/large=0.32",
"tree/birch/small=3.2"
]
}

View File

@ -5,11 +5,14 @@
"LONG_GRASS:1=0.23",
"LONG_GRASS:2=0.13"
],
"height": 0.11,
"objects": [
"tree/oak/medium=0.23",
"tree/oak/small=2.5",
"tree/oak/medium=0.83",
"tree/oak/small=2.8",
"colossal/oak/massive=0.001",
"colossal/oak/superlarge=0.0004",
"colossal/oak/supermassive=0.0001"
"colossal/oak/supermassive=0.0001",
"tree/fantasyoak/large=0.18",
"tree/fantasyoak/medium=0.18"
]
}

View File

@ -5,4 +5,9 @@
"LONG_GRASS:1=0.37",
"LONG_GRASS:2=0.09"
],
"objects": [
"colossal/blossom/massive=0.0008",
"colossal/blossom/supermassive=0.00011",
"colossal/blossom/superlarge=0.00054"
]
}

View File

@ -12,8 +12,10 @@
"LONG_GRASS:2=0.07"
],
"objects": [
"tree/spruce/medium=0.67",
"tree/spruce/small=2.7",
"tree/spruce/dead/medium=0.09"
"tree/spruce/medium=0.87",
"tree/spruce/small=3.7",
"tree/spruce/dead/medium=0.01",
"tree/evergreen/large=0.17",
"tree/evergreen/medium=0.22"
]
}

View File

@ -13,7 +13,9 @@
],
"objects": [
"tree/spruce/medium=0.87",
"tree/spruce/small=2.7",
"tree/spruce/dead/medium=0.06"
"tree/spruce/small=3.7",
"tree/spruce/dead/medium=0.01",
"tree/evergreen/large=0.27",
"tree/evergreen/medium=0.32"
]
}

View File

@ -6,10 +6,10 @@
"LONG_GRASS:2=0.09"
],
"objects": [
"tree/serrulata/bleeding/alt/medium=0.033",
"tree/serrulata/bleeding/large=0.042",
"tree/serrulata/bleeding/medium=0.042",
"tree/serrulata/nobleed/medium=0.042",
"tree/serrulata/sakura/medium=0.02"
"tree/serrulata/bleeding/alt/medium=0.012",
"tree/serrulata/bleeding/medium=0.012",
"tree/serrulata/nobleed/medium=0.012",
"tree/serrulata/sakura/medium=0.012",
"tree/serrulata/bleeding/large=0.003"
]
}

View File

@ -3,5 +3,11 @@
"derivative": "SAVANNA",
"scatter":[
"LONG_GRASS:1=0.18"
],
"objects":[
"colossal/dead/massive=0.001",
"colossal/dead/superlarge=0.0005",
"colossal/dead/supermassive=0.0001",
"colossal/dead/fallen/massive=0.001"
]
}