Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Biome Scanner #12

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions src/main/java/dev/enjarai/minitardis/component/BiomeScanner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package dev.enjarai.minitardis.component;

import java.util.Iterator;
import java.util.function.BiConsumer;

import org.joml.Vector2i;

import dev.enjarai.minitardis.block.ModBlocks;
import net.minecraft.block.BlockState;
import net.minecraft.block.MapColor;
import net.minecraft.block.MapColor.Brightness;
import net.minecraft.fluid.Fluids;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;

public class BiomeScanner {
public static final int RANGE = 9216;
public static final int TOTAL_BLOCKS = RANGE * RANGE;

private final int maxPerTick;
private final byte[] biomeMap = new byte[TOTAL_BLOCKS];
private Iterator<Vector2i> iterator = newIterator();
private boolean shouldScanNextTick;
private boolean isZAxis;

public BiomeScanner(int maxPerTick) {
this.maxPerTick = maxPerTick;
}

public void tick() {
if (shouldScanNextTick) {
tardis.getDestinationWorld().ifPresent(world -> {
@SuppressWarnings("OptionalGetWithoutIsPresent")
var location = tardis.getDestination().get();

iterator = update(world, biomeMap, iterator, (pos3, pos2) -> pos3.set(location.pos()).move(pos2.x, 0, pos2.y));
});

shouldScanNextTick = false;
} else {
iterator = newIterator();
}
}

public byte getFor(int x, int y) {
return getFor(getIndex(x, y));
}

public byte getFor(int pos) {
return biomeMap[pos];
}

public void shouldScanNextTick() {
shouldScanNextTick = true;
}

private Iterator<Vector2i> update(ServerWorld world, byte[] map, Iterator<Vector2i> iterator, BiConsumer<BlockPos.Mutable, Vector2i> posApplier) {
var pos3 = new BlockPos.Mutable();
var pos2 = new Vector2i();

for (int i = 0; i < maxPerTick; i++) {
if (!iterator.hasNext()) return newIterator();

pos2.set(iterator.next());
posApplier.accept(pos3, pos2);
pos2.add(RANGE / 2 - 1, RANGE / 2 - 1);

byte value = getValue(world, pos3);
map[getIndex(pos2)] = value;
}

return iterator;
}

private byte getValue(ServerWorld world, BlockPos pos) {
switch (world.getBiome(pos).getKey().get().getValue().toTranslationKey()) {
case "biome.minecraft.ocean":
return (byte) MapColor.DARK_AQUA.id;
default:
return (byte) MapColor.CYAN.id;
}
}

public static int getIndex(Vector2i pos) {
return getIndex(pos.x, pos.y);
}

public static int getIndex(int x, int y) {
return (x + y * RANGE) % TOTAL_BLOCKS;
}

public static Vector2i getPos(int index) {
return new Vector2i(index % RANGE - RANGE / 2, index / RANGE - RANGE / 2);
}

// https://stackoverflow.com/questions/3706219/algorithm-for-iterating-over-an-outward-spiral-on-a-discrete-2d-grid-from-the-or
private static Iterator<Vector2i> newIterator() {
return new Iterator<>() {
// direction in which we move right now
final Vector2i direction = new Vector2i(1, 0);
// length of current segment
int segment_length = 1;

// current position and how much of current segment we passed
final Vector2i current = new Vector2i(0, 0);
int segment_passed = 0;
int k = 0;

@Override
public boolean hasNext() {
return k < TOTAL_BLOCKS;
}

@Override
public Vector2i next() {
k++;
// make a step, add direction vector to current position
current.add(direction);
++segment_passed;

if (segment_passed == segment_length) {
// done with current segment
segment_passed = 0;

// 'rotate' directions
//noinspection SuspiciousNameCombination
direction.set(-direction.y, direction.x);

// increase segment length if necessary
if (direction.y == 0) {
++segment_length;
}
}

return current;
}
};
}
}
6 changes: 6 additions & 0 deletions src/main/java/dev/enjarai/minitardis/component/Tardis.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public class Tardis {
@Nullable
RuntimeWorldHandle interiorWorld;
DestinationScanner destinationScanner = new DestinationScanner(this, 128);
BiomeScanner biomeScanner = new BiomeScanner(this, 128);
private int sparksQueued;

private final UUID uuid;
Expand Down Expand Up @@ -170,6 +171,7 @@ public void tick() {
}

destinationScanner.tick();
biomeScanner.tick();
}

public ServerWorld getInteriorWorld() {
Expand All @@ -194,6 +196,10 @@ public Optional<ServerWorld> getDestinationWorld() {
public DestinationScanner getDestinationScanner() {
return destinationScanner;
}

public BiomeScanner getBiomeScanner() {
return biomeScanner;
}

private void initializeInteriorWorld() {
var server = holder.getServer();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package dev.enjarai.minitardis.component.screen.app;

import java.util.List;
import java.util.NoSuchElementException;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import dev.enjarai.minitardis.block.console.ScreenBlockEntity;
import dev.enjarai.minitardis.canvas.TardisCanvasUtils;
import dev.enjarai.minitardis.component.BiomeScanner;
import dev.enjarai.minitardis.component.DestinationScanner;
import dev.enjarai.minitardis.component.TardisControl;
import dev.enjarai.minitardis.component.screen.element.SmallButtonElement;
import eu.pb4.mapcanvas.api.core.CanvasColor;
import eu.pb4.mapcanvas.api.core.DrawableCanvas;
import eu.pb4.mapcanvas.api.utils.CanvasUtils;
import eu.pb4.mapcanvas.impl.view.Rotate90ClockwiseView;
import net.minecraft.block.MapColor;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ClickType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.source.BiomeCoords;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus;

public class BiomeScannerApp implements ScreenApp {
//public static final Codec<BiomeScannerApp> CODEC = RecordCodecBuilder.create(instance -> instance.group(
// h.optionalFieldOf("biome_scanner", List.of()).forGetter(app -> app.scanner)
//).apply(instance, BiomeScannerApp::new));

private final BiomeScanner scanner;

@Override
public AppView getView(TardisControl controls) {
return new ElementHoldingView(controls) {
//{
//addElement(new SmallButtonElement(96 + 2, 2 + 14, "XAxis", controls -> controls.getTardis().getDestinationScanner().useXAxis()));
//addElement(new SmallButtonElement(96 + 2, 2 + 14 + 14, "ZAxis", controls -> controls.getTardis().getDestinationScanner().useZAxis()));
//}

@Override
public void draw(ScreenBlockEntity blockEntity, DrawableCanvas canvas) {
for (int x = 0; x < BiomeScanner.RANGE; x++) {
for (int y = 0; y < BiomeScanner.RANGE; y++) {
byte value = controls.getTardis().getBiomeScanner().getFor(x, y);
var color = CanvasColor.from(MapColor.get(value), MapColor.Brightness.NORMAL);
canvas.set(x, -y - 1 + BiomeScanner.RANGE, color);
}
}

CanvasUtils.draw(canvas, 96, 64, TardisCanvasUtils.getSprite("coord_widget_x"));
controls.getTardis().getDestination().ifPresent(destination -> {
var rotation = destination.facing().getHorizontal();
//if (isZ) {
// rotation = (rotation + 3) % 4;
//}

//DrawableCanvas view = TardisCanvasUtils.getSprite("destination_facing_widget");
//for (int i = 0; i < rotation; i++) {
// view = new Rotate90ClockwiseView(view);
//}
//CanvasUtils.draw(canvas, 96, 64, view);
});

super.draw(blockEntity, canvas);
}

@Override
public void screenTick(ScreenBlockEntity blockEntity) {
controls.getTardis().getBiomeScanner().shouldScanNextTick();
}
};
}


@Override
public void drawIcon(TardisControl controls, ScreenBlockEntity blockEntity, DrawableCanvas canvas) {
CanvasUtils.draw(canvas, 0, 0, TardisCanvasUtils.getSprite("app/dummy"));
}

@Override
public ScreenAppType<?> getType() {
return ScreenAppTypes.BIOME_SCANNER;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
public class ScreenAppTypes {
public static final ScreenAppType<DummyApp> DUMMY = register("dummy", DummyApp.CODEC, DummyApp::new);
public static final ScreenAppType<ScannerApp> SCANNER = register("scanner", ScannerApp.CODEC, ScannerApp::new, true);
public static final ScreenAppType<BiomeScannerApp> BIOME_SCANNER = register("biome_scanner", BiomeScannerApp.CODEC, BiomeScannerApp::new, true);
public static final ScreenAppType<GpsApp> GPS = register("gps", GpsApp.CODEC, GpsApp::new);
public static final ScreenAppType<BadAppleApp> BAD_APPLE = register("bad_apple", BadAppleApp.CODEC, BadAppleApp::new, true);
public static final ScreenAppType<StatusApp> STATUS = register("status", StatusApp.CODEC, StatusApp::new);
Expand Down