Schematics

This commit is contained in:
Daniel Mills 2020-01-19 07:11:11 -05:00
parent 8ced379e44
commit 2ea1bd5e67
14 changed files with 845 additions and 84 deletions

View File

@ -11,6 +11,7 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import ninja.bytecode.iris.controller.PackController;
import ninja.bytecode.iris.controller.WandController;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.util.Direction;
import ninja.bytecode.iris.util.IrisController;
@ -58,6 +59,7 @@ public class Iris extends JavaPlugin implements Listener
public void onDisable()
{
getController(PackController.class).dispose();
getController(WandController.class).dispose();
controllerSet.stopControllers();
HandlerList.unregisterAll((Plugin) this);
Bukkit.getScheduler().cancelTasks(this);

View File

@ -18,6 +18,7 @@ public class Settings
public boolean interpolation = true;
public boolean surfaceNoise = true;
public boolean verbose = false;
public int placeHistoryLimit = 8192;
}
public static class GeneratorSettings

View File

@ -21,20 +21,33 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.util.BlockVector;
import org.bukkit.util.Vector;
import mortar.compute.math.M;
import mortar.util.text.C;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.generator.IrisGenerator;
import ninja.bytecode.iris.generator.genobject.GenObject;
import ninja.bytecode.iris.generator.genobject.GenObjectGroup;
import ninja.bytecode.iris.generator.genobject.PlacedObject;
import ninja.bytecode.iris.pack.IrisBiome;
import ninja.bytecode.iris.util.Cuboid;
import ninja.bytecode.iris.util.IrisController;
import ninja.bytecode.iris.util.MB;
import ninja.bytecode.iris.util.ParticleEffect;
import ninja.bytecode.iris.util.ParticleRedstone;
import ninja.bytecode.shuriken.collections.GList;
import ninja.bytecode.shuriken.collections.GMap;
import ninja.bytecode.shuriken.format.F;
public class WandController implements IrisController
{
private GMap<String, GenObject> goc;
private GMap<String, GenObjectGroup> gog;
@Override
public void onStart()
{
goc = new GMap<>();
gog = new GMap<>();
// TODO: Optimize
Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () ->
{
@ -58,7 +71,24 @@ public class WandController implements IrisController
{
if(isWand(p.getInventory().getItemInMainHand()))
{
if(Iris.settings.performance.debugMode && p.getWorld().getGenerator() instanceof IrisGenerator)
{
tickHighlight(p, (IrisGenerator) p.getWorld().getGenerator());
}
Location[] d = getCuboid(p.getInventory().getItemInMainHand());
draw(d, p);
}
}
catch(Throwable e)
{
}
}
private void draw(Location[] d, Player p)
{
ParticleEffect.CRIT_MAGIC.display(0.1f, 1, d[0].clone().add(0.5, 0.5, 0.5).clone().add(Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65)), p);
ParticleEffect.CRIT.display(0.1f, 1, d[1].clone().add(0.5, 0.5, 0.5).clone().add(Vector.getRandom().subtract(Vector.getRandom()).normalize().clone().multiply(0.65)), p);
@ -84,6 +114,8 @@ public class WandController implements IrisController
for(double k = miny - 1; k < maxy + 1; k += 0.25)
{
for(double l = minz - 1; l < maxz + 1; l += 0.25)
{
if(M.r(0.25))
{
boolean jj = j == minx || j == maxx;
boolean kk = k == miny || k == maxy;
@ -136,9 +168,95 @@ public class WandController implements IrisController
}
}
private void tickHighlight(Player p, IrisGenerator generator)
{
Location l = p.getTargetBlock(null, 32).getLocation();
PlacedObject po = generator.nearest(l, 12);
if(po != null)
{
if(!goc.containsKey(po.getF()))
{
String root = po.getF().split("\\Q:\\E")[0];
String n = po.getF().split("\\Q:\\E")[1];
GenObjectGroup gg = generator.getDimension().getObjectGroup(root);
gog.put(root, gg);
for(GenObject i : gg.getSchematics())
{
if(i.getName().equals(n))
{
goc.put(po.getF(), i);
break;
}
}
if(!goc.containsKey(po.getF()))
{
goc.put(po.getF(), new GenObject(0, 0, 0));
}
}
GenObjectGroup ggg = gog.get(po.getF().split("\\Q:\\E")[0]);
GenObject g = goc.get(po.getF());
if(g != null)
{
Location point = new Location(l.getWorld(), po.getX(), po.getY(), po.getZ());
IrisBiome biome = generator.getBiome((int) generator.getOffsetX(po.getX()), (int) generator.getOffsetZ(po.getZ()));
String gg = po.getF().split("\\Q:\\E")[0];
for(int j = 0; j < 10; j++)
{
p.sendMessage(" ");
}
p.sendMessage(C.DARK_GREEN + C.BOLD.toString() + gg + C.GRAY + "/" + C.RESET + C.ITALIC + C.GRAY + g.getName() + C.RESET + C.WHITE + " (1 of " + F.f(generator.getDimension().getObjectGroup(gg).size()) + " variants)");
if(biome.getSchematicGroups().containsKey(gg))
{
String f = "";
double percent = biome.getSchematicGroups().get(gg);
if(percent > 1D)
{
f = (int) percent + " + " + F.pc(percent - (int) percent, percent - (int) percent >= 0.01 ? 0 : 3);
}
else
{
f = F.pc(percent, percent >= 0.01 ? 0 : 3);
}
p.sendMessage(C.GOLD + "Spawn Chance in " + C.YELLOW + biome.getName() + C.RESET + ": " + C.BOLD + C.WHITE + f);
}
try
{
int a = 0;
int b = 0;
double c = 0;
for(GenObject i : ggg.getSchematics())
{
a += i.getSuccesses();
b += i.getPlaces();
}
c = ((double) a / (double) b);
p.sendMessage(C.GRAY + "Grp: " + C.DARK_AQUA + F.f(a) + C.GRAY + " of " + C.AQUA + F.f(b) + C.GRAY + " placements (" + C.DARK_AQUA + F.pc(c, 0) + C.GRAY + ")");
}
catch(Throwable e)
{
e.printStackTrace();
}
p.sendMessage(C.GRAY + "Var: " + C.DARK_AQUA + F.f(g.getSuccesses()) + C.GRAY + " of " + C.AQUA + F.f(g.getPlaces()) + C.GRAY + " placements (" + C.DARK_AQUA + F.pc(g.getSuccess(), 0) + C.GRAY + ")");
draw(new Location[] {point.clone().add(g.getW() / 2, g.getH() / 2, g.getD() / 2), point.clone().subtract(g.getW() / 2, g.getH() / 2, g.getD() / 2)
}, p);
}
}
}
@ -260,6 +378,12 @@ public class WandController implements IrisController
return createWand(left ? a : other, left ? other : a);
}
public void dispose()
{
goc.clear();
gog.clear();
}
public static ItemStack createWand(Location a, Location b)
{
ItemStack is = new ItemStack(Material.BLAZE_ROD);

View File

@ -3,15 +3,18 @@ package ninja.bytecode.iris.generator;
import java.util.List;
import java.util.Random;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.util.NumberConversions;
import mortar.util.text.C;
import ninja.bytecode.iris.Iris;
import ninja.bytecode.iris.controller.PackController;
import ninja.bytecode.iris.generator.genobject.GenObjectDecorator;
import ninja.bytecode.iris.generator.genobject.PlacedObject;
import ninja.bytecode.iris.generator.layer.GenLayerBiome;
import ninja.bytecode.iris.generator.layer.GenLayerCarving;
import ninja.bytecode.iris.generator.layer.GenLayerCaverns;
@ -62,6 +65,7 @@ public class IrisGenerator extends ParallelChunkGenerator
private MB PACKED_ICE = new MB(Material.PACKED_ICE);
private MB WATER = new MB(Material.STATIONARY_WATER);
private MB BEDROCK = new MB(Material.BEDROCK);
private GenObjectDecorator god;
private GenLayerLayeredNoise glLNoise;
private GenLayerBiome glBiome;
private GenLayerCaves glCaves;
@ -350,7 +354,7 @@ public class IrisGenerator extends ParallelChunkGenerator
if(Iris.settings.gen.genObjects)
{
p.add(new GenObjectDecorator(this));
p.add(god = new GenObjectDecorator(this));
}
return p;
@ -408,4 +412,25 @@ public class IrisGenerator extends ParallelChunkGenerator
{
return disposed;
}
public PlacedObject nearest(Location o, int i)
{
PlacedObject f = null;
double d = Integer.MAX_VALUE;
if(god != null)
{
for(PlacedObject j : god.getHistory())
{
double dx = Math.abs(NumberConversions.square(j.getX() - o.getX()) + NumberConversions.square(j.getY() - o.getY()) + NumberConversions.square(j.getZ() - o.getZ()));
if(dx < d)
{
d = dx;
f = j;
}
}
}
return f;
}
}

View File

@ -44,6 +44,8 @@ public class GenObject
private int w;
private int h;
private int d;
private int failures;
private int successes;
private String name = "?";
private final GMap<SBlockVector, MB> s;
private BlockVector mount;
@ -290,14 +292,10 @@ public class GenObject
L.w(C.WHITE + "Object " + C.YELLOW + getName() + C.WHITE + " failed to place in " + C.YELLOW + m.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(f.getBlockX()) + " " + F.f(f.getBlockY()) + " " + F.f(f.getBlockZ()));
}
failures++;
return null;
}
if(b.material.equals(Material.SKULL))
{
continue;
}
try
{
undo.put(f, placer.get(f));
@ -310,6 +308,7 @@ public class GenObject
}
}
successes++;
return start;
}
@ -592,6 +591,26 @@ public class GenObject
}
}
public double getSuccess()
{
return (double) successes / ((double) successes + (double) failures);
}
public int getFailures()
{
return failures;
}
public int getSuccesses()
{
return successes;
}
public int getPlaces()
{
return successes + failures;
}
public void dispose()
{
s.clear();

View File

@ -32,6 +32,7 @@ import ninja.bytecode.shuriken.math.M;
public class GenObjectDecorator extends BlockPopulator
{
private GList<PlacedObject> placeHistory;
private GMap<IrisBiome, GList<GenObjectGroup>> orderCache;
private GMap<IrisBiome, GMap<GenObjectGroup, Double>> populationCache;
private IPlacer placer;
@ -42,6 +43,7 @@ public class GenObjectDecorator extends BlockPopulator
public GenObjectDecorator(IrisGenerator generator)
{
this.g = generator;
placeHistory = new GList<>();
populationCache = new GMap<>();
orderCache = new GMap<>();
ex = Executors.newSingleThreadExecutor();
@ -103,6 +105,7 @@ public class GenObjectDecorator extends BlockPopulator
{
if(g.isDisposed())
{
placeHistory.clear();
return;
}
@ -155,8 +158,12 @@ public class GenObjectDecorator extends BlockPopulator
Material t = b.getType();
if(!t.isSolid() || !biome.isSurface(t))
{
if(Iris.settings.performance.verbose)
{
L.w(C.WHITE + "Object " + C.YELLOW + i.getName() + "/*" + C.WHITE + " failed to place in " + C.YELLOW + t.toString().toLowerCase() + C.WHITE + " at " + C.YELLOW + F.f(b.getX()) + " " + F.f(b.getY()) + " " + F.f(b.getZ()));
}
continue;
}
@ -178,10 +185,26 @@ public class GenObjectDecorator extends BlockPopulator
{
Location start = g.place(x, b.getY(), z, placer);
if(start != null && Iris.settings.performance.verbose)
if(start != null)
{
if(Iris.settings.performance.verbose)
{
L.v(C.GRAY + "Placed " + C.DARK_GREEN + i.getName() + C.WHITE + "/" + C.DARK_GREEN + g.getName() + C.GRAY + " at " + C.DARK_GREEN + F.f(start.getBlockX()) + " " + F.f(start.getBlockY()) + " " + F.f(start.getBlockZ()));
}
if(Iris.settings.performance.debugMode)
{
placeHistory.add(new PlacedObject(start.getBlockX(), start.getBlockY(), start.getBlockZ(), i.getName() + ":" + g.getName()));
if(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
while(placeHistory.size() > Iris.settings.performance.placeHistoryLimit)
{
placeHistory.remove(0);
}
}
}
}
});
}
}
@ -214,4 +237,9 @@ public class GenObjectDecorator extends BlockPopulator
return floor;
}
public GList<PlacedObject> getHistory()
{
return placeHistory;
}
}

View File

@ -0,0 +1,95 @@
package ninja.bytecode.iris.generator.genobject;
public class PlacedObject
{
private int x;
private int y;
private int z;
private String f;
public PlacedObject(int x, int y, int z, String f)
{
this.x = x;
this.y = y;
this.z = z;
this.f = f;
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
public int getY()
{
return y;
}
public void setY(int y)
{
this.y = y;
}
public int getZ()
{
return z;
}
public void setZ(int z)
{
this.z = z;
}
public String getF()
{
return f;
}
public void setF(String f)
{
this.f = f;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((f == null) ? 0 : f.hashCode());
result = prime * result + x;
result = prime * result + y;
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;
PlacedObject other = (PlacedObject) obj;
if(f == null)
{
if(other.f != null)
return false;
}
else if(!f.equals(other.f))
return false;
if(x != other.x)
return false;
if(y != other.y)
return false;
if(z != other.z)
return false;
return true;
}
}

View File

@ -0,0 +1,10 @@
package ninja.bytecode.iris.util;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@FunctionalInterface
public interface GRT
{
public Glower getGlower(Entity entity, Player observer);
}

View File

@ -0,0 +1,106 @@
package ninja.bytecode.iris.util;
import org.bukkit.ChatColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import mortar.api.nms.NMP;
import mortar.util.text.C;
public class GlossGlower implements Glower
{
private final Player observer;
private final Entity entity;
private ChatColor color;
private boolean sentTeam;
public GlossGlower(Entity entity, Player observer)
{
sentTeam = false;
this.entity = entity;
this.observer = observer;
this.color = ChatColor.WHITE;
}
@Override
public Entity getEntity()
{
return entity;
}
@Override
public ChatColor getColor()
{
return color;
}
@Override
public void setColor(ChatColor color)
{
if(color.isFormat())
{
throw new UnsupportedOperationException("You cannot use format codes for glow colors");
}
this.color = color;
if(observer == null)
{
for(Player i : entity.getWorld().getPlayers())
{
NMP.host.sendGlowingColorMeta(i, getEntity(), C.values()[color.ordinal()]);
}
}
else
{
NMP.host.sendGlowingColorMeta(getObserver(), getEntity(), C.values()[color.ordinal()]);
}
}
@Override
public void setGlowing(boolean glowing)
{
if(observer == null)
{
for(Player i : entity.getWorld().getPlayers())
{
NMP.host.sendEntityMetadata(i, getEntity().getEntityId(), NMP.host.getMetaEntityProperties(false, false, false, false, false, glowing, false));
}
}
else
{
NMP.host.sendEntityMetadata(observer, getEntity().getEntityId(), NMP.host.getMetaEntityProperties(false, false, false, false, false, glowing, false));
}
}
@Override
public void destroy()
{
setGlowing(false);
if(sentTeam)
{
if(observer == null)
{
for(Player i : entity.getWorld().getPlayers())
{
NMP.host.sendRemoveGlowingColorMeta(i, getEntity());
}
}
else
{
NMP.host.sendRemoveGlowingColorMeta(getObserver(), getEntity());
}
}
}
@Override
public Player getObserver()
{
return observer;
}
}

View File

@ -0,0 +1,14 @@
package ninja.bytecode.iris.util;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public class GlowManager
{
public static GRT f = null;
public static Glower create(Entity e, Player observer)
{
return f.getGlower(e, observer);
}
}

View File

@ -0,0 +1,20 @@
package ninja.bytecode.iris.util;
import org.bukkit.ChatColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
public interface Glower
{
public Player getObserver();
public Entity getEntity();
public ChatColor getColor();
public void setColor(ChatColor color);
public void setGlowing(boolean glowing);
public void destroy();
}

View File

@ -0,0 +1,179 @@
package ninja.bytecode.iris.util;
import java.util.UUID;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import mortar.api.nms.NMP;
import mortar.api.world.MaterialBlock;
import mortar.compute.math.M;
import mortar.util.text.C;
public class GlowingBlock
{
private static int idd = 123456789;
private int id;
private UUID uid;
private Location location;
private Location current;
private Player player;
private double factor;
private Vector velocity;
private boolean active;
private long mv = M.ms();
private MaterialBlock mb;
private ChatColor c;
public GlowingBlock(Player player, Location init, MaterialBlock mb, ChatColor c)
{
this.mb = mb;
this.uid = UUID.randomUUID();
this.id = idd--;
location = init;
current = init.clone();
this.player = player;
factor = Math.PI;
active = false;
velocity = new Vector();
this.c = c;
}
public int getId()
{
return id;
}
public void sendMetadata(boolean glowing)
{
PacketGate.mark(PacketCategory.EFFECT);
NMP.host.sendEntityMetadata(player, id, NMP.host.getMetaEntityProperties(false, false, false, false, false, glowing, false));
}
public void sendMetadata(ChatColor c)
{
PacketGate.mark(PacketCategory.EFFECT);
//NMP.host.sendGlowingColorMetaEntity(getPlayer(), uid, C.values()[c.ordinal()]);
}
public void update()
{
if(M.ms() - mv < 50)
{
return;
}
if(location.getX() == current.getX() && location.getY() == current.getY() && location.getZ() == current.getZ())
{
return;
}
mv = M.ms();
if(location.distanceSquared(current) > 16)
{
if(PacketGate.can(PacketCategory.EFFECT))
{
sendTeleport(location);
current = location;
}
}
else
{
if(PacketGate.can(PacketCategory.EFFECT))
{
double dx = location.getX() - current.getX();
double dy = location.getY() - current.getY();
double dz = location.getZ() - current.getZ();
dx += velocity.getX();
dy += velocity.getY();
dz += velocity.getZ();
dx = M.clip(dx, -8, 8);
dy = M.clip(dy, -8, 8);
dz = M.clip(dz, -8, 8);
sendMove(dx / factor, dy / factor, dz / factor);
current.add(dx / factor, dy / factor, dz / factor);
current.setX(Math.abs(location.getX() - current.getX()) < 0.00001 ? location.getX() : current.getX());
current.setY(Math.abs(location.getY() - current.getY()) < 0.00001 ? location.getY() : current.getY());
current.setZ(Math.abs(location.getZ() - current.getZ()) < 0.00001 ? location.getZ() : current.getZ());
if(location.getX() == current.getX() && location.getY() == current.getY() && location.getZ() == current.getZ())
{
if(PacketGate.can(PacketCategory.EFFECT))
{
sendTeleport(location);
current = location;
}
}
}
}
}
public Location getPosition()
{
return location.clone();
}
public void setPosition(Location l)
{
location = l;
}
public Player getPlayer()
{
return player;
}
public void destroy()
{
sendDestroy();
}
public void create()
{
sendSpawn();
}
public boolean isActive()
{
return active;
}
public void setFactor(int i)
{
factor = i;
}
private void sendTeleport(Location l)
{
NMP.host.teleportEntity(id, player, l, false);
}
private void sendMove(double x, double y, double z)
{
NMP.host.moveEntityRelative(id, player, x, y, z, false);
}
public void sendDestroy()
{
active = false;
NMP.host.removeEntity(id, player);
NMP.host.sendRemoveGlowingColorMetaEntity(getPlayer(), uid);
sendMetadata(false);
PacketGate.mark(PacketCategory.EFFECT);
PacketGate.mark(PacketCategory.EFFECT);
}
public void sendSpawn()
{
NMP.host.spawnFallingBlock(id, uid, location, player, mb);
sendMetadata(c);
sendMetadata(true);
active = true;
PacketGate.mark(PacketCategory.EFFECT);
PacketGate.mark(PacketCategory.EFFECT);
}
}

View File

@ -0,0 +1,9 @@
package ninja.bytecode.iris.util;
public enum PacketCategory
{
BOARD,
HOLOGRAM,
EFFECT,
TABLIST;
}

View File

@ -0,0 +1,129 @@
package ninja.bytecode.iris.util;
import mortar.compute.math.RollingAverage;
import mortar.lang.collection.GMap;
public class PacketGate
{
private static final GMap<PacketCategory, PacketGate> gates = new GMap<>();
private final RollingAverage average;
private final int pps;
private int sent;
private PacketGate(int pps)
{
sent = 0;
this.pps = pps;
average = new RollingAverage(100);
}
public void tick()
{
average.put(sent * 20D);
sent = 0;
}
public boolean can()
{
if(should())
{
mark();
return true;
}
return false;
}
public boolean should()
{
if(average.get() < pps)
{
return true;
}
return false;
}
public void mark()
{
sent++;
}
private double getAveragePPS()
{
return average.get();
}
public static int getTotalPPS()
{
double m = 0;
for(PacketCategory i : PacketCategory.values())
{
m += getAveragePPS(i);
}
return (int) m;
}
public static void tickAll()
{
if(gates.isEmpty())
{
reset();
}
for(PacketCategory i : PacketCategory.values())
{
gates.get(i).tick();
}
}
public static double getAveragePPS(PacketCategory cat)
{
if(!gates.containsKey(cat))
{
reset();
}
return gates.get(cat).getAveragePPS();
}
public static boolean can(PacketCategory cat)
{
if(!gates.containsKey(cat))
{
reset();
}
return gates.get(cat).can();
}
public static void mark(PacketCategory cat)
{
if(!gates.containsKey(cat))
{
reset();
}
gates.get(cat).mark();
}
public static boolean should(PacketCategory cat)
{
if(!gates.containsKey(cat))
{
reset();
}
return gates.get(cat).should();
}
public static void reset()
{
gates.put(PacketCategory.BOARD, new PacketGate(100));
gates.put(PacketCategory.EFFECT, new PacketGate(100));
gates.put(PacketCategory.HOLOGRAM, new PacketGate(100));
gates.put(PacketCategory.TABLIST, new PacketGate(100));
}
}