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)
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 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
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 BaseBand bb;
@ -35,7 +38,7 @@ public abstract class Feature extends ToggleButton implements SetCommand {
public Category category;
@Marker(1)
@Marker(M_ENABLED)
public boolean enabled = defaultEnable();
@Config("Toggle")
@ -176,7 +179,7 @@ public abstract class Feature extends ToggleButton implements SetCommand {
}
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);
if(description != null)

View file

@ -40,7 +40,7 @@ public class HUD extends Feature {
private final long start = new Date().getTime();
public Notification(String text) {
this(text, 5000);
this(text, 10000);
}
public Notification(String text, int ms) {
@ -181,7 +181,7 @@ public class HUD extends Feature {
int localYSize = ySize;
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;
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.configuration.annotation.Config;
import com.baseband.client.configuration.annotation.Gate;
import com.baseband.client.configuration.annotation.Range;
import com.baseband.client.module.Feature;
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.misc.Description;
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.render.Pixels;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11;
import de.tudbut.tools.Lock;
import java.util.Objects;
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 {
@Config("Seed")
@Description("The world seed you want to overlay")
public String seed = "enter the server seed";
@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")
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;
@ -38,56 +60,223 @@ public class SeedOverlay extends Feature {
}
@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() {
BaseBand.ifFeaturePresent(ClickGUI.class, gui -> gui.setEnabled(false));
long seed;
try {
seed = Long.parseLong(this.seed);
} catch (NumberFormatException e) {
seed = this.seed.hashCode();
}
BaseBand.notify("Creating world with seed " + seed + "...");
genOverworld = SimpleWorldGenerator.overworld(mc.world.getWorldInfo(), seed);
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;
running = true;
canSetRD = false;
new Thread(() -> {
BaseBand.ifFeaturePresent(ClickGUI.class, gui -> gui.setEnabled(false));
long seed;
try {
seed = Long.parseLong(this.seed);
} catch (NumberFormatException e) {
seed = this.seed.hashCode();
}
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;
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
public void onRender(RenderWorldLastEvent event) {
if(buffer == null) {
public synchronized void onRender(RenderWorldLastEvent event) {
if(frontBuffer == null) {
BaseBand.notify("Please input a |Seed| and trigger |Generate now|");
toggle();
return;
}
Vec3d p = mc.player.getPositionEyes(event.getPartialTicks());
Vec3d p = Objects.requireNonNull(mc.getRenderViewEntity()).getPositionEyes(event.getPartialTicks());
ready();
translate(-p.x + bufferPosition.getX(), -p.y + bufferPosition.getY(), -p.z + bufferPosition.getZ());
color(0xffff00ff); // if this renders, this is an error
depth(false);
begin(GL11.GL_QUADS);
for (int x = 0; x < buffer.length; x++) {
for (int y = 0; y < buffer[x].length; y++) {
for (int z = 0; z < buffer[y].length; z++) {
int c = buffer[x][y][z];
for (int x = 0; x < frontBuffer.length; x++) {
for (int y = 0; y < frontBuffer[x].length; y++) {
for (int z = 0; z < frontBuffer[x][y].length; z++) {
int c = frontBuffer[x][y][z];
if(c != 0) {
color(c);
changeColor(c);
drawBlockFacesNow(x, y, z);
}
}

View file

@ -1,11 +1,12 @@
package com.baseband.client.util.adapt;
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.nbt.NBTTagCompound;
import net.minecraft.profiler.Profiler;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
@ -25,74 +26,83 @@ import java.util.Map;
public class SimpleWorldGenerator implements IChunkProvider {
final World world;
final HashMap<Vector2i, Chunk> loaded = new HashMap<>();
public final World world;
final HashMap<ChunkPos, Chunk> loaded = new HashMap<>();
final IChunkGenerator generator;
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.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);
nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.OVERWORLD);
return new SimpleWorldGenerator(world, new ChunkGeneratorOverworld(world, seed, true, null));
DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.OVERWORLD);
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);
nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.NETHER);
return new SimpleWorldGenerator(world, new ChunkGeneratorHell(world, true, seed));
DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.NETHER);
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);
nbt.setLong("RandomSeed", seed);
World world = new DummyWorld(new WorldInfo(nbt), DimensionType.THE_END);
return new SimpleWorldGenerator(world, new ChunkGeneratorEnd(world, true, seed, new BlockPos(0,0,0)));
DummyWorld world = new DummyWorld(new WorldInfo(nbt), DimensionType.THE_END);
return new SimpleWorldGenerator(world, new ChunkGeneratorEnd(world, true, seed, new BlockPos(0,0,0)), unloadDistance);
}
@Nullable
@Override
public Chunk getLoadedChunk(int x, int z) {
return loaded.get(new Vector2i(x, z));
return loaded.get(new ChunkPos(x, z));
}
@Override
@Nonnull
public Chunk provideChunk(int x, int 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);
loaded.put(new Vector2i(x, z), chunk);
loaded.put(chunk.getPos(), chunk);
chunk.onLoad();
chunk.populate(this, generator);
chunk.onTick(true);
GlobalUtil.LOGGER.debug("Chunk gen finished");
return chunk;
}
@Override
public boolean tick() {
public synchronized boolean tick() {
for (Map.Entry<Vector2i, Chunk> entry : loaded.entrySet()) {
Vector2i pos = entry.getKey();
if(Math.abs(mc.player.chunkCoordX - pos.getX()) > mc.gameSettings.renderDistanceChunks) {
entry.getValue().onUnload();
loaded.remove(pos);
for (Map.Entry<ChunkPos, Chunk> entry : loaded.entrySet().toArray(new Map.Entry[0])) {
ChunkPos pos = entry.getKey();
Chunk chunk = entry.getValue();
if(Math.abs(mc.player.chunkCoordX - pos.x) > distance) {
onUnload(pos, chunk);
continue;
}
if(Math.abs(mc.player.chunkCoordZ - pos.getY()) > mc.gameSettings.renderDistanceChunks) {
entry.getValue().onUnload();
loaded.remove(pos);
if(Math.abs(mc.player.chunkCoordZ - pos.z) > distance) {
onUnload(pos, chunk);
continue;
}
}
@ -100,20 +110,39 @@ public class SimpleWorldGenerator implements IChunkProvider {
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
@Nonnull
public String makeString() {
return Setup.get().Name + ".SimpleWorldGenerator";
return Setup.get().Name + "." + this;
}
@Override
public String toString() {
return "SimpleWorldGenerator";
}
@Override
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 {
public DummyWorld(WorldInfo info, DimensionType type) {
super(new SaveHandlerMP(), info, new DummyWorldProvider(type), new Profiler(), false);
provider.setWorld(this);
}
@Override
@ -123,8 +152,12 @@ public class SimpleWorldGenerator implements IChunkProvider {
}
@Override
protected boolean isChunkLoaded(int x, int y, boolean b) {
throw new IllegalAccessError("Tried to treat dummy world like a real world");
protected boolean isChunkLoaded(int x, int z, boolean b) {
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]);
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) {
depth = b;
if(b)
if(b) {
glEnable(GL_DEPTH_TEST);
else
} else {
glDisable(GL_DEPTH_TEST);
glClear(GL_DEPTH_BUFFER_BIT);
}
}
public static void put(double x, double y, double z) {
glVertex3d(x,y,z);