seedoverlay working, but still with messy decorations

This commit is contained in:
Daniella / Tove 2024-05-29 00:25:34 +02:00
parent d9bbea9a45
commit f6474d2840
7 changed files with 301 additions and 70 deletions

Binary file not shown.

View file

@ -25,7 +25,7 @@ public abstract class Component {
@Marker(Integer.MIN_VALUE) @Marker(Integer.MIN_VALUE)
static final boolean FALSE = false; static final boolean FALSE = false;
public static final int MARKER_PREFIX = -512; private static final int MARKER_PREFIX = -512;
public static final int M_GUI_EXPANDED = MARKER_PREFIX + 1; public static final int M_GUI_EXPANDED = MARKER_PREFIX + 1;
public Point loc; public Point loc;

View file

@ -28,6 +28,9 @@ import java.util.HashMap;
//Double fuck you if this involves commands too then it's a feature not a module //Double fuck you if this involves commands too then it's a feature not a module
public abstract class Feature extends ToggleButton implements SetCommand { public abstract class Feature extends ToggleButton implements SetCommand {
private static final int MARKER_PREFIX = -1024;
public static final int M_ENABLED = MARKER_PREFIX + 1;
protected Setup Setup; protected Setup Setup;
protected BaseBand bb; protected BaseBand bb;
@ -35,7 +38,7 @@ public abstract class Feature extends ToggleButton implements SetCommand {
public Category category; public Category category;
@Marker(1) @Marker(M_ENABLED)
public boolean enabled = defaultEnable(); public boolean enabled = defaultEnable();
@Config("Toggle") @Config("Toggle")
@ -176,7 +179,7 @@ public abstract class Feature extends ToggleButton implements SetCommand {
} }
handle = settings; handle = settings;
BaseBand.registerUpdater(settings.linkWith(this, FieldFinder.findMarked(Feature.class, 1)).name("Enabled")).populate(); BaseBand.registerUpdater(settings.linkWith(this, FieldFinder.findMarked(Feature.class, M_ENABLED)).name("Enabled")).populate();
Description description = getClass().getDeclaredAnnotation(Description.class); Description description = getClass().getDeclaredAnnotation(Description.class);
if(description != null) if(description != null)

View file

@ -40,7 +40,7 @@ public class HUD extends Feature {
private final long start = new Date().getTime(); private final long start = new Date().getTime();
public Notification(String text) { public Notification(String text) {
this(text, 5000); this(text, 10000);
} }
public Notification(String text, int ms) { public Notification(String text, int ms) {
@ -181,7 +181,7 @@ public class HUD extends Feature {
int localYSize = ySize; int localYSize = ySize;
String text = TextSplitter.breakText(notif.text, xSize - textOffset * 2); String text = TextSplitter.breakText(notif.text, xSize - textOffset * 2);
localYSize -= TextSplitter.getStringHeight(text) - mc.fontRenderer.FONT_HEIGHT; localYSize += TextSplitter.getStringHeight(text) - mc.fontRenderer.FONT_HEIGHT;
int textboxYSize = localYSize; int textboxYSize = localYSize;
localYSize = notif.opacity(localYSize, 1); localYSize = notif.opacity(localYSize, 1);

View file

@ -2,6 +2,7 @@ package com.baseband.client.module.world;
import com.baseband.client.BaseBand; import com.baseband.client.BaseBand;
import com.baseband.client.configuration.annotation.Config; import com.baseband.client.configuration.annotation.Config;
import com.baseband.client.configuration.annotation.Gate;
import com.baseband.client.configuration.annotation.Range; import com.baseband.client.configuration.annotation.Range;
import com.baseband.client.module.Feature; import com.baseband.client.module.Feature;
import com.baseband.client.module.category.World; import com.baseband.client.module.category.World;
@ -9,12 +10,20 @@ import com.baseband.client.module.render.ClickGUI;
import com.baseband.client.util.adapt.SimpleWorldGenerator; import com.baseband.client.util.adapt.SimpleWorldGenerator;
import com.baseband.client.util.misc.Description; import com.baseband.client.util.misc.Description;
import com.baseband.client.util.misc.GlobalUtil; import com.baseband.client.util.misc.GlobalUtil;
import com.baseband.client.util.misc.Marker;
import com.baseband.client.util.misc.Trigger; import com.baseband.client.util.misc.Trigger;
import com.baseband.client.util.render.Pixels;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import de.tudbut.tools.Lock;
import java.util.Objects;
import static com.baseband.client.util.render.Tesselator.*; import static com.baseband.client.util.render.Tesselator.*;
@ -24,11 +33,24 @@ import static com.baseband.client.util.render.Tesselator.*;
public class SeedOverlay extends Feature { public class SeedOverlay extends Feature {
@Config("Seed") @Config("Seed")
@Description("The world seed you want to overlay")
public String seed = "enter the server seed"; public String seed = "enter the server seed";
@Config("Distance (chunks)") @Config("Distance (chunks)")
@Description("The distance at which chunks should be checked. Higher is a lot slower. §7(This is O(n^2).)")
@Gate(1)
@Range("0..8") @Range("0..8")
public int rd = 8; public int rd = 4;
@Config("Opacity")
@Description("The opacity of rendered overlay.")
@Range("0.01..0.8")
public float opacity = 0.2f;
@Marker(1)
boolean canSetRD = true;
@Marker(2)
boolean running = false;
SimpleWorldGenerator genOverworld = null, genNether = null, genEnd = null; SimpleWorldGenerator genOverworld = null, genNether = null, genEnd = null;
@ -38,56 +60,223 @@ public class SeedOverlay extends Feature {
} }
@Trigger("Generate now") @Trigger("Generate now")
@Description("Hit this after entering the Seed - this starts the world generators and initializes the render buffers.")
@Gate(1)
public void generate() { public void generate() {
BaseBand.ifFeaturePresent(ClickGUI.class, gui -> gui.setEnabled(false)); running = true;
long seed; canSetRD = false;
try { new Thread(() -> {
seed = Long.parseLong(this.seed); BaseBand.ifFeaturePresent(ClickGUI.class, gui -> gui.setEnabled(false));
} catch (NumberFormatException e) { long seed;
seed = this.seed.hashCode(); try {
} seed = Long.parseLong(this.seed);
BaseBand.notify("Creating world with seed " + seed + "..."); } catch (NumberFormatException e) {
genOverworld = SimpleWorldGenerator.overworld(mc.world.getWorldInfo(), seed); seed = this.seed.hashCode();
genNether = SimpleWorldGenerator.nether(mc.world.getWorldInfo(), seed);
genEnd = SimpleWorldGenerator.end(mc.world.getWorldInfo(), seed);
int rd = this.rd + 1;
int length = rd * 16 * 256 * rd * 16;
BaseBand.notify("World generators acquired. Allocating render buffer with " + (length * 4 / 1024) + "KB space.");
bufferPosition = new BlockPos((mc.player.chunkCoordX - 4) * 16, 0, (mc.player.chunkCoordZ - 4) * 16);
buffer = new int[rd * 16][256][rd * 16];
GlobalUtil.LOGGER.info("Allocated.");
for (int x = 0; x < rd * 16; x++) {
for (int z = 0; z < rd * 16; z++) {
buffer[x][0][z] = 0x800000ff;
} }
BaseBand.notify("Creating world with seed " + seed + "...");
int rd = this.rd * 2 + 1;
genOverworld = SimpleWorldGenerator.overworld(mc.world.getWorldInfo(), seed, rd);
genNether = SimpleWorldGenerator.nether(mc.world.getWorldInfo(), seed, rd);
genEnd = SimpleWorldGenerator.end(mc.world.getWorldInfo(), seed, rd);
int length = rd * 16 * 256 * rd * 16;
BaseBand.notify("World generators acquired. Allocating render buffer with " + (length * 4 / 1024) + "KB space.");
bufferPosition = new BlockPos((mc.player.chunkCoordX - this.rd) * 16, 0, (mc.player.chunkCoordZ - this.rd) * 16);
frontBuffer = new int[rd * 16][256][rd * 16];
backBuffer = new int[rd * 16][256][rd * 16];
GlobalUtil.LOGGER.info("Allocated.");
for (int x = 0; x < rd * 16; x++) {
for (int z = 0; z < rd * 16; z++) {
frontBuffer[x][0][z] = 0x800000ff;
backBuffer[x][0][z] = 0x800000ff;
}
}
GlobalUtil.LOGGER.info("Filled buffer with test state.");
BaseBand.notify("Render buffer created. Starting...");
setEnabled(true);
}, this + " init").start();
}
@Trigger("Stop world")
@Description("Shuts down the generators, frees the render buffers, disables the module. This must be done before changing the Distance.")
@Gate(2)
public void stopWorld() {
new Thread(() -> {
setEnabled(false);
running = false;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// these should already be stopped!
if(updater.isAlive() || generator.isAlive()) {
GlobalUtil.LOGGER.warn(this + " threads were still running when stopping the world. This should not happen! Stopping them forcefully.");
//noinspection deprecation
updater.stop();
//noinspection deprecation
generator.stop();
}
canSetRD = true;
genOverworld.destroy();
genNether.destroy();
genEnd.destroy();
genOverworld = null;
genNether = null;
genEnd = null;
bufferPosition = null;
frontBuffer = null;
backBuffer = null;
}, this + " stopper").start();
}
Thread updater, generator;
@Override
public void onEnable() {
updater = new Thread(this::updateSeedOverlay, this + " updater");
updater.start();
generator = new Thread(this::genLoop, this + " generator");
generator.start();
}
private void genLoop() {
Lock lock = new Lock();
while (enabled) {
lock.lock(100);
int rd = this.rd * 2 + 1;
net.minecraft.world.World mcWorld = mc.world;
EntityPlayerSP player = mc.player;
if(notIngame())
break;
SimpleWorldGenerator gen = getGen(mcWorld);
int ocx = (player.chunkCoordX - this.rd);
int ocz = (player.chunkCoordZ - this.rd);
gen.tick();
for (int x = -1; x < rd + 1; x++) {
for (int z = -1; z < rd + 1; z++) {
gen.provideChunk(ocx + x, ocz + z);
if(!enabled)
return;
}
}
lock.waitHere();
} }
GlobalUtil.LOGGER.info("Filled buffer with test state."); }
BaseBand.notify("Render buffer created. Starting...");
setEnabled(true); private SimpleWorldGenerator getGen(net.minecraft.world.World world) {
SimpleWorldGenerator gen;
switch (world.provider.getDimensionType()) {
case OVERWORLD:
gen = genOverworld;
break;
case NETHER:
gen = genNether;
break;
case THE_END:
gen = genEnd;
break;
default:
throw new RuntimeException("Dimension " + world.provider.getDimensionType() + " not available for SeedOverlay!");
}
return gen;
} }
BlockPos bufferPosition = null; BlockPos bufferPosition = null;
int[][][] buffer = null; int[][][] backBuffer = null;
int[][][] frontBuffer = null;
private void updateSeedOverlay() {
while (enabled) {
int rd = this.rd * 2 + 1;
net.minecraft.world.World world = mc.world;
EntityPlayerSP player = mc.player;
if(notIngame())
break;
SimpleWorldGenerator gen = getGen(world);
int ocx = (player.chunkCoordX - this.rd), ox = ocx * 16;
int ocz = (player.chunkCoordZ - this.rd), oz = ocz * 16;
Chunk[][] chunks = new Chunk[rd][rd];
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
chunks[x][z] = gen.getLoadedChunk(ocx + x, ocz + z);
}
}
int red = Pixels.mulTransparency(0xffff0000, opacity);
int green = Pixels.mulTransparency(0xff00ff00, opacity);
int yellow = Pixels.mulTransparency(0xffffff00, opacity);
for (int x = 0; x < backBuffer.length; x++) {
for (int z = 0; z < backBuffer[x][0].length; z++) {
if(!enabled)
return;
Chunk c = chunks[x / 16][z / 16];
Chunk rc = world.getChunk(ocx + x / 16, ocz + z / 16);
if(c == null || !c.isTerrainPopulated())
continue;
if(rc.isEmpty() || !rc.isTerrainPopulated())
continue;
for (int y = 0; y < backBuffer[x].length; y++) {
if(c.getBlockState(x, y, z).getBlock() == rc.getBlockState(x, y, z).getBlock()) {
backBuffer[x][y][z] = 0;
continue;
}
if(rc.getBlockState(x, y, z).getBlock() == Blocks.AIR) {
backBuffer[x][y][z] = red;
continue;
}
if(c.getBlockState(x, y, z).getBlock() == Blocks.AIR) {
backBuffer[x][y][z] = green;
continue;
}
backBuffer[x][y][z] = yellow;
}
}
}
swapBuffers(new BlockPos(ox, 0, oz));
}
}
private synchronized void swapBuffers(BlockPos bufferPosition) {
this.bufferPosition = bufferPosition;
int[][][] oldFront = this.frontBuffer;
this.frontBuffer = this.backBuffer;
this.backBuffer = oldFront;
}
@SubscribeEvent @SubscribeEvent
public void onRender(RenderWorldLastEvent event) { public synchronized void onRender(RenderWorldLastEvent event) {
if(buffer == null) { if(frontBuffer == null) {
BaseBand.notify("Please input a |Seed| and trigger |Generate now|"); BaseBand.notify("Please input a |Seed| and trigger |Generate now|");
toggle(); toggle();
return; return;
} }
Vec3d p = mc.player.getPositionEyes(event.getPartialTicks()); Vec3d p = Objects.requireNonNull(mc.getRenderViewEntity()).getPositionEyes(event.getPartialTicks());
ready(); ready();
translate(-p.x + bufferPosition.getX(), -p.y + bufferPosition.getY(), -p.z + bufferPosition.getZ()); translate(-p.x + bufferPosition.getX(), -p.y + bufferPosition.getY(), -p.z + bufferPosition.getZ());
color(0xffff00ff); // if this renders, this is an error color(0xffff00ff); // if this renders, this is an error
depth(false); depth(false);
begin(GL11.GL_QUADS); begin(GL11.GL_QUADS);
for (int x = 0; x < buffer.length; x++) { for (int x = 0; x < frontBuffer.length; x++) {
for (int y = 0; y < buffer[x].length; y++) { for (int y = 0; y < frontBuffer[x].length; y++) {
for (int z = 0; z < buffer[y].length; z++) { for (int z = 0; z < frontBuffer[x][y].length; z++) {
int c = buffer[x][y][z]; int c = frontBuffer[x][y][z];
if(c != 0) { if(c != 0) {
color(c); changeColor(c);
drawBlockFacesNow(x, y, z); drawBlockFacesNow(x, y, z);
} }
} }

View file

@ -1,11 +1,12 @@
package com.baseband.client.util.adapt; package com.baseband.client.util.adapt;
import com.baseband.client.Setup; import com.baseband.client.Setup;
import de.tudbut.obj.Vector2i; import com.baseband.client.util.misc.GlobalUtil;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.profiler.Profiler; import net.minecraft.profiler.Profiler;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.DimensionType; import net.minecraft.world.DimensionType;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldProvider; import net.minecraft.world.WorldProvider;
@ -25,74 +26,83 @@ import java.util.Map;
public class SimpleWorldGenerator implements IChunkProvider { public class SimpleWorldGenerator implements IChunkProvider {
final World world; public final World world;
final HashMap<Vector2i, Chunk> loaded = new HashMap<>(); final HashMap<ChunkPos, Chunk> loaded = new HashMap<>();
final IChunkGenerator generator; final IChunkGenerator generator;
final Minecraft mc = Minecraft.getMinecraft(); final Minecraft mc = Minecraft.getMinecraft();
public SimpleWorldGenerator(World world, IChunkGenerator generator) { final int distance;
private SimpleWorldGenerator(DummyWorld world, IChunkGenerator generator, int distance) {
this.world = world; this.world = world;
this.generator = generator; this.generator = generator;
this.distance = distance;
world.setChunkProvider(this);
} }
public static SimpleWorldGenerator overworld(WorldInfo original, long seed) { public static SimpleWorldGenerator overworld(WorldInfo original, long seed, int unloadDistance) {
NBTTagCompound nbt = original.cloneNBTCompound(null); NBTTagCompound nbt = original.cloneNBTCompound(null);
nbt.setLong("RandomSeed", seed); nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.OVERWORLD); DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.OVERWORLD);
return new SimpleWorldGenerator(world, new ChunkGeneratorOverworld(world, seed, true, null)); return new SimpleWorldGenerator(world, new ChunkGeneratorOverworld(world, seed, true, ""), unloadDistance);
} }
public static SimpleWorldGenerator nether(WorldInfo original, long seed) { public static SimpleWorldGenerator nether(WorldInfo original, long seed, int unloadDistance) {
NBTTagCompound nbt = original.cloneNBTCompound(null); NBTTagCompound nbt = original.cloneNBTCompound(null);
nbt.setLong("RandomSeed", seed); nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.NETHER); DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.NETHER);
return new SimpleWorldGenerator(world, new ChunkGeneratorHell(world, true, seed)); return new SimpleWorldGenerator(world, new ChunkGeneratorHell(world, true, seed), unloadDistance);
} }
public static SimpleWorldGenerator end(WorldInfo original, long seed) { public static SimpleWorldGenerator end(WorldInfo original, long seed, int unloadDistance) {
NBTTagCompound nbt = original.cloneNBTCompound(null); NBTTagCompound nbt = original.cloneNBTCompound(null);
nbt.setLong("RandomSeed", seed); nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.THE_END); DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.THE_END);
return new SimpleWorldGenerator(world, new ChunkGeneratorEnd(world, true, seed, new BlockPos(0,0,0))); return new SimpleWorldGenerator(world, new ChunkGeneratorEnd(world, true, seed, new BlockPos(0,0,0)), unloadDistance);
} }
@Nullable @Nullable
@Override @Override
public Chunk getLoadedChunk(int x, int z) { public Chunk getLoadedChunk(int x, int z) {
return loaded.get(new Vector2i(x, z)); return loaded.get(new ChunkPos(x, z));
} }
@Override @Override
@Nonnull @Nonnull
public Chunk provideChunk(int x, int z) { public Chunk provideChunk(int x, int z) {
Chunk chunk = getLoadedChunk(x, z); Chunk chunk = getLoadedChunk(x, z);
return chunk != null ? chunk : gen(x, z); if(chunk == null)
return gen(x, z);
return chunk;
} }
public Chunk gen(int x, int z) { public synchronized Chunk gen(int x, int z) {
GlobalUtil.LOGGER.debug(this + " is generating chunk at {} {}", x, z);
Chunk chunk = generator.generateChunk(x, z); Chunk chunk = generator.generateChunk(x, z);
loaded.put(new Vector2i(x, z), chunk); loaded.put(chunk.getPos(), chunk);
chunk.onLoad(); chunk.onLoad();
chunk.populate(this, generator); chunk.populate(this, generator);
chunk.onTick(true); chunk.onTick(true);
GlobalUtil.LOGGER.debug("Chunk gen finished");
return chunk; return chunk;
} }
@Override @Override
public boolean tick() { public synchronized boolean tick() {
for (Map.Entry<Vector2i, Chunk> entry : loaded.entrySet()) { for (Map.Entry<ChunkPos, Chunk> entry : loaded.entrySet().toArray(new Map.Entry[0])) {
Vector2i pos = entry.getKey(); ChunkPos pos = entry.getKey();
if(Math.abs(mc.player.chunkCoordX - pos.getX()) > mc.gameSettings.renderDistanceChunks) { Chunk chunk = entry.getValue();
entry.getValue().onUnload(); if(Math.abs(mc.player.chunkCoordX - pos.x) > distance) {
loaded.remove(pos); onUnload(pos, chunk);
continue; continue;
} }
if(Math.abs(mc.player.chunkCoordZ - pos.getY()) > mc.gameSettings.renderDistanceChunks) { if(Math.abs(mc.player.chunkCoordZ - pos.z) > distance) {
entry.getValue().onUnload(); onUnload(pos, chunk);
loaded.remove(pos);
continue; continue;
} }
} }
@ -100,20 +110,39 @@ public class SimpleWorldGenerator implements IChunkProvider {
return false; return false;
} }
private void onUnload(ChunkPos pos, Chunk chunk) {
GlobalUtil.LOGGER.debug(this + " is unloading chunk at {} {}", pos.x, pos.z);
chunk.onUnload();
loaded.remove(pos);
}
@Override @Override
@Nonnull @Nonnull
public String makeString() { public String makeString() {
return Setup.get().Name + ".SimpleWorldGenerator"; return Setup.get().Name + "." + this;
}
@Override
public String toString() {
return "SimpleWorldGenerator";
} }
@Override @Override
public boolean isChunkGeneratedAt(int x, int z) { public boolean isChunkGeneratedAt(int x, int z) {
return loaded.containsKey(new Vector2i(x, z)); return loaded.containsKey(new ChunkPos(x, z));
}
public synchronized void destroy() {
for (Map.Entry<ChunkPos, Chunk> entry : loaded.entrySet().toArray(new Map.Entry[0])) {
onUnload(entry.getKey(), entry.getValue());
}
} }
private static class DummyWorld extends World { private static class DummyWorld extends World {
public DummyWorld(WorldInfo info, DimensionType type) { public DummyWorld(WorldInfo info, DimensionType type) {
super(new SaveHandlerMP(), info, new DummyWorldProvider(type), new Profiler(), false); super(new SaveHandlerMP(), info, new DummyWorldProvider(type), new Profiler(), false);
provider.setWorld(this);
} }
@Override @Override
@ -123,8 +152,12 @@ public class SimpleWorldGenerator implements IChunkProvider {
} }
@Override @Override
protected boolean isChunkLoaded(int x, int y, boolean b) { protected boolean isChunkLoaded(int x, int z, boolean b) {
throw new IllegalAccessError("Tried to treat dummy world like a real world"); return chunkProvider.isChunkGeneratedAt(x, z);
}
public void setChunkProvider(SimpleWorldGenerator chunkProvider) {
this.chunkProvider = chunkProvider;
} }
} }

View file

@ -37,12 +37,18 @@ public class Tesselator {
glColor4ub(bytes[1], bytes[2], bytes[3], bytes[0]); glColor4ub(bytes[1], bytes[2], bytes[3], bytes[0]);
color = argb; color = argb;
} }
public static void changeColor(int argb) {
byte[] bytes = PBIC.putInt(argb);
glColor4ub(bytes[1], bytes[2], bytes[3], bytes[0]);
}
public static void depth(boolean b) { public static void depth(boolean b) {
depth = b; depth = b;
if(b) if(b) {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
else } else {
glDisable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
}
} }
public static void put(double x, double y, double z) { public static void put(double x, double y, double z) {
glVertex3d(x,y,z); glVertex3d(x,y,z);