mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 05:27:37 +00:00
Natural Spawns PR2 Improvements to GUI Functionality
This commit is contained in:
1 parent
27e9f98862
commit
5c42308ca3
9 files changed
+378
-33
No files matched your search
@@ -28,8 +28,10 @@ import noppes.npcs.scripted.event.CustomNPCsEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -37,6 +39,10 @@ public class NPCSpawning {
|
||||
private static Set<ChunkCoordIntPair> eligibleChunksForSpawning = Sets.newHashSet();
|
||||
private static final byte CHUNK_SPAWN_RADIUS = 7;
|
||||
private static final int SPAWN_ATTEMPTS_PER_CHUNK = 3;
|
||||
private static final String NATURAL_SPAWN_ID_TAG = "CNPCNaturalSpawnId";
|
||||
private static final String NATURAL_SPAWN_NAME_TAG = "CNPCNaturalSpawnName";
|
||||
private static final String NATURAL_SPAWN_TIME_TAG = "CNPCNaturalSpawnTime";
|
||||
private static final Map<Long, Long> SPAWN_COOLDOWNS = new HashMap<Long, Long>();
|
||||
|
||||
private static boolean animalSpawn;
|
||||
private static boolean monsterSpawn;
|
||||
@@ -67,6 +73,7 @@ public class NPCSpawning {
|
||||
if (npcCount >= cap) {
|
||||
return;
|
||||
}
|
||||
HashMap<Integer, Integer> spawnEntryCounts = getNaturalSpawnEntryCounts(world);
|
||||
ArrayList<ChunkCoordIntPair> tmp = new ArrayList(eligibleChunksForSpawning);
|
||||
Collections.shuffle(tmp);
|
||||
Iterator<ChunkCoordIntPair> iterator = tmp.iterator();
|
||||
@@ -95,10 +102,10 @@ public class NPCSpawning {
|
||||
|
||||
String name = world.getBiomeGenForCoords(x, z).biomeName;
|
||||
SpawnData data = SpawnController.Instance.getRandomSpawnData(name, world.provider.dimensionId);
|
||||
if (data == null || y < data.spawnHeightMin || y > data.spawnHeightMax || !canCreatureTypeSpawnAtLocation(data, world, x, y, z) || world.getClosestPlayer(x, y, z, 24.0D) != null)
|
||||
if (data == null)
|
||||
continue;
|
||||
|
||||
if (spawnData(data, world, x, y, z)) {
|
||||
if (trySpawnWithEntryConfig(data, world, x, y, z, world.rand, spawnEntryCounts)) {
|
||||
npcCount++;
|
||||
}
|
||||
}
|
||||
@@ -141,12 +148,108 @@ public class NPCSpawning {
|
||||
return chunkSet.size();
|
||||
}
|
||||
|
||||
private static HashMap<Integer, Integer> getNaturalSpawnEntryCounts(World world) {
|
||||
HashMap<Integer, Integer> counts = new HashMap<Integer, Integer>();
|
||||
List<Entity> list = world.loadedEntityList;
|
||||
for (Entity entity : list) {
|
||||
if (entity == null || entity.isDead) {
|
||||
continue;
|
||||
}
|
||||
NBTTagCompound entityData = entity.getEntityData();
|
||||
if (!entityData.hasKey(NATURAL_SPAWN_ID_TAG)) {
|
||||
continue;
|
||||
}
|
||||
int spawnId = entityData.getInteger(NATURAL_SPAWN_ID_TAG);
|
||||
Integer count = counts.get(spawnId);
|
||||
counts.put(spawnId, count == null ? 1 : count + 1);
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
private static long getSpawnCooldownKey(World world, int spawnId) {
|
||||
return ((long) world.provider.dimensionId << 32) ^ (spawnId & 0xffffffffL);
|
||||
}
|
||||
|
||||
private static boolean isSpawnOnCooldown(World world, SpawnData data) {
|
||||
if (data.cooldownTicks <= 0 || data.id < 0) {
|
||||
return false;
|
||||
}
|
||||
long key = getSpawnCooldownKey(world, data.id);
|
||||
Long lastSpawnTick = SPAWN_COOLDOWNS.get(key);
|
||||
if (lastSpawnTick == null) {
|
||||
return false;
|
||||
}
|
||||
long tickDelta = world.getWorldInfo().getWorldTotalTime() - lastSpawnTick;
|
||||
return tickDelta < data.cooldownTicks;
|
||||
}
|
||||
|
||||
private static void markSpawnCooldown(World world, SpawnData data) {
|
||||
if (data.cooldownTicks <= 0 || data.id < 0) {
|
||||
return;
|
||||
}
|
||||
long key = getSpawnCooldownKey(world, data.id);
|
||||
SPAWN_COOLDOWNS.put(key, world.getWorldInfo().getWorldTotalTime());
|
||||
}
|
||||
|
||||
private static boolean isSpawnEntryAtCapacity(SpawnData data, Map<Integer, Integer> spawnEntryCounts) {
|
||||
if (data.maxAlive <= 0 || data.id < 0) {
|
||||
return false;
|
||||
}
|
||||
Integer currentCount = spawnEntryCounts.get(data.id);
|
||||
return currentCount != null && currentCount >= data.maxAlive;
|
||||
}
|
||||
|
||||
private static void incrementSpawnEntryCount(SpawnData data, Map<Integer, Integer> spawnEntryCounts) {
|
||||
if (data.id < 0) {
|
||||
return;
|
||||
}
|
||||
Integer currentCount = spawnEntryCounts.get(data.id);
|
||||
spawnEntryCounts.put(data.id, currentCount == null ? 1 : currentCount + 1);
|
||||
}
|
||||
|
||||
private static boolean hasNearbyPlayer(SpawnData data, World world, int x, int y, int z) {
|
||||
if (data.playerMinDistance <= 0) {
|
||||
return false;
|
||||
}
|
||||
return world.getClosestPlayer(x, y, z, data.playerMinDistance) != null;
|
||||
}
|
||||
|
||||
private static boolean trySpawnWithEntryConfig(SpawnData data, World world, int x, int y, int z, Random rand, Map<Integer, Integer> spawnEntryCounts) {
|
||||
if (y < data.spawnHeightMin || y > data.spawnHeightMax) {
|
||||
return false;
|
||||
}
|
||||
if (isSpawnEntryAtCapacity(data, spawnEntryCounts) || isSpawnOnCooldown(world, data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int attempts = Math.max(1, data.attemptsPerCycle);
|
||||
for (int attempt = 0; attempt < attempts; attempt++) {
|
||||
int attemptX = x;
|
||||
int attemptZ = z;
|
||||
if (attempt > 0) {
|
||||
attemptX += rand.nextInt(5) - rand.nextInt(5);
|
||||
attemptZ += rand.nextInt(5) - rand.nextInt(5);
|
||||
}
|
||||
|
||||
if (!canCreatureTypeSpawnAtLocation(data, world, attemptX, y, attemptZ) || hasNearbyPlayer(data, world, attemptX, y, attemptZ)) {
|
||||
continue;
|
||||
}
|
||||
if (spawnData(data, world, attemptX, y, attemptZ)) {
|
||||
incrementSpawnEntryCount(data, spawnEntryCounts);
|
||||
markSpawnCooldown(world, data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void performWorldGenSpawning(World world, int x, int z, Random rand) {
|
||||
int cap = getCap(world);
|
||||
int npcCount = countNPCs(world);
|
||||
if (npcCount >= cap) {
|
||||
return;
|
||||
}
|
||||
HashMap<Integer, Integer> spawnEntryCounts = getNaturalSpawnEntryCounts(world);
|
||||
BiomeGenBase biome = world.getBiomeGenForCoords(x + 8, z + 8);
|
||||
while (rand.nextFloat() < biome.getSpawningChance()) {
|
||||
if (npcCount >= cap) {
|
||||
@@ -174,13 +277,13 @@ public class NPCSpawning {
|
||||
l2 = l2 + (int) ((data.spawnHeightMax - l2) * Math.random());
|
||||
}
|
||||
|
||||
if (!canCreatureTypeSpawnAtLocation(data, world, j1, l2, k1)) {
|
||||
if (!trySpawnWithEntryConfig(data, world, j1, l2, k1, rand, spawnEntryCounts)) {
|
||||
j1 += rand.nextInt(5) - rand.nextInt(5);
|
||||
|
||||
for (k1 += rand.nextInt(5) - rand.nextInt(5); j1 < x || j1 >= x + size || k1 < z || k1 >= z + size; k1 = i2 + rand.nextInt(5) - rand.nextInt(5)) {
|
||||
j1 = l1 + rand.nextInt(5) - rand.nextInt(5);
|
||||
}
|
||||
} else if (spawnData(data, world, j1, l2, k1)) {
|
||||
} else {
|
||||
npcCount++;
|
||||
break;
|
||||
}
|
||||
@@ -226,14 +329,22 @@ public class NPCSpawning {
|
||||
if (spawnEntity instanceof EntityCustomNpc) {
|
||||
EntityCustomNpc npc = (EntityCustomNpc) spawnEntity;
|
||||
npc.stats.spawnCycle = 3;
|
||||
npc.stats.canDespawn = true;
|
||||
npc.stats.playerSetCanDespawn = true;
|
||||
if (data.despawnMode == SpawnData.DESPAWN_FORCE_PERSISTENT) {
|
||||
npc.stats.canDespawn = false;
|
||||
npc.stats.playerSetCanDespawn = false;
|
||||
} else if (data.despawnMode == SpawnData.DESPAWN_FORCE_NATURAL) {
|
||||
npc.stats.canDespawn = true;
|
||||
npc.stats.playerSetCanDespawn = true;
|
||||
}
|
||||
npc.ais.returnToStart = false;
|
||||
npc.ais.startPos = new int[]{x, y, z};
|
||||
npc.updateAI = true;
|
||||
npc.updateClient = true;
|
||||
npc.getNavigator().clearPathEntity();
|
||||
}
|
||||
entityliving.getEntityData().setInteger(NATURAL_SPAWN_ID_TAG, data.id);
|
||||
entityliving.getEntityData().setString(NATURAL_SPAWN_NAME_TAG, data.name);
|
||||
entityliving.getEntityData().setLong(NATURAL_SPAWN_TIME_TAG, world.getWorldInfo().getWorldTotalTime());
|
||||
spawnEntity.setLocationAndAngles(x + 0.5, y, z + 0.5, world.rand.nextFloat() * 360.0F, 0.0F);
|
||||
} catch (Exception exception) {
|
||||
exception.printStackTrace();
|
||||
|
||||
@@ -5,6 +5,7 @@ import noppes.npcs.client.gui.util.GuiNpcButton;
|
||||
import noppes.npcs.client.gui.util.GuiNpcButtonYesNo;
|
||||
import noppes.npcs.client.gui.util.GuiNpcLabel;
|
||||
import noppes.npcs.client.gui.util.GuiNpcTextField;
|
||||
import noppes.npcs.client.gui.util.GuiScrollWindow;
|
||||
import noppes.npcs.client.gui.util.ITextfieldListener;
|
||||
import noppes.npcs.client.gui.util.SubGuiInterface;
|
||||
import noppes.npcs.controllers.data.SpawnData;
|
||||
@@ -22,30 +23,90 @@ public class SubGuiSpawningOptions extends SubGuiInterface implements ITextfield
|
||||
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
int y = guiTop - 15;
|
||||
int scrollX = guiLeft + 4;
|
||||
int scrollY = guiTop + 4;
|
||||
int scrollW = xSize - 8;
|
||||
int scrollH = ySize - 34;
|
||||
|
||||
addButton(new GuiNpcButtonYesNo(10, guiLeft + 120, y += 22, data.animalSpawning));
|
||||
addLabel(new GuiNpcLabel(10, "spawning.animalSpawning", guiLeft + 4, y + 5));
|
||||
GuiScrollWindow sw = new GuiScrollWindow(this, scrollX, scrollY, scrollW, scrollH, 0);
|
||||
sw.drawDefaultBackground = false;
|
||||
addScrollableGui(0, sw);
|
||||
|
||||
addButton(new GuiNpcButtonYesNo(11, guiLeft + 120, y += 22, data.monsterSpawning));
|
||||
addLabel(new GuiNpcLabel(11, "spawning.monsterSpawning", guiLeft + 4, y + 5));
|
||||
int labelX = 4;
|
||||
int controlX = 132;
|
||||
int y = 6;
|
||||
|
||||
addButton(new GuiNpcButtonYesNo(12, guiLeft + 120, y += 22, data.liquidSpawning));
|
||||
addLabel(new GuiNpcLabel(12, "spawning.liquidSpawning", guiLeft + 4, y + 5));
|
||||
sw.addButton(new GuiNpcButtonYesNo(10, controlX, y, data.animalSpawning));
|
||||
sw.addLabel(new GuiNpcLabel(10, "spawning.animalSpawning", labelX, y + 5));
|
||||
sw.getButton(10).setHoverText("tooltip.naturalspawns.options.animal");
|
||||
y += 22;
|
||||
|
||||
addButton(new GuiNpcButtonYesNo(13, guiLeft + 120, y += 22, data.airSpawning));
|
||||
addLabel(new GuiNpcLabel(13, "spawning.airSpawning", guiLeft + 4, y + 5));
|
||||
sw.addButton(new GuiNpcButtonYesNo(11, controlX, y, data.monsterSpawning));
|
||||
sw.addLabel(new GuiNpcLabel(11, "spawning.monsterSpawning", labelX, y + 5));
|
||||
sw.getButton(11).setHoverText("tooltip.naturalspawns.options.monster");
|
||||
y += 22;
|
||||
|
||||
addTextField(new GuiNpcTextField(14, this, guiLeft + 120, y += 22, 40, 20, "" + data.spawnHeightMin));
|
||||
addLabel(new GuiNpcLabel(14, "spawning.minHeight", guiLeft + 4, y + 5));
|
||||
addTextField(new GuiNpcTextField(15, this, guiLeft + 120, y += 22, 40, 20, "" + data.spawnHeightMax));
|
||||
addLabel(new GuiNpcLabel(15, "spawning.maxHeight", guiLeft + 4, y + 5));
|
||||
getTextField(14).integersOnly = true;
|
||||
getTextField(14).setMinMaxDefault(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
|
||||
getTextField(15).integersOnly = true;
|
||||
getTextField(15).setMinMaxDefault(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
|
||||
sw.addButton(new GuiNpcButtonYesNo(12, controlX, y, data.liquidSpawning));
|
||||
sw.addLabel(new GuiNpcLabel(12, "spawning.liquidSpawning", labelX, y + 5));
|
||||
sw.getButton(12).setHoverText("tooltip.naturalspawns.options.liquid");
|
||||
y += 22;
|
||||
|
||||
addButton(new GuiNpcButton(100, guiLeft + 154, guiTop + 192, 60, 20, "gui.done"));
|
||||
sw.addButton(new GuiNpcButtonYesNo(13, controlX, y, data.airSpawning));
|
||||
sw.addLabel(new GuiNpcLabel(13, "spawning.airSpawning", labelX, y + 5));
|
||||
sw.getButton(13).setHoverText("tooltip.naturalspawns.options.air");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(14, this, controlX, y, 60, 20, "" + data.spawnHeightMin));
|
||||
sw.addLabel(new GuiNpcLabel(14, "spawning.minHeight", labelX, y + 5));
|
||||
sw.getTextField(14).integersOnly = true;
|
||||
sw.getTextField(14).setMinMaxDefault(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
|
||||
sw.getTextField(14).setHoverText("tooltip.naturalspawns.options.minHeight");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(15, this, controlX, y, 60, 20, "" + data.spawnHeightMax));
|
||||
sw.addLabel(new GuiNpcLabel(15, "spawning.maxHeight", labelX, y + 5));
|
||||
sw.getTextField(15).integersOnly = true;
|
||||
sw.getTextField(15).setMinMaxDefault(-Integer.MAX_VALUE, Integer.MAX_VALUE, 0);
|
||||
sw.getTextField(15).setHoverText("tooltip.naturalspawns.options.maxHeight");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(16, this, controlX, y, 60, 20, "" + data.maxAlive));
|
||||
sw.addLabel(new GuiNpcLabel(16, "spawning.maxAlive", labelX, y + 5));
|
||||
sw.getTextField(16).integersOnly = true;
|
||||
sw.getTextField(16).setMinMaxDefault(0, Integer.MAX_VALUE, 0);
|
||||
sw.getTextField(16).setHoverText("tooltip.naturalspawns.options.maxAlive");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(17, this, controlX, y, 60, 20, "" + data.cooldownTicks));
|
||||
sw.addLabel(new GuiNpcLabel(17, "spawning.cooldownTicks", labelX, y + 5));
|
||||
sw.getTextField(17).integersOnly = true;
|
||||
sw.getTextField(17).setMinMaxDefault(0, Integer.MAX_VALUE, 0);
|
||||
sw.getTextField(17).setHoverText("tooltip.naturalspawns.options.cooldownTicks");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(18, this, controlX, y, 60, 20, "" + data.attemptsPerCycle));
|
||||
sw.addLabel(new GuiNpcLabel(18, "spawning.attemptsPerCycle", labelX, y + 5));
|
||||
sw.getTextField(18).integersOnly = true;
|
||||
sw.getTextField(18).setMinMaxDefault(1, Integer.MAX_VALUE, 1);
|
||||
sw.getTextField(18).setHoverText("tooltip.naturalspawns.options.attemptsPerCycle");
|
||||
y += 22;
|
||||
|
||||
sw.addTextField(new GuiNpcTextField(19, this, controlX, y, 60, 20, "" + data.playerMinDistance));
|
||||
sw.addLabel(new GuiNpcLabel(19, "spawning.playerMinDistance", labelX, y + 5));
|
||||
sw.getTextField(19).integersOnly = true;
|
||||
sw.getTextField(19).setMinMaxDefault(0, Integer.MAX_VALUE, 24);
|
||||
sw.getTextField(19).setHoverText("tooltip.naturalspawns.options.playerMinDistance");
|
||||
y += 22;
|
||||
|
||||
sw.addButton(new GuiNpcButton(20, controlX, y, 74, 20,
|
||||
new String[]{"spawning.despawn.forceNatural", "spawning.despawn.preserve", "spawning.despawn.forcePersistent"}, data.despawnMode));
|
||||
sw.addLabel(new GuiNpcLabel(20, "spawning.despawnMode", labelX, y + 5));
|
||||
sw.getButton(20).setHoverText("tooltip.naturalspawns.options.despawnMode");
|
||||
y += 22;
|
||||
|
||||
sw.maxScrollY = Math.max(0, y - sw.clipHeight + 8);
|
||||
|
||||
addButton(new GuiNpcButton(100, guiLeft + xSize - 64, guiTop + ySize - 24, 60, 20, "gui.done"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,6 +125,9 @@ public class SubGuiSpawningOptions extends SubGuiInterface implements ITextfield
|
||||
if (button.id == 13) {
|
||||
data.airSpawning = button.getValue() == 1;
|
||||
}
|
||||
if (button.id == 20) {
|
||||
data.setDespawnMode(button.getValue());
|
||||
}
|
||||
if (button.id == 100) {
|
||||
close();
|
||||
}
|
||||
@@ -77,5 +141,17 @@ public class SubGuiSpawningOptions extends SubGuiInterface implements ITextfield
|
||||
if (textfield.id == 15) {
|
||||
data.spawnHeightMax = textfield.getInteger();
|
||||
}
|
||||
if (textfield.id == 16) {
|
||||
data.setMaxAlive(textfield.getInteger());
|
||||
}
|
||||
if (textfield.id == 17) {
|
||||
data.setCooldownTicks(textfield.getInteger());
|
||||
}
|
||||
if (textfield.id == 18) {
|
||||
data.setAttemptsPerCycle(textfield.getInteger());
|
||||
}
|
||||
if (textfield.id == 19) {
|
||||
data.setPlayerMinDistance(textfield.getInteger());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,12 @@ public class GuiNpcNaturalSpawns extends GuiNPCInterface2 implements IGuiData, I
|
||||
|
||||
this.addButton(new GuiNpcButton(1, guiLeft + 358, guiTop + 38, 58, 20, "gui.add"));
|
||||
this.addButton(new GuiNpcButton(2, guiLeft + 358, guiTop + 61, 58, 20, "gui.remove"));
|
||||
getButton(1).setHoverText("tooltip.naturalspawns.main.addProfile");
|
||||
getButton(2).setHoverText("tooltip.naturalspawns.main.removeProfile");
|
||||
|
||||
if (getTextField(55) != null) {
|
||||
getTextField(55).setHoverText("tooltip.naturalspawns.main.search");
|
||||
}
|
||||
|
||||
if (this.spawn.id >= 0)
|
||||
showSpawn();
|
||||
@@ -74,15 +80,18 @@ public class GuiNpcNaturalSpawns extends GuiNPCInterface2 implements IGuiData, I
|
||||
int y = guiTop + 30;
|
||||
addLabel(new GuiNpcLabel(3, "spawning.biomes", guiLeft + 4, y));
|
||||
addButton(new GuiNpcButton(3, guiLeft + 40, y - 5, 50, 20, "selectServer.edit"));
|
||||
getButton(3).setHoverText("tooltip.naturalspawns.main.biomes");
|
||||
|
||||
addLabel(new GuiNpcLabel(11, StatCollector.translateToLocal("Dimensions"), guiLeft + 95, y));
|
||||
addButton(new GuiNpcButton(11, guiLeft + 150, y - 5, 50, 20, "selectServer.edit"));
|
||||
getButton(11).setHoverText("tooltip.naturalspawns.main.dimensions");
|
||||
|
||||
addLabel(new GuiNpcLabel(4, "spawning.options", guiLeft + 4, y += 22));
|
||||
addButton(new GuiNpcButton(4, guiLeft + 90, y - 5, 50, 20, "selectServer.edit"));
|
||||
getButton(4).setHoverText("tooltip.naturalspawns.main.options");
|
||||
|
||||
addSlider(new GuiNpcSlider(this, 5, guiLeft + 4, y += 17, 180, 20, (float) this.spawn.itemWeight / 100));
|
||||
addExtra(new GuiHoverText(1, "spawning.naturalInfo", guiLeft + 188, y + 5));
|
||||
addExtra(new GuiHoverText(1, "spawning.naturalInfoPerformance", guiLeft + 188, y + 5));
|
||||
|
||||
this.spawnEntryScroll.guiLeft = guiLeft + 4;
|
||||
this.spawnEntryScroll.guiTop = y + 40;
|
||||
@@ -96,13 +105,17 @@ public class GuiNpcNaturalSpawns extends GuiNPCInterface2 implements IGuiData, I
|
||||
addScroll(this.spawnEntryScroll);
|
||||
|
||||
addButton(new GuiNpcButton(21, guiLeft + 6, y += 20, 20, 20, "+"));
|
||||
getButton(21).setHoverText("tooltip.naturalspawns.main.addEntry");
|
||||
if (this.spawnEntryScroll.hasSelected()) {
|
||||
int selected = Integer.parseInt(this.spawnEntryScroll.getSelected());
|
||||
addButton(new GuiNpcButton(22, guiLeft + 32, y, 20, 20, "-"));
|
||||
getButton(22).setHoverText("tooltip.naturalspawns.main.removeEntry");
|
||||
GuiNpcTextField num = new GuiNpcTextField(25, this, guiLeft + 60, y += 10, 30, 20, "" + selected);
|
||||
num.integersOnly = true;
|
||||
addTextField(num);
|
||||
getTextField(25).setHoverText("tooltip.naturalspawns.main.slot");
|
||||
addButton(new GuiNpcButton(26, guiLeft + 92, y, 100, 20, this.getTitle(this.spawn.spawnCompounds.get(selected))));
|
||||
getButton(26).setHoverText("tooltip.naturalspawns.main.selectEntry");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,8 @@ public class GuiNpcButton extends GuiButton {
|
||||
}
|
||||
|
||||
public void setHoverText(String text) {
|
||||
this.hoverableText = StatCollector.translateToLocal(text);
|
||||
String translated = StatCollector.translateToLocal(text);
|
||||
this.hoverableText = translated == null ? "" : translated.replace("\\n", "\n");
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
@@ -201,13 +202,30 @@ public class GuiNpcButton extends GuiButton {
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
String displayString = StatCollector.translateToLocal(hoverableText);
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
List<String> lines = TextSplitter.splitText(displayString, 30);
|
||||
List<String> lines = splitHoverText(displayString, 30);
|
||||
drawHoveringText(lines, i, j, mc);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitHoverText(String text, int maxLineLength) {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
if (text == null || text.isEmpty())
|
||||
return lines;
|
||||
|
||||
String normalized = text.replace("\\n", "\n");
|
||||
String[] explicitLines = normalized.split("\\r?\\n", -1);
|
||||
for (String line : explicitLines) {
|
||||
if (line.isEmpty()) {
|
||||
lines.add("");
|
||||
continue;
|
||||
}
|
||||
lines.addAll(TextSplitter.splitText(line, maxLineLength));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
protected void drawHoveringText(List textLines, int x, int y, Minecraft mc) {
|
||||
if (mc.fontRenderer == null || textLines.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -12,6 +12,7 @@ import net.minecraft.util.StatCollector;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GuiNpcTextField extends GuiTextField {
|
||||
@@ -304,7 +305,8 @@ public class GuiNpcTextField extends GuiTextField {
|
||||
}
|
||||
|
||||
public void setHoverText(String text) {
|
||||
this.hoverableText = StatCollector.translateToLocal(text);
|
||||
String translated = StatCollector.translateToLocal(text);
|
||||
this.hoverableText = translated == null ? "" : translated.replace("\\n", "\n");
|
||||
}
|
||||
|
||||
public boolean hasHoverText() {
|
||||
@@ -317,10 +319,14 @@ public class GuiNpcTextField extends GuiTextField {
|
||||
}
|
||||
|
||||
public void drawHover(int mouseX, int mouseY, boolean hasSubGui) {
|
||||
drawHover(mouseX, mouseY, mouseX, mouseY, hasSubGui);
|
||||
}
|
||||
|
||||
public void drawHover(int hitMouseX, int hitMouseY, int tooltipMouseX, int tooltipMouseY, boolean hasSubGui) {
|
||||
if (hasSubGui || !enabled || hoverableText.isEmpty())
|
||||
return;
|
||||
|
||||
boolean isHovered = isMouseOver(mouseX, mouseY);
|
||||
boolean isHovered = isMouseOver(hitMouseX, hitMouseY);
|
||||
if (!isHovered) {
|
||||
wasHovered = false;
|
||||
hoverCount = 0;
|
||||
@@ -338,13 +344,30 @@ public class GuiNpcTextField extends GuiTextField {
|
||||
GL11.glPushMatrix();
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
GL11.glColor4f(1, 1, 1, 1);
|
||||
List<String> lines = TextSplitter.splitText(hoverableText, 30);
|
||||
drawHoveringText(lines, mouseX, mouseY, mc);
|
||||
List<String> lines = splitHoverText(hoverableText, 30);
|
||||
drawHoveringText(lines, tooltipMouseX, tooltipMouseY, mc);
|
||||
GL11.glDisable(GL11.GL_LIGHTING);
|
||||
GL11.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> splitHoverText(String text, int maxLineLength) {
|
||||
List<String> lines = new ArrayList<String>();
|
||||
if (text == null || text.isEmpty())
|
||||
return lines;
|
||||
|
||||
String normalized = text.replace("\\n", "\n");
|
||||
String[] explicitLines = normalized.split("\\r?\\n", -1);
|
||||
for (String line : explicitLines) {
|
||||
if (line.isEmpty()) {
|
||||
lines.add("");
|
||||
continue;
|
||||
}
|
||||
lines.addAll(TextSplitter.splitText(line, maxLineLength));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
protected void drawHoveringText(List<String> textLines, int x, int y, Minecraft mc) {
|
||||
if (mc.fontRenderer == null || textLines.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -300,9 +300,14 @@ public class GuiScrollWindow extends GuiScreen implements ITextfieldListener, IC
|
||||
button.drawHover(mouseX, mouseY, subGui);
|
||||
}
|
||||
}
|
||||
// Label hover: convert screen mouse to scroll-local coords for hit testing
|
||||
int localMouseX = mouseX - xPos;
|
||||
int localMouseY = (int) (mouseY - yPos + scrollY);
|
||||
for (GuiNpcTextField textField : textfields.values()) {
|
||||
if (textField.hasHoverText()) {
|
||||
textField.drawHover(localMouseX, localMouseY, mouseX, mouseY, subGui);
|
||||
}
|
||||
}
|
||||
// Label hover: convert screen mouse to scroll-local coords for hit testing
|
||||
for (GuiNpcLabel label : labels.values()) {
|
||||
if (!label.hoverableText.isEmpty()) {
|
||||
label.drawHover(localMouseX, localMouseY, mouseX, mouseY, subGui, fontRendererObj);
|
||||
|
||||
@@ -21,6 +21,10 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SpawnData extends WeightedRandom.Item implements INaturalSpawn {
|
||||
public static final int DESPAWN_FORCE_NATURAL = INaturalSpawn.DESPAWN_FORCE_NATURAL;
|
||||
public static final int DESPAWN_PRESERVE_TEMPLATE = INaturalSpawn.DESPAWN_PRESERVE_TEMPLATE;
|
||||
public static final int DESPAWN_FORCE_PERSISTENT = INaturalSpawn.DESPAWN_FORCE_PERSISTENT;
|
||||
|
||||
public List<String> biomes = new ArrayList<>();
|
||||
public HashSet<Integer> dimensions = new HashSet<>();
|
||||
public int id = -1;
|
||||
@@ -35,6 +39,11 @@ public class SpawnData extends WeightedRandom.Item implements INaturalSpawn {
|
||||
|
||||
public int spawnHeightMin;
|
||||
public int spawnHeightMax = 100;
|
||||
public int maxAlive = 0;
|
||||
public int cooldownTicks = 0;
|
||||
public int attemptsPerCycle = 1;
|
||||
public int playerMinDistance = 24;
|
||||
public int despawnMode = DESPAWN_FORCE_NATURAL;
|
||||
|
||||
public SpawnData() {
|
||||
super(10);
|
||||
@@ -74,6 +83,19 @@ public class SpawnData extends WeightedRandom.Item implements INaturalSpawn {
|
||||
} else {
|
||||
spawnHeightMax = compound.getInteger("HeightMax");
|
||||
}
|
||||
|
||||
maxAlive = compound.hasKey("MaxAlive") ? Math.max(0, compound.getInteger("MaxAlive")) : 0;
|
||||
cooldownTicks = compound.hasKey("CooldownTicks") ? Math.max(0, compound.getInteger("CooldownTicks")) : 0;
|
||||
attemptsPerCycle = compound.hasKey("AttemptsPerCycle") ? Math.max(1, compound.getInteger("AttemptsPerCycle")) : 1;
|
||||
playerMinDistance = compound.hasKey("PlayerMinDistance") ? Math.max(0, compound.getInteger("PlayerMinDistance")) : 24;
|
||||
if (compound.hasKey("DespawnMode")) {
|
||||
despawnMode = compound.getInteger("DespawnMode");
|
||||
} else {
|
||||
despawnMode = DESPAWN_FORCE_NATURAL;
|
||||
}
|
||||
if (despawnMode < DESPAWN_FORCE_NATURAL || despawnMode > DESPAWN_FORCE_PERSISTENT) {
|
||||
despawnMode = DESPAWN_FORCE_NATURAL;
|
||||
}
|
||||
}
|
||||
|
||||
public NBTTagCompound writeNBT(NBTTagCompound compound) {
|
||||
@@ -98,6 +120,11 @@ public class SpawnData extends WeightedRandom.Item implements INaturalSpawn {
|
||||
|
||||
compound.setInteger("HeightMin", spawnHeightMin);
|
||||
compound.setInteger("HeightMax", spawnHeightMax);
|
||||
compound.setInteger("MaxAlive", maxAlive);
|
||||
compound.setInteger("CooldownTicks", cooldownTicks);
|
||||
compound.setInteger("AttemptsPerCycle", attemptsPerCycle);
|
||||
compound.setInteger("PlayerMinDistance", playerMinDistance);
|
||||
compound.setInteger("DespawnMode", despawnMode);
|
||||
return compound;
|
||||
}
|
||||
|
||||
@@ -204,4 +231,46 @@ public class SpawnData extends WeightedRandom.Item implements INaturalSpawn {
|
||||
public void setBiomes(String[] biomes) {
|
||||
this.biomes = new ArrayList<>(Arrays.asList(biomes));
|
||||
}
|
||||
|
||||
public void setMaxAlive(int maxAlive) {
|
||||
this.maxAlive = Math.max(0, maxAlive);
|
||||
}
|
||||
|
||||
public int getMaxAlive() {
|
||||
return this.maxAlive;
|
||||
}
|
||||
|
||||
public void setCooldownTicks(int ticks) {
|
||||
this.cooldownTicks = Math.max(0, ticks);
|
||||
}
|
||||
|
||||
public int getCooldownTicks() {
|
||||
return this.cooldownTicks;
|
||||
}
|
||||
|
||||
public void setAttemptsPerCycle(int attempts) {
|
||||
this.attemptsPerCycle = Math.max(1, attempts);
|
||||
}
|
||||
|
||||
public int getAttemptsPerCycle() {
|
||||
return this.attemptsPerCycle;
|
||||
}
|
||||
|
||||
public void setPlayerMinDistance(int distance) {
|
||||
this.playerMinDistance = Math.max(0, distance);
|
||||
}
|
||||
|
||||
public int getPlayerMinDistance() {
|
||||
return this.playerMinDistance;
|
||||
}
|
||||
|
||||
public void setDespawnMode(int mode) {
|
||||
if (mode < DESPAWN_FORCE_NATURAL || mode > DESPAWN_FORCE_PERSISTENT)
|
||||
mode = DESPAWN_FORCE_NATURAL;
|
||||
this.despawnMode = mode;
|
||||
}
|
||||
|
||||
public int getDespawnMode() {
|
||||
return this.despawnMode;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user