Merge pull request #77 from rafern/master

Add LocateFeature command
This commit is contained in:
noil 2021-08-08 22:17:10 -04:00 committed by GitHub
commit c0d0350303
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 140 additions and 0 deletions

View File

@ -0,0 +1,139 @@
package me.rigamortis.seppuku.impl.command;
import me.rigamortis.seppuku.Seppuku;
import me.rigamortis.seppuku.api.command.Command;
import me.rigamortis.seppuku.api.util.StringUtil;
import me.rigamortis.seppuku.impl.management.WorldManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.IChunkGenerator;
import net.minecraft.world.gen.MapGenBase;
import net.minecraft.world.gen.structure.MapGenStructure;
import net.minecraft.world.storage.SaveHandlerMP;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.common.DimensionManager;
import java.lang.reflect.Field;
public final class LocateFeatureCommand extends Command {
public LocateFeatureCommand() {
super("LocateFeature", new String[]{"LocFeature", "LocateFeat", "LF"}, "Like /locate, but client-side and with an option to override the origin for calculating the nearest feature", "LocateFeature <Feature name>\nLocate <Feature name> <X> <Z>");
}
@Override
public void exec(String input) {
if (!this.clamp(input, 2, 4)) {
this.printUsage();
return;
}
final String[] split = input.split(" ");
if (split.length == 3) {
this.printUsage();
return;
}
final BlockPos originPos;
final String originHint;
if (split.length == 4) {
if (StringUtil.isInt(split[2])) {
if (StringUtil.isInt(split[3])) {
originPos = new BlockPos(Integer.parseInt(split[2]), 64, Integer.parseInt(split[3]));
} else {
Seppuku.INSTANCE.errorChat("Unknown number " + "\247f\"" + split[3] + "\"");
return;
}
} else {
Seppuku.INSTANCE.errorChat("Unknown number " + "\247f\"" + split[2] + "\"");
return;
}
originHint = "to " + String.valueOf(originPos.getX()) + ", " + String.valueOf(originPos.getZ());
} else {
originPos = new BlockPos(Minecraft.getMinecraft().player.posX, 64, Minecraft.getMinecraft().player.posZ);
originHint = "you";
}
final ServerData serverData = Minecraft.getMinecraft().getCurrentServerData();
if (serverData != null) {
final WorldManager.WorldData worldData = Seppuku.INSTANCE.getWorldManager().find(serverData.serverIP);
if (worldData != null) {
final FakeWorld world = new FakeWorld(worldData.getSeed());
final BlockPos pos = world.getNearestStructurePos(split[1], originPos);
if (pos == null) {
Seppuku.INSTANCE.errorChat("No structure found " + "\247f\"" + split[1] + "\"");
} else {
Seppuku.INSTANCE.logChat(split[1] + " nearest " + originHint + " is at " + String.valueOf(pos.getX()) + ", " + String.valueOf(pos.getZ()));
}
} else {
Seppuku.INSTANCE.errorChat("Seed not set. Use the seed command first");
}
} else {
Seppuku.INSTANCE.errorChat("Cannot locate feature on localhost, since localhost has no seed");
}
}
private class FakeWorld extends World {
final IChunkGenerator chunkGenerator;
public FakeWorld(long seed) {
this(Minecraft.getMinecraft().world, seed);
}
public FakeWorld(WorldClient worldClient, long seed) {
super(new SaveHandlerMP(), new WorldInfo(new WorldSettings(seed, worldClient.getWorldInfo().getGameType(), true, worldClient.getWorldInfo().isHardcoreModeEnabled(), worldClient.getWorldInfo().getTerrainType()), "MpServer"), DimensionManager.createProviderFor(worldClient.provider.getDimension()), null, true);
this.provider.setWorld(this);
this.chunkGenerator = this.provider.createChunkGenerator();
// I would use getDeclaredField("world") here, but it fails outside the dev environment
// I also tried using ObfuscationReflectionHelper but it wouldn't compile, so I gave up
Field worldField = null;
for(Field field : MapGenBase.class.getDeclaredFields()) {
if (World.class.isAssignableFrom(field.getType())) {
worldField = field;
break;
}
}
if (worldField == null) {
Seppuku.INSTANCE.errorChat("Could not find \"world\" field; feature location will fail");
return;
}
worldField.setAccessible(true);
for(Field field : this.chunkGenerator.getClass().getDeclaredFields()) {
try {
if (MapGenStructure.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
MapGenBase structureGenerator = (MapGenBase) field.get(this.chunkGenerator);
worldField.set(structureGenerator, this);
}
} catch(IllegalAccessException e) {
Seppuku.INSTANCE.errorChat("Potential feature type skipped due to exception");
e.printStackTrace();
}
}
}
protected IChunkProvider createChunkProvider()
{
return null;
}
protected boolean isChunkLoaded(int x, int z, boolean allowEmpty)
{
return false;
}
public BlockPos getNearestStructurePos(String structureName, BlockPos position) {
return this.chunkGenerator.getNearestStructurePos(this, structureName, position, false);
}
}
}

View File

@ -72,6 +72,7 @@ public final class CommandManager {
this.commandList.add(new LastInvCommand());
this.commandList.add(new SearchCommand());
this.commandList.add(new PlayCommand());
this.commandList.add(new LocateFeatureCommand());
//create commands for every value within every module
loadValueCommands();