package jas.spawner.modern.command;
import jas.spawner.modern.MVELProfile;
import jas.spawner.modern.spawner.CountInfo;
import jas.spawner.modern.spawner.CustomSpawner;
import jas.spawner.modern.spawner.Tags;
import jas.spawner.modern.spawner.biome.group.BiomeHelper;
import jas.spawner.modern.spawner.biome.structure.StructureHandler;
import jas.spawner.modern.spawner.creature.entry.BiomeSpawnListRegistry;
import jas.spawner.modern.spawner.creature.entry.SpawnListEntry;
import jas.spawner.modern.spawner.creature.handler.LivingGroupRegistry;
import jas.spawner.modern.spawner.creature.handler.LivingHandler;
import jas.spawner.modern.spawner.creature.handler.LivingHandlerRegistry;
import jas.spawner.modern.spawner.creature.handler.LivingHelper;
import jas.spawner.modern.spawner.creature.type.CreatureType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.MathHelper;
import net.minecraft.world.biome.BiomeGenBase;
public class CommandCanSpawnHere extends CommandJasBase {
/*
* Number of trials to run canSpawnHere to rule out random chance of success/failure.
*
* This was chosen such that to give a ~95% accuracy to the minimum accepted deviation in chance which is 1%. Any
* entity that spawns at least 1% of the time should be detected properly >=95% of the time.
*
* CHANCE_OF_SUCCESS = 0.95 >= = 1-(1-TRIAL_CHANCE/100)^SIMULATION_TRIALS. TRIAL_CHANCE is chance out of 100 that
* the entity would spawn.
*/
private static final int SIMULATION_TRIALS = 300;
public String getCommandName() {
return "canspawnhere";
}
/**
* Return the required permission level for this command.
*/
public int getRequiredPermissionLevel() {
return 2;
}
@Override
public String getCommandUsage(ICommandSender commandSender) {
return "commands.jascanspawnhere.usage";
}
@Override
public void process(ICommandSender commandSender, String[] stringArgs) {
if (stringArgs.length == 0 || stringArgs.length > 2) {
throw new WrongUsageException("commands.jascanspawnhere.usage", new Object[0]);
}
EntityPlayer targetPlayer = stringArgs.length == 1 ? getPlayer(commandSender,
commandSender.getCommandSenderName()) : getPlayer(commandSender, stringArgs[0]);
String entityName = stringArgs.length == 1 ? stringArgs[0] : stringArgs[1];
if (!isValidEntityName(entityName)) {
throw new WrongUsageException("commands.jascanspawnhere.entitynotfound", new Object[0]);
}
EntityLiving entity = getTargetEntity(entityName, targetPlayer);
LivingGroupRegistry groupRegistry = MVELProfile.worldSettings().livingGroupRegistry();
LivingHandlerRegistry handlerRegistry = MVELProfile.worldSettings().livingHandlerRegistry();
List<LivingHandler> livingHandlers = handlerRegistry.getLivingHandlers(groupRegistry.EntityClasstoJASName
.get(entity.getClass()));
if (livingHandlers.isEmpty()) {
throw new WrongUsageException("commands.jascanspawnhere.entityhasnogroups", new Object[0]);
}
for (LivingHandler livingHandler : livingHandlers) {
CreatureType livingType = MVELProfile.worldSettings().creatureTypeRegistry()
.getCreatureType(livingHandler.creatureTypeID);
if (livingType == null) {
commandSender.addChatMessage(new ChatComponentText(String.format(
"Entity %s is of type NONE and thus will never spawn.", entityName)));
return;
}
CountInfo countInfo = CustomSpawner.spawnCounter.countEntities(entity.worldObj);
/* Get local spawnlist. Reminder: Biomes are only used when a structure is absent or empty */
boolean isBiome = false;
List<SpawnListEntry> spawnlistentries = new ArrayList<SpawnListEntry>(3);
String locationName = getMatchingStructureSpawnListEntries(livingHandler.livingID, entity, spawnlistentries);
String structureName = locationName;
if (spawnlistentries.isEmpty()) {
isBiome = true;
locationName = getMatchingBiomeSpawnListEntries(livingHandler.livingID, entity, livingType,
spawnlistentries);
}
if (spawnlistentries.isEmpty()) {
spawnlistentries.add(null);
}
StringBuilder resultMessage = new StringBuilder();
if (livingHandlers.size() > 1) {
resultMessage.append("{Group ").append(livingHandler.livingID).append(": ");
}
Iterator<SpawnListEntry> iterator = spawnlistentries.iterator();
while (iterator.hasNext()) {
SpawnListEntry spawnListEntry = iterator.next();
if (spawnlistentries.size() > 1) {
resultMessage.append("{");
}
resultMessage.append(
canEntitySpawnHere(targetPlayer, entity, livingHandler, livingType, spawnListEntry, entityName,
countInfo)).append(": ");
resultMessage.append(canEntityTypeSpawnHere(targetPlayer, entity, livingType, countInfo)).append(" ");
resultMessage.append(canLivingHandlerSpawnHere(targetPlayer, entity, livingHandler, countInfo)).append(
" ");
if (!isBiome) {
resultMessage.append(canSpawnListSpawnHere(targetPlayer, entity, livingHandler, spawnListEntry,
locationName, false, countInfo));
} else {
/* If structureName is !null a structure is present but the spawnlist was empty so default to biome */
if (structureName != null) {
resultMessage.append("\u00A7b").append("Empty S: ").append(structureName)
.append(" spawnlist defaults to biome. ").append("\u00A7r");
}
resultMessage.append(canSpawnListSpawnHere(targetPlayer, entity, livingHandler, spawnListEntry,
locationName, true, countInfo));
}
if (spawnlistentries.size() > 1) {
resultMessage.append("}");
if (iterator.hasNext()) {
resultMessage.append(" ");
}
}
}
if (livingHandlers.size() > 1) {
resultMessage.append("}");
}
commandSender.addChatMessage(new ChatComponentText(resultMessage.toString()));
}
}
private boolean isValidEntityName(String entityName) {
LivingGroupRegistry livingGroupRegistry = MVELProfile.worldSettings().livingGroupRegistry();
for (String mapping : livingGroupRegistry.JASNametoEntityClass.keySet()) {
if (entityName.equals(mapping)) {
return true;
}
}
return false;
}
private EntityLiving getTargetEntity(String entityName, EntityPlayer targetPlayer) {
EntityLiving entity;
try {
LivingGroupRegistry livingGroupRegistry = MVELProfile.worldSettings().livingGroupRegistry();
@SuppressWarnings("unchecked")
Class<? extends EntityLiving> entityClass = livingGroupRegistry.JASNametoEntityClass.get(entityName);
entity = (EntityLiving) LivingHelper.instantiateEntity(entityClass, targetPlayer.worldObj);
} catch (Exception exception) {
throw new WrongUsageException("commands.jascanspawnhere.cannotinstantiateentity", new Object[0]);
}
entity.setLocationAndAngles(targetPlayer.posX, targetPlayer.posY, targetPlayer.posZ, targetPlayer.rotationYaw,
targetPlayer.rotationPitch);
return entity;
}
private String getMatchingStructureSpawnListEntries(String livingGroupID, EntityLiving entity,
Collection<SpawnListEntry> matchingSpawnListEntries) {
String structureName;
for (StructureHandler StructureHandler : MVELProfile.worldSettings().structureHandlerRegistry()
.handlers()) {
structureName = StructureHandler.getStructure(entity.worldObj, (int) entity.posX, (int) entity.posY,
(int) entity.posZ);
if (structureName != null) {
for (String structureKey : StructureHandler.getStructureKeys()) {
if (structureName.equals(structureKey)) {
for (SpawnListEntry entry : StructureHandler.getStructureSpawnList(structureKey)) {
if (livingGroupID.equals(entry.livingGroupID)) {
matchingSpawnListEntries.add(entry);
}
}
return structureKey;
}
}
}
}
return null;
}
private String getMatchingBiomeSpawnListEntries(String livingGroupID, Entity entity, CreatureType livingType,
Collection<SpawnListEntry> matchingSpawnListEntries) {
BiomeGenBase biome = entity.worldObj.getBiomeGenForCoords((int) entity.posX, (int) entity.posZ);
String packageBiome = BiomeHelper.getPackageName(biome);
BiomeSpawnListRegistry biomeSpawnListRegistry = MVELProfile.worldSettings().biomeSpawnListRegistry();
for (SpawnListEntry spawnListEntry : biomeSpawnListRegistry.getSpawnListFor(livingType.typeID, packageBiome)) {
if (spawnListEntry.livingGroupID.equals(livingGroupID)) {
matchingSpawnListEntries.add(spawnListEntry);
}
}
String shortName = MVELProfile.worldSettings().biomeGroupRegistry().biomePckgToMapping().get(packageBiome);
return shortName == null ? biome.biomeName : shortName;
}
private String canEntitySpawnHere(EntityPlayer targetPlayer, EntityLiving entity, LivingHandler livingHandler,
CreatureType livingType, SpawnListEntry spawnListEntry, String entityName, CountInfo countInfo) {
String failureMessage = "\u00A7c".concat(entityName).concat(" cannot spawn").concat("\u00A7r");
/* Check Entity Type */
{
boolean tempSpawning = targetPlayer.preventEntitySpawning;
targetPlayer.preventEntitySpawning = false;
Tags tags = new Tags(entity.worldObj, countInfo, MathHelper.floor_double(entity.posX),
MathHelper.floor_double(entity.boundingBox.minY), MathHelper.floor_double(entity.posZ));
boolean canTypeSpawn = livingType.canSpawnAtLocation(entity.worldObj, tags, (int) entity.posX, (int) entity.posY,
(int) entity.posZ);
targetPlayer.preventEntitySpawning = tempSpawning;
if (canTypeSpawn == false) {
return failureMessage;
}
}
boolean tempSpawning = targetPlayer.preventEntitySpawning;
targetPlayer.preventEntitySpawning = false;
boolean canSpawn = false;
if (spawnListEntry != null) {
for (int i = 0; i < SIMULATION_TRIALS; i++) {
if (livingHandler.getCanSpawnHere(entity, spawnListEntry, countInfo)) {
canSpawn = true;
break;
}
}
}
targetPlayer.preventEntitySpawning = tempSpawning;
if (canSpawn) {
StringBuilder builder = new StringBuilder();
builder.append("\u00A7a").append(entityName).append(" can spawn").append("\u00A7r");
return builder.toString();
} else {
return failureMessage;
}
}
private String canEntityTypeSpawnHere(EntityPlayer targetPlayer, EntityLiving entity, CreatureType livingType, CountInfo countInfo) {
Tags tags = new Tags(entity.worldObj, countInfo, MathHelper.floor_double(entity.posX),
MathHelper.floor_double(entity.boundingBox.minY), MathHelper.floor_double(entity.posZ));
boolean tempSpawning = targetPlayer.preventEntitySpawning;
targetPlayer.preventEntitySpawning = false;
boolean canSpawn = false;
int successes = 0;
int numTrials = 0;
for (int i = 0; i < SIMULATION_TRIALS; i++) {
if (livingType.canSpawnAtLocation(entity.worldObj, tags, (int) entity.posX, (int) entity.posY,
(int) entity.posZ)) {
canSpawn = true;
successes++;
}
numTrials++;
}
targetPlayer.preventEntitySpawning = tempSpawning;
if (canSpawn) {
StringBuilder builder = new StringBuilder();
builder.append("\u00A7a").append(livingType.typeID).append(" can spawn");
if (successes != numTrials) {
builder.append(" [").append(MathHelper.ceiling_float_int(successes / (float) numTrials)).append("%]");
} else {
builder.append(".");
}
builder.append("\u00A7r");
return builder.toString();
} else {
return "\u00A7c".concat(livingType.typeID).concat(" cannot spawn.").concat("\u00A7r");
}
}
private String canLivingHandlerSpawnHere(EntityPlayer targetPlayer, EntityLiving entity, LivingHandler livingHandler, CountInfo countInfo) {
boolean tempSpawning = targetPlayer.preventEntitySpawning;
targetPlayer.preventEntitySpawning = false;
boolean canSpawn = false;
int successes = 0;
int numTrials = 0;
for (int i = 0; i < SIMULATION_TRIALS; i++) {
if (livingHandler.isValidLiving(entity, countInfo)) {
canSpawn = true;
successes++;
}
numTrials++;
}
targetPlayer.preventEntitySpawning = tempSpawning;
if (canSpawn) {
StringBuilder builder = new StringBuilder();
builder.append("\u00A7a").append("Livinghandler can spawn");
if (successes != numTrials) {
builder.append(" [").append(MathHelper.ceiling_float_int(successes / (float) numTrials)).append("%]");
} else {
builder.append(".");
}
builder.append("\u00A7r");
return builder.toString();
} else {
return "\u00A7c".concat("Livinghandler cannot spawn.").concat("\u00A7r");
}
}
private String canSpawnListSpawnHere(EntityPlayer targetPlayer, EntityLiving entity, LivingHandler livingHandler,
SpawnListEntry spawnListEntry, String locationName, boolean isBiome, CountInfo countInfo) {
if (spawnListEntry == null) {
return "\u00A7c".concat("Entity not in B:").concat(locationName).concat(" spawnlist").concat("\u00A7r");
}
if (!spawnListEntry.getOptionalSpawning().isPresent()) {
return "\u00A7a".concat("No ").concat(isBiome ? "B:" : "S:").concat(locationName).concat(" tags.")
.concat("\u00A7r");
}
boolean tempSpawning = targetPlayer.preventEntitySpawning;
targetPlayer.preventEntitySpawning = false;
boolean canSpawn = false;
int successes = 0;
int numTrials = 0;
for (int i = 0; i < SIMULATION_TRIALS; i++) {
if (livingHandler.isValidSpawnList(entity, spawnListEntry, countInfo)) {
canSpawn = true;
successes++;
}
numTrials++;
}
targetPlayer.preventEntitySpawning = tempSpawning;
if (canSpawn) {
StringBuilder builder = new StringBuilder();
builder.append("\u00A7a").append("Can spawn in ").append(isBiome ? "B:" : "S:").append(locationName);
if (successes != numTrials) {
builder.append(" [").append(MathHelper.ceiling_float_int(successes / (float) numTrials)).append("%]");
} else {
builder.append(".");
}
builder.append("\u00A7r");
return builder.toString();
} else {
return "\u00A7c".concat("Cannot spawn in ").concat(isBiome ? "B:" : "S:").concat(locationName).concat(".")
.concat("\u00A7r");
}
}
/**
* Adds the strings available in this command to the given list of tab completion options.
*/
@Override
public List<String> getTabCompletions(ICommandSender commandSender, String[] stringArgs) {
stringArgs = correctedParseArgs(stringArgs, false);
List<String> tabCompletions = new ArrayList<String>();
if (stringArgs.length == 1) {
addPlayerUsernames(tabCompletions);
addEntityNames(tabCompletions);
} else if (stringArgs.length == 2) {
addEntityNames(tabCompletions);
}
if (!tabCompletions.isEmpty()) {
return getStringsMatchingLastWord(stringArgs, tabCompletions);
} else {
return tabCompletions;
}
}
}