Доброго времени суток.
Так как ни одного нормального русского тутора по добавлению своего GUI прямо в игру, хочу показать как сделать что-то простенькое, что-то вроде
этого.
Моддить мы будем на чистом minecraft, без forge или ModLoader. В нашем случае во всех случаях (Чистый Minecraft, с Forge или ModLoader) все получится почти одинаково.
Я не буду долго и нудно рассказывать как начать моддить: все это есть, наверное, у нас на форуме, ну а в крайнем случае вы сможете найти туториалы в интернете, но все же...
Нам понадобятся:
MCP (выбираем нужную нам версию)
Клиент и сервер Minecraft (я даю ссылку на 1.5.1, там мы и моддим)
Так же нам понадобится JDK.
И желательно NetBeans, или Eclipse (мой выбор упал на второе).
Создадим, допустим, папку MCP, и закинем туда все файлы нашего mcp. Зайдем в эту папку, и в папку jars закинем minecraft_server.jar и папки bin и resource нашей версии minecraft.
Жмем decompile.bat, ждем. Далее (как на эклипсе) открываем эклипс, Указываем папку eclipse в папке нашего MCP, запускаем.
Если у вас получилось что-то вроде
этого (левый столбец), то вы все сделали правильно. Продолжаем.
Открываем папку Client, после src. Находим пакет net.minecraft.src, открываем файл GuiIngame.java. Давайте воспользуемся поиском по нему (Ctrl + F). Вобьем в него
if (this.mc.gameSettings.showDebugInfo), нажмем поиск (Find). Увидим
код.
Разберем основное.
if (this.mc.gameSettings.showDebugInfo)
{
this.mc.mcProfiler.startSection("debug");
GL11.glPushMatrix();
var8.drawStringWithShadow("Minecraft 1.5.1 (" + this.mc.debug + ")", 2, 2, 16777215);
var8.drawStringWithShadow(this.mc.debugInfoRenders(), 2, 12, 16777215);
var8.drawStringWithShadow(this.mc.getEntityDebug(), 2, 22, 16777215);
var8.drawStringWithShadow(this.mc.debugInfoEntities(), 2, 32, 16777215);
var8.drawStringWithShadow(this.mc.getWorldProviderName(), 2, 42, 16777215);
long var36 = Runtime.getRuntime().maxMemory();
long var40 = Runtime.getRuntime().totalMemory();
long var43 = Runtime.getRuntime().freeMemory();
long var44 = var40 - var43;
String var46 = "Used memory: " + var44 * 100L / var36 + "% (" + var44 / 1024L / 1024L + "MB) of " + var36 / 1024L / 1024L + "MB";
this.drawString(var8, var46, var6 - var8.getStringWidth(var46) - 2, 2, 14737632);
var46 = "Allocated memory: " + var40 * 100L / var36 + "% (" + var40 / 1024L / 1024L + "MB)";
this.drawString(var8, var46, var6 - var8.getStringWidth(var46) - 2, 12, 14737632);
var47 = MathHelper.floor_double(this.mc.thePlayer.posX);
var22 = MathHelper.floor_double(this.mc.thePlayer.posY);
var23 = MathHelper.floor_double(this.mc.thePlayer.posZ);
this.drawString(var8, String.format("x: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posX), Integer.valueOf(var47), Integer.valueOf(var47 ›› 4), Integer.valueOf(var47 & 15)}), 2, 64, 14737632);
this.drawString(var8, String.format("y: %.3f (feet pos, %.3f eyes pos)", new Object[] {Double.valueOf(this.mc.thePlayer.boundingBox.minY), Double.valueOf(this.mc.thePlayer.posY)}), 2, 72, 14737632);
this.drawString(var8, String.format("z: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posZ), Integer.valueOf(var23), Integer.valueOf(var23 ›› 4), Integer.valueOf(var23 & 15)}), 2, 80, 14737632);
var24 = MathHelper.floor_double((double)(this.mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
this.drawString(var8, "f: " + var24 + " (" + Direction.directions[var24] + ") / " + MathHelper.wrapAngleTo180_float(this.mc.thePlayer.rotationYaw), 2, 88, 14737632);
if (this.mc.theWorld != null && this.mc.theWorld.blockExists(var47, var22, var23))
{
Chunk var52 = this.mc.theWorld.getChunkFromBlockCoords(var47, var23);
this.drawString(var8, "lc: " + (var52.getTopFilledSegment() + 15) + " b: " + var52.getBiomeGenForWorldCoords(var47 & 15, var23 & 15, this.mc.theWorld.getWorldChunkManager()).biomeName + " bl: " + var52.getSavedLightValue(EnumSkyBlock.Block, var47 & 15, var22, var23 & 15) + " sl: " + var52.getSavedLightValue(EnumSkyBlock.Sky, var47 & 15, var22, var23 & 15) + " rl: " + var52.getBlockLightValue(var47 & 15, var22, var23 & 15, 0), 2, 96, 14737632);
}
this.drawString(var8, String.format("ws: %.3f, fs: %.3f, g: %b, fl: %d", new Object[] {Float.valueOf(this.mc.thePlayer.capabilities.getWalkSpeed()), Float.valueOf(this.mc.thePlayer.capabilities.getFlySpeed()), Boolean.valueOf(this.mc.thePlayer.onGround), Integer.valueOf(this.mc.theWorld.getHeightValue(var47, var23))}), 2, 104, 14737632);
GL11.glPopMatrix();
this.mc.mcProfiler.endSection();
}
var8.drawStringWithShadow("Minecraft 1.5.1 (" + this.mc.debug + ")", 2, 2, 16777215);
//Добавляем надпись Minecraft 1.5.1 (65 fps, 99 chunk updates) - как пример
var47 = MathHelper.floor_double(this.mc.thePlayer.posX);
var22 = MathHelper.floor_double(this.mc.thePlayer.posY);
var23 = MathHelper.floor_double(this.mc.thePlayer.posZ);
this.drawString(var8, String.format("x: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posX), Integer.valueOf(var47), Integer.valueOf(var47 ›› 4), Integer.valueOf(var47 & 15)}), 2, 64, 14737632);
this.drawString(var8, String.format("y: %.3f (feet pos, %.3f eyes pos)", new Object[] {Double.valueOf(this.mc.thePlayer.boundingBox.minY), Double.valueOf(this.mc.thePlayer.posY)}), 2, 72, 14737632);
this.drawString(var8, String.format("z: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posZ), Integer.valueOf(var23), Integer.valueOf(var23 ›› 4), Integer.valueOf(var23 & 15)}), 2, 80, 14737632);
//Выводим координаты
Так как же создать то, что было вначале туториала? А очень просто. Изменяем нашу
конструкцию на
такую, чтобы в итоге получилось
так.
if (this.mc.gameSettings.showDebugInfo)
{
}
if (this.mc.gameSettings.showDebugInfo)
{
}
else
{
}
if (this.mc.gameSettings.showDebugInfo)
{
this.mc.mcProfiler.startSection("debug");
GL11.glPushMatrix();
var8.drawStringWithShadow("Minecraft 1.5.1 (" + this.mc.debug + ")", 2, 2, 16777215);
var8.drawStringWithShadow(this.mc.debugInfoRenders(), 2, 12, 16777215);
var8.drawStringWithShadow(this.mc.getEntityDebug(), 2, 22, 16777215);
var8.drawStringWithShadow(this.mc.debugInfoEntities(), 2, 32, 16777215);
var8.drawStringWithShadow(this.mc.getWorldProviderName(), 2, 42, 16777215);
long var36 = Runtime.getRuntime().maxMemory();
long var40 = Runtime.getRuntime().totalMemory();
long var43 = Runtime.getRuntime().freeMemory();
long var44 = var40 - var43;
String var46 = "Used memory: " + var44 * 100L / var36 + "% (" + var44 / 1024L / 1024L + "MB) of " + var36 / 1024L / 1024L + "MB";
this.drawString(var8, var46, var6 - var8.getStringWidth(var46) - 2, 2, 14737632);
var46 = "Allocated memory: " + var40 * 100L / var36 + "% (" + var40 / 1024L / 1024L + "MB)";
this.drawString(var8, var46, var6 - var8.getStringWidth(var46) - 2, 12, 14737632);
var47 = MathHelper.floor_double(this.mc.thePlayer.posX);
var22 = MathHelper.floor_double(this.mc.thePlayer.posY);
var23 = MathHelper.floor_double(this.mc.thePlayer.posZ);
this.drawString(var8, String.format("x: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posX), Integer.valueOf(var47), Integer.valueOf(var47 ›› 4), Integer.valueOf(var47 & 15)}), 2, 64, 14737632);
this.drawString(var8, String.format("y: %.3f (feet pos, %.3f eyes pos)", new Object[] {Double.valueOf(this.mc.thePlayer.boundingBox.minY), Double.valueOf(this.mc.thePlayer.posY)}), 2, 72, 14737632);
this.drawString(var8, String.format("z: %.5f (%d) // c: %d (%d)", new Object[] {Double.valueOf(this.mc.thePlayer.posZ), Integer.valueOf(var23), Integer.valueOf(var23 ›› 4), Integer.valueOf(var23 & 15)}), 2, 80, 14737632);
var24 = MathHelper.floor_double((double)(this.mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
this.drawString(var8, "f: " + var24 + " (" + Direction.directions[var24] + ") / " + MathHelper.wrapAngleTo180_float(this.mc.thePlayer.rotationYaw), 2, 88, 14737632);
if (this.mc.theWorld != null && this.mc.theWorld.blockExists(var47, var22, var23))
{
Chunk var52 = this.mc.theWorld.getChunkFromBlockCoords(var47, var23);
this.drawString(var8, "lc: " + (var52.getTopFilledSegment() + 15) + " b: " + var52.getBiomeGenForWorldCoords(var47 & 15, var23 & 15, this.mc.theWorld.getWorldChunkManager()).biomeName + " bl: " + var52.getSavedLightValue(EnumSkyBlock.Block, var47 & 15, var22, var23 & 15) + " sl: " + var52.getSavedLightValue(EnumSkyBlock.Sky, var47 & 15, var22, var23 & 15) + " rl: " + var52.getBlockLightValue(var47 & 15, var22, var23 & 15, 0), 2, 96, 14737632);
}
this.drawString(var8, String.format("ws: %.3f, fs: %.3f, g: %b, fl: %d", new Object[] {Float.valueOf(this.mc.thePlayer.capabilities.getWalkSpeed()), Float.valueOf(this.mc.thePlayer.capabilities.getFlySpeed()), Boolean.valueOf(this.mc.thePlayer.onGround), Integer.valueOf(this.mc.theWorld.getHeightValue(var47, var23))}), 2, 104, 14737632);
GL11.glPopMatrix();
this.mc.mcProfiler.endSection();
}else{
}
Теперь изменим нашу последнюю конструкцию
так.
if (this.mc.gameSettings.showDebugInfo)
{
}
else
{
drawString(var8, (new StringBuilder()).append("X: ").append((int)mc.thePlayer.posX).toString(), 6, 51, 0xe0e0e0);
drawString(var8, (new StringBuilder()).append("Y: ").append((int)mc.thePlayer.posY).toString(), 6, 61, 0xe0e0e0);
drawString(var8, (new StringBuilder()).append("Z: ").append((int)mc.thePlayer.posZ).toString(), 6, 71, 0xe0e0e0);
}
Почему так? На мой взгляд такой вывод координат удобнее, чем тот, который был указан выше в нашем первоначальном коде.
Давайте
разберем часть кода.
drawString(var8, (new StringBuilder()).append("Y: ").append((int)mc.thePlayer.posY).toString(), 6, 61, 0xe0e0e0);
//var8 - наш fontrenderer
//.append("Y: ").append((int)mc.thePlayer.posY) - выводим наши координаты в текст на экран
//6, 61 - координаты, начиная от левого верхнего угла. 6 - слева, 61 - сверху.
//0xe0e0e0 - цвет. Как сделать свой - читать в конце тутора.
Теперь у нас получилось
это.
Теперь я предлагаю попробовать вывести обычный текст на экран. В этом так же ничего сложного нет. Добавляем в наш код
это. Там все мы уже разобрали в контейнере выше.
drawString(var8, (new StringBuilder()).append("Shadow Tutorial").toString(), 6, 2, 0xefd334);
Теперь давайте попробуем вывести на экран свой ник. Добавим
это в наш код, а так же разберем.
drawString(var8, mc.thePlayer.username, 6, 19, 0xe0e0e0);
//Часть уже разобрана
//mc.thePlayer.username
//mc - так зареган наш minecraft.java вначале файла
//username - что выводим из thePlayer. Там можно вывести многое. К примеру, ссылку на скин

Теперь пришло время картинки. Добавляем
это в наш код, а так же разбираем.
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
this.mc.renderEngine.bindTexture("/gui/topgui.png");
this.drawTexturedModalRect(this.width=0 / 2, this.height=-70 / 2, 0, 0, 100, 200);
GL11.glDisable(GL11.GL_BLEND);
//С помощью GL11 мы добавляем полупрозрачность. Если убрать его - полупрозрачные картинки работать не будут!
//topgui.png - имя нашей картинки в ...bin/minecraft.jar/gui.
//this.width=0 / 2, this.height=-70 / 2 - смещение (отрицательное число тоже можно)
//100, 200 - какая часть картинки видна (ширина, высота) (ВСЕ КАРТИНКИ ДОЛЖНЫ БЫТЬ 256х256, НЕ смотря на эту строчку)
Чтобы показать, что можно использовать координаты в минус, я взял картинку больше, чем нужно, и сместил ее вверх. Получилось то, что нужно. Сама
картинка.
И так, у нас получилось то, что мы и хотели.
Теперь: как сделать цвет?
Скажем так... Html color:
ff0000,
0000ff,
ffffffЦвета в наш код:
0xff0000,
0x0000ff,
0xffffff (не удивляйтесь, что оно может измениться)
Спасибо за просмотр. Будут вопросы - задавайте.
P.S. Простите за то, что вместо code использовал quote. Дело в том, что если использовать code, то страница порвется так, что будет совершенно неудобно закрывать контейнеры, да и вообще потеряетесь

P.S.S. Картинка вначале темы немного неверна. Там вместо fps выводится fps + chunks update (или как там). Изменить можно в minecraft.java.