mirror of
https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1.git
synced 2026-03-19 22:43:32 +00:00
Added capes (needs improvement)
This commit is contained in:
@@ -107,64 +107,74 @@ static std::string extractJsonString(const std::string& json, const std::string&
|
|||||||
return json.substr(pos, end - pos);
|
return json.substr(pos, end - pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getSkinUrlForUsername(const std::string& username) {
|
static std::string getTextureUrlForUsername(const std::string& username, const std::string& textureKey) {
|
||||||
if (username.empty()) {
|
if (username.empty()) {
|
||||||
LOGI("[Skin] username empty\n");
|
LOGI("[%s] username empty\n", textureKey.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("[Skin] resolving UUID for user '%s'...\n", username.c_str());
|
LOGI("[%s] resolving UUID for user '%s'...\n", textureKey.c_str(), username.c_str());
|
||||||
std::vector<unsigned char> body;
|
std::vector<unsigned char> body;
|
||||||
std::string apiUrl = "http://api.mojang.com/users/profiles/minecraft/" + username;
|
std::string apiUrl = "http://api.mojang.com/users/profiles/minecraft/" + username;
|
||||||
if (!HttpClient::download(apiUrl, body)) {
|
if (!HttpClient::download(apiUrl, body)) {
|
||||||
LOGW("[Skin] failed to download UUID for %s\n", username.c_str());
|
LOGW("[%s] failed to download UUID for %s\n", textureKey.c_str(), username.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string response(body.begin(), body.end());
|
std::string response(body.begin(), body.end());
|
||||||
std::string uuid = extractJsonString(response, "id");
|
std::string uuid = extractJsonString(response, "id");
|
||||||
if (uuid.empty()) {
|
if (uuid.empty()) {
|
||||||
LOGW("[Skin] no UUID found in Mojang response for %s\n", username.c_str());
|
LOGW("[%s] no UUID found in Mojang response for %s\n", textureKey.c_str(), username.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("[Skin] UUID=%s for user %s\n", uuid.c_str(), username.c_str());
|
LOGI("[%s] UUID=%s for user %s\n", textureKey.c_str(), uuid.c_str(), username.c_str());
|
||||||
|
|
||||||
std::string profileUrl = "http://sessionserver.mojang.com/session/minecraft/profile/" + uuid;
|
std::string profileUrl = "http://sessionserver.mojang.com/session/minecraft/profile/" + uuid;
|
||||||
if (!HttpClient::download(profileUrl, body)) {
|
if (!HttpClient::download(profileUrl, body)) {
|
||||||
LOGW("[Skin] failed to download profile for UUID %s\n", uuid.c_str());
|
LOGW("[%s] failed to download profile for UUID %s\n", textureKey.c_str(), uuid.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
response.assign(body.begin(), body.end());
|
response.assign(body.begin(), body.end());
|
||||||
std::string encoded = extractJsonString(response, "value");
|
std::string encoded = extractJsonString(response, "value");
|
||||||
if (encoded.empty()) {
|
if (encoded.empty()) {
|
||||||
LOGW("[Skin] no value field in profile response for UUID %s\n", uuid.c_str());
|
LOGW("[%s] no value field in profile response for UUID %s\n", textureKey.c_str(), uuid.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string decoded = base64Decode(encoded);
|
std::string decoded = base64Decode(encoded);
|
||||||
size_t skinPos = decoded.find("\"SKIN\"");
|
|
||||||
if (skinPos == std::string::npos) {
|
std::string searchKey = "\"" + textureKey + "\"";
|
||||||
LOGW("[Skin] no SKIN entry in decoded profile for UUID %s\n", uuid.c_str());
|
size_t texturePos = decoded.find(searchKey);
|
||||||
|
if (texturePos == std::string::npos) {
|
||||||
|
LOGW("[%s] no %s entry in decoded profile for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
size_t urlPos = decoded.find("\"url\"", skinPos);
|
size_t urlPos = decoded.find("\"url\"", texturePos);
|
||||||
if (urlPos == std::string::npos) {
|
if (urlPos == std::string::npos) {
|
||||||
LOGW("[Skin] no url field under SKIN for UUID %s\n", uuid.c_str());
|
LOGW("[%s] no url field under %s for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the URL value from the substring starting at urlPos
|
// extract the URL value from the substring starting at urlPos
|
||||||
std::string urlFragment = decoded.substr(urlPos);
|
std::string urlFragment = decoded.substr(urlPos);
|
||||||
std::string skinUrl = extractJsonString(urlFragment, "url");
|
std::string textureUrl = extractJsonString(urlFragment, "url");
|
||||||
if (skinUrl.empty()) {
|
if (textureUrl.empty()) {
|
||||||
LOGW("[Skin] failed to parse skin URL for UUID %s\n", uuid.c_str());
|
LOGW("[%s] failed to parse %s URL for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str());
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGI("[Skin] skin URL for %s: %s\n", username.c_str(), skinUrl.c_str());
|
LOGI("[%s] %s URL for %s: %s\n", textureKey.c_str(), textureKey.c_str(), username.c_str(), textureUrl.c_str());
|
||||||
return skinUrl;
|
return textureUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getSkinUrlForUsername(const std::string& username) {
|
||||||
|
return getTextureUrlForUsername(username, "SKIN");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getCapeUrlForUsername(const std::string& username) {
|
||||||
|
return getTextureUrlForUsername(username, "CAPE");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ensureDirectoryExists(const std::string& path) {
|
static bool ensureDirectoryExists(const std::string& path) {
|
||||||
@@ -235,6 +245,51 @@ static void* fetchSkinForPlayer(void* param) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* fetchCapeForPlayer(void* param) {
|
||||||
|
LocalPlayer* player = (LocalPlayer*)param;
|
||||||
|
if (!player) return NULL;
|
||||||
|
|
||||||
|
LOGI("[Cape] starting cape download for %s\n", player->name.c_str());
|
||||||
|
|
||||||
|
const std::string cacheDir = "data/images/capes";
|
||||||
|
if (!ensureDirectoryExists(cacheDir)) {
|
||||||
|
LOGW("[Cape] failed to create cache directory %s\n", cacheDir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cacheFile = cacheDir + "/" + player->name + ".png";
|
||||||
|
if (fileExists(cacheFile)) {
|
||||||
|
LOGI("[Cape] using cached cape for %s\n", player->name.c_str());
|
||||||
|
player->setCapeTextureName("capes/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string capeUrl = getCapeUrlForUsername(player->name);
|
||||||
|
if (capeUrl.empty()) {
|
||||||
|
LOGW("[Cape] cape URL lookup failed for %s\n", player->name.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGI("[Cape] downloading cape from %s\n", capeUrl.c_str());
|
||||||
|
std::vector<unsigned char> capeData;
|
||||||
|
if (!HttpClient::download(capeUrl, capeData) || capeData.empty()) {
|
||||||
|
LOGW("[Cape] download failed for %s\n", capeUrl.c_str());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to cache
|
||||||
|
FILE* fp = fopen(cacheFile.c_str(), "wb");
|
||||||
|
if (fp) {
|
||||||
|
fwrite(capeData.data(), 1, capeData.size(), fp);
|
||||||
|
fclose(fp);
|
||||||
|
LOGI("[Cape] cached cape to %s\n", cacheFile.c_str());
|
||||||
|
} else {
|
||||||
|
LOGW("[Cape] failed to write cape cache %s\n", cacheFile.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
player->setCapeTextureName("capes/" + player->name + ".png");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
//@note: doesn't work completely, since it doesn't care about stairs rotation
|
//@note: doesn't work completely, since it doesn't care about stairs rotation
|
||||||
static bool isJumpable(int tileId) {
|
static bool isJumpable(int tileId) {
|
||||||
return tileId != Tile::fence->id
|
return tileId != Tile::fence->id
|
||||||
@@ -265,8 +320,9 @@ LocalPlayer::LocalPlayer(Minecraft* minecraft, Level* level, User* user, int dim
|
|||||||
|
|
||||||
if (user != NULL && !user->name.empty()) {
|
if (user != NULL && !user->name.empty()) {
|
||||||
this->name = user->name;
|
this->name = user->name;
|
||||||
// Fetch user skin from Mojang servers in the background (avoids blocking the main thread)
|
// Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread)
|
||||||
new CThread(fetchSkinForPlayer, this);
|
new CThread(fetchSkinForPlayer, this);
|
||||||
|
new CThread(fetchCapeForPlayer, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "EntityRenderDispatcher.h"
|
#include "EntityRenderDispatcher.h"
|
||||||
#include "../ItemInHandRenderer.h"
|
#include "../ItemInHandRenderer.h"
|
||||||
#include "../TileRenderer.h"
|
#include "../TileRenderer.h"
|
||||||
|
#include "../Tesselator.h"
|
||||||
#include "../../model/HumanoidModel.h"
|
#include "../../model/HumanoidModel.h"
|
||||||
#include "../../../world/level/tile/Tile.h"
|
#include "../../../world/level/tile/Tile.h"
|
||||||
#include "../../../world/entity/player/Player.h"
|
#include "../../../world/entity/player/Player.h"
|
||||||
@@ -12,7 +13,9 @@
|
|||||||
|
|
||||||
HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow)
|
HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow)
|
||||||
: super(humanoidModel, shadow),
|
: super(humanoidModel, shadow),
|
||||||
humanoidModel(humanoidModel)
|
humanoidModel(humanoidModel),
|
||||||
|
lastCapeXRot(0),
|
||||||
|
lastCapeZRot(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +71,143 @@ void HumanoidMobRenderer::additionalRendering(Mob* mob, float a) {
|
|||||||
entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item);
|
entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item);
|
||||||
glPopMatrix2();
|
glPopMatrix2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render player cape if available
|
||||||
|
{
|
||||||
|
Player* player = dynamic_cast<Player*>(mob);
|
||||||
|
if (player) {
|
||||||
|
const std::string capeTex = player->getCapeTexture();
|
||||||
|
if (!capeTex.empty()) {
|
||||||
|
|
||||||
|
bindTexture(capeTex);
|
||||||
|
|
||||||
|
glPushMatrix2();
|
||||||
|
|
||||||
|
// Attach to player body
|
||||||
|
humanoidModel->body.translateTo(1 / 16.0f);
|
||||||
|
|
||||||
|
// Convert model units (pixels) to world units
|
||||||
|
glScalef2(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f);
|
||||||
|
|
||||||
|
// Position cape slightly down and behind the shoulders
|
||||||
|
glTranslatef2(0.0f, 1.0f, 2.0f);
|
||||||
|
|
||||||
|
// Java-like cape physics (interpolated inertia + body motion)
|
||||||
|
float pt = a;
|
||||||
|
|
||||||
|
double capeX = player->getCapePrevX() + (player->getCapeX() - player->getCapePrevX()) * pt;
|
||||||
|
double capeY = player->getCapePrevY() + (player->getCapeY() - player->getCapePrevY()) * pt;
|
||||||
|
double capeZ = player->getCapePrevZ() + (player->getCapeZ() - player->getCapePrevZ()) * pt;
|
||||||
|
|
||||||
|
double px = player->xo + (player->x - player->xo) * pt;
|
||||||
|
double py = player->yo + (player->y - player->yo) * pt;
|
||||||
|
double pz = player->zo + (player->z - player->zo) * pt;
|
||||||
|
|
||||||
|
double dx = capeX - px;
|
||||||
|
double dy = capeY - py;
|
||||||
|
double dz = capeZ - pz;
|
||||||
|
|
||||||
|
float bodyYaw = player->yBodyRotO + (player->yBodyRot - player->yBodyRotO) * pt;
|
||||||
|
|
||||||
|
float rad = bodyYaw * Mth::PI / 180.0f;
|
||||||
|
double sinYaw = Mth::sin(rad);
|
||||||
|
double cosYaw = -Mth::cos(rad);
|
||||||
|
|
||||||
|
float forward = (float)(dx * sinYaw + dz * cosYaw) * 100.0f;
|
||||||
|
float sideways = (float)(dx * cosYaw - dz * sinYaw) * 100.0f;
|
||||||
|
if (forward < 0.0f) forward = 0.0f;
|
||||||
|
|
||||||
|
float lift = (float)dy * 10.0f;
|
||||||
|
if (lift < -6.0f) lift = -6.0f;
|
||||||
|
if (lift > 32.0f) lift = 32.0f;
|
||||||
|
|
||||||
|
float walk =
|
||||||
|
Mth::sin((player->walkAnimPos + player->walkAnimSpeed) * 6.0f) *
|
||||||
|
32.0f *
|
||||||
|
player->walkAnimSpeed;
|
||||||
|
|
||||||
|
float capeXRot = 6.0f + forward / 2.0f + lift + walk;
|
||||||
|
float capeZRot = sideways / 2.0f;
|
||||||
|
|
||||||
|
// Smooth out jitter by lerping from the previous frame
|
||||||
|
const float smooth = 0.3f;
|
||||||
|
capeXRot = lastCapeXRot + (capeXRot - lastCapeXRot) * smooth;
|
||||||
|
capeZRot = lastCapeZRot + (capeZRot - lastCapeZRot) * smooth;
|
||||||
|
|
||||||
|
lastCapeXRot = capeXRot;
|
||||||
|
lastCapeZRot = capeZRot;
|
||||||
|
|
||||||
|
glRotatef2(capeXRot, 1.0f, 0.0f, 0.0f);
|
||||||
|
glRotatef2(capeZRot, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
Tesselator& t = Tesselator::instance;
|
||||||
|
t.begin();
|
||||||
|
|
||||||
|
// UV coordinates (64x32 skin layout)
|
||||||
|
const float u0 = 1.0f / 64.0f;
|
||||||
|
const float u1 = 11.0f / 64.0f;
|
||||||
|
const float u2 = 12.0f / 64.0f;
|
||||||
|
const float u3 = 22.0f / 64.0f;
|
||||||
|
|
||||||
|
const float uL0 = 0.0f / 64.0f;
|
||||||
|
const float uL1 = 1.0f / 64.0f;
|
||||||
|
|
||||||
|
const float uR0 = 11.0f / 64.0f;
|
||||||
|
const float uR1 = 12.0f / 64.0f;
|
||||||
|
|
||||||
|
const float v0 = 0.0f / 32.0f;
|
||||||
|
const float v1 = 1.0f / 32.0f;
|
||||||
|
|
||||||
|
const float vTop = 1.0f / 32.0f;
|
||||||
|
const float vBottom = 17.0f / 32.0f;
|
||||||
|
|
||||||
|
// Cape size (10x16x1 pixels)
|
||||||
|
const float halfW = 5.0f;
|
||||||
|
const float height = 16.0f;
|
||||||
|
const float depth = 1.0f;
|
||||||
|
|
||||||
|
// Front
|
||||||
|
t.tex(u0, vTop); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u1, vTop); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u1, vBottom); t.vertex(halfW, height, 0.0f);
|
||||||
|
t.tex(u0, vBottom); t.vertex(-halfW, height, 0.0f);
|
||||||
|
|
||||||
|
// Back
|
||||||
|
t.tex(u2, vTop); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(u3, vTop); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(u3, vBottom); t.vertex(-halfW, height, depth);
|
||||||
|
t.tex(u2, vBottom); t.vertex(halfW, height, depth);
|
||||||
|
|
||||||
|
// Left
|
||||||
|
t.tex(uL0, vTop); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(uL1, vTop); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(uL1, vBottom); t.vertex(-halfW, height, 0.0f);
|
||||||
|
t.tex(uL0, vBottom); t.vertex(-halfW, height, depth);
|
||||||
|
|
||||||
|
// Right
|
||||||
|
t.tex(uR0, vTop); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(uR1, vTop); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(uR1, vBottom); t.vertex(halfW, height, depth);
|
||||||
|
t.tex(uR0, vBottom); t.vertex(halfW, height, 0.0f);
|
||||||
|
|
||||||
|
// Top
|
||||||
|
t.tex(u0, v0); t.vertex(-halfW, 0.0f, depth);
|
||||||
|
t.tex(u1, v0); t.vertex(halfW, 0.0f, depth);
|
||||||
|
t.tex(u1, v1); t.vertex(halfW, 0.0f, 0.0f);
|
||||||
|
t.tex(u0, v1); t.vertex(-halfW, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
t.tex(u2, v0); t.vertex(halfW, height, 0.0f);
|
||||||
|
t.tex(u3, v0); t.vertex(-halfW, height, 0.0f);
|
||||||
|
t.tex(u3, v1); t.vertex(-halfW, height, depth);
|
||||||
|
t.tex(u2, v1); t.vertex(halfW, height, depth);
|
||||||
|
|
||||||
|
t.draw();
|
||||||
|
|
||||||
|
glPopMatrix2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) {
|
void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) {
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
HumanoidModel* humanoidModel;
|
HumanoidModel* humanoidModel;
|
||||||
|
|
||||||
|
// Last rotation values for cape smoothing (reduces jitter)
|
||||||
|
float lastCapeXRot;
|
||||||
|
float lastCapeZRot;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ Mob::Mob(Level* level)
|
|||||||
invulnerableDuration(20),
|
invulnerableDuration(20),
|
||||||
//hasHair(false),
|
//hasHair(false),
|
||||||
textureName("mob/char.png"),
|
textureName("mob/char.png"),
|
||||||
|
capeTextureName(""),
|
||||||
allowAlpha(true),
|
allowAlpha(true),
|
||||||
modelName(""),
|
modelName(""),
|
||||||
bobStrength(1),
|
bobStrength(1),
|
||||||
@@ -82,6 +83,15 @@ Mob::Mob(Level* level)
|
|||||||
yRot = (float) (Mth::random() * Mth::PI * 2);
|
yRot = (float) (Mth::random() * Mth::PI * 2);
|
||||||
|
|
||||||
this->footSize = 0.5f;
|
this->footSize = 0.5f;
|
||||||
|
|
||||||
|
// Initialize cape inertia positions
|
||||||
|
xCape = x;
|
||||||
|
yCape = y;
|
||||||
|
zCape = z;
|
||||||
|
|
||||||
|
xc = xCape;
|
||||||
|
yc = yCape;
|
||||||
|
zc = zCape;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob::~Mob() {
|
Mob::~Mob() {
|
||||||
@@ -115,6 +125,16 @@ void Mob::setTextureName(const std::string& name)
|
|||||||
textureName = name;
|
textureName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Mob::getCapeTexture()
|
||||||
|
{
|
||||||
|
return capeTextureName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::setCapeTextureName(const std::string& name)
|
||||||
|
{
|
||||||
|
capeTextureName = name;
|
||||||
|
}
|
||||||
|
|
||||||
bool Mob::isPickable()
|
bool Mob::isPickable()
|
||||||
{
|
{
|
||||||
return !removed;
|
return !removed;
|
||||||
@@ -274,6 +294,10 @@ void Mob::superTick()
|
|||||||
|
|
||||||
void Mob::tick()
|
void Mob::tick()
|
||||||
{
|
{
|
||||||
|
xc = xCape;
|
||||||
|
yc = yCape;
|
||||||
|
zc = zCape;
|
||||||
|
|
||||||
super::tick();
|
super::tick();
|
||||||
|
|
||||||
if (arrowCount > 0) {
|
if (arrowCount > 0) {
|
||||||
@@ -378,6 +402,18 @@ void Mob::tick()
|
|||||||
while (xRot - xRotO >= 180)
|
while (xRot - xRotO >= 180)
|
||||||
xRotO += 360;
|
xRotO += 360;
|
||||||
animStep += walkSpeed;
|
animStep += walkSpeed;
|
||||||
|
|
||||||
|
// Reduce jitter by using a smaller interpolation factor (more lag, smoother motion)
|
||||||
|
double dxCape = x - xCape;
|
||||||
|
double dyCape = y - yCape;
|
||||||
|
double dzCape = z - zCape;
|
||||||
|
|
||||||
|
const double interp = 0.15; // small value for smoother cape motion
|
||||||
|
const double interpY = 0.12; // extra smoothing on vertical movement
|
||||||
|
|
||||||
|
xCape += dxCape * interp;
|
||||||
|
yCape += dyCape * interpY;
|
||||||
|
zCape += dzCape * interp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::setSize( float w, float h )
|
void Mob::setSize( float w, float h )
|
||||||
|
|||||||
@@ -44,9 +44,14 @@ public:
|
|||||||
virtual std::string getTexture();
|
virtual std::string getTexture();
|
||||||
virtual void setTextureName(const std::string& name);
|
virtual void setTextureName(const std::string& name);
|
||||||
|
|
||||||
|
// Optional player cape texture (non-null on clients when available)
|
||||||
|
virtual std::string getCapeTexture();
|
||||||
|
virtual void setCapeTextureName(const std::string& name);
|
||||||
|
|
||||||
virtual bool isAlive();
|
virtual bool isAlive();
|
||||||
virtual bool isPickable();
|
virtual bool isPickable();
|
||||||
virtual bool isPushable();
|
virtual bool isPushable();
|
||||||
|
|
||||||
virtual bool isShootable();
|
virtual bool isShootable();
|
||||||
|
|
||||||
MoveControl* getMoveControl();
|
MoveControl* getMoveControl();
|
||||||
@@ -213,7 +218,22 @@ protected:
|
|||||||
float walkingSpeed;
|
float walkingSpeed;
|
||||||
float flyingSpeed;
|
float flyingSpeed;
|
||||||
|
|
||||||
|
// Cape inertia positions
|
||||||
|
double xCape, yCape, zCape;
|
||||||
|
double xc, yc, zc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Cape position accessors (for renderers)
|
||||||
|
double getCapeX() const { return xCape; }
|
||||||
|
double getCapeY() const { return yCape; }
|
||||||
|
double getCapeZ() const { return zCape; }
|
||||||
|
|
||||||
|
double getCapePrevX() const { return xc; }
|
||||||
|
double getCapePrevY() const { return yc; }
|
||||||
|
double getCapePrevZ() const { return zc; }
|
||||||
|
|
||||||
std::string textureName;
|
std::string textureName;
|
||||||
|
std::string capeTextureName;
|
||||||
std::string modelName;
|
std::string modelName;
|
||||||
int deathScore;
|
int deathScore;
|
||||||
float oRun, run;
|
float oRun, run;
|
||||||
|
|||||||
Reference in New Issue
Block a user