mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 03:25:14 -04:00
Simplify code related to entity nametags
This commit is contained in:
parent
e267d43976
commit
f527fdaa44
236
src/Entity.c
236
src/Entity.c
@ -70,7 +70,8 @@ void Entity_Init(struct Entity* e) {
|
||||
e->ModelScale = Vec3_Create1(1.0f);
|
||||
e->uScale = 1.0f;
|
||||
e->vScale = 1.0f;
|
||||
e->SkinNameRaw[0] = '\0';
|
||||
e->SkinNameRaw[0] = '\0';
|
||||
e->DisplayNameRaw[0] = '\0';
|
||||
}
|
||||
|
||||
Vec3 Entity_GetEyePosition(struct Entity* e) {
|
||||
@ -216,6 +217,105 @@ bool Entity_TouchesAnyWater(struct Entity* e) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Entity nametag------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#define NAME_IS_EMPTY -30000
|
||||
#define NAME_OFFSET 3 /* offset of back layer of name above an entity */
|
||||
|
||||
static void Entity_MakeNameTexture(struct Entity* e) {
|
||||
String colorlessName; char colorlessBuffer[STRING_SIZE];
|
||||
BitmapCol shadowCol = BITMAPCOL_CONST(80, 80, 80, 255);
|
||||
BitmapCol origWhiteCol;
|
||||
|
||||
struct DrawTextArgs args;
|
||||
bool bitmapped;
|
||||
String name;
|
||||
Size2D size;
|
||||
Bitmap bmp;
|
||||
|
||||
/* Names are always drawn not using the system font */
|
||||
bitmapped = Drawer2D_BitmappedText;
|
||||
Drawer2D_BitmappedText = true;
|
||||
name = String_FromRawArray(e->DisplayNameRaw);
|
||||
|
||||
Drawer2D_MakeFont(&args.font, 24, FONT_STYLE_NORMAL);
|
||||
DrawTextArgs_Make(&args, &name, &args.font, false);
|
||||
size = Drawer2D_MeasureText(&args);
|
||||
|
||||
if (size.Width == 0) {
|
||||
e->NameTex.ID = GFX_NULL;
|
||||
e->NameTex.X = NAME_IS_EMPTY;
|
||||
} else {
|
||||
String_InitArray(colorlessName, colorlessBuffer);
|
||||
size.Width += NAME_OFFSET; size.Height += NAME_OFFSET;
|
||||
|
||||
Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
|
||||
{
|
||||
origWhiteCol = Drawer2D_Cols['f'];
|
||||
|
||||
Drawer2D_Cols['f'] = shadowCol;
|
||||
String_AppendColorless(&colorlessName, &name);
|
||||
args.text = colorlessName;
|
||||
Drawer2D_DrawText(&bmp, &args, NAME_OFFSET, NAME_OFFSET);
|
||||
|
||||
Drawer2D_Cols['f'] = origWhiteCol;
|
||||
args.text = name;
|
||||
Drawer2D_DrawText(&bmp, &args, 0, 0);
|
||||
}
|
||||
Drawer2D_Make2DTexture(&e->NameTex, &bmp, size, 0, 0);
|
||||
Mem_Free(bmp.Scan0);
|
||||
}
|
||||
Drawer2D_BitmappedText = bitmapped;
|
||||
}
|
||||
|
||||
static void Entity_DrawName(struct Entity* e) {
|
||||
VertexP3fT2fC4b vertices[4];
|
||||
PackedCol col = PACKEDCOL_WHITE;
|
||||
|
||||
struct Model* model;
|
||||
struct Matrix mat;
|
||||
Vec3 pos;
|
||||
float scale;
|
||||
Vec2 size;
|
||||
|
||||
if (e->NameTex.X == NAME_IS_EMPTY) return;
|
||||
if (!e->NameTex.ID) Entity_MakeNameTexture(e);
|
||||
Gfx_BindTexture(e->NameTex.ID);
|
||||
|
||||
model = e->Model;
|
||||
Vec3_TransformY(&pos, model->GetNameY(e), &e->Transform);
|
||||
|
||||
scale = model->NameScale * e->ModelScale.Y;
|
||||
scale = scale > 1.0f ? (1.0f/70.0f) : (scale/70.0f);
|
||||
size.X = e->NameTex.Width * scale; size.Y = e->NameTex.Height * scale;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && LocalPlayer_Instance.Hacks.CanSeeAllNames) {
|
||||
Matrix_Mul(&mat, &Gfx.View, &Gfx.Projection); /* TODO: This mul is slow, avoid it */
|
||||
/* Get W component of transformed position */
|
||||
scale = pos.X * mat.Row0.W + pos.Y * mat.Row1.W + pos.Z * mat.Row2.W + mat.Row3.W;
|
||||
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
|
||||
}
|
||||
|
||||
Particle_DoRender(&size, &pos, &e->NameTex.uv, col, vertices);
|
||||
Gfx_SetVertexFormat(VERTEX_FORMAT_P3FT2FC4B);
|
||||
Gfx_UpdateDynamicVb_IndexedTris(Gfx_texVb, vertices, 4);
|
||||
}
|
||||
|
||||
/* Deletes the texture containing the entity's nametag */
|
||||
CC_NOINLINE static void Entity_DeleteNameTex(struct Entity* e) {
|
||||
Gfx_DeleteTexture(&e->NameTex.ID);
|
||||
e->NameTex.X = 0; /* X is used as an 'empty name' flag */
|
||||
}
|
||||
|
||||
void Entity_SetName(struct Entity* e, const String* name) {
|
||||
Entity_DeleteNameTex(e);
|
||||
String_CopyToRawArray(e->DisplayNameRaw, name);
|
||||
/* name texture redraw deferred until necessary */
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------------Entities---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
@ -298,11 +398,15 @@ void Entities_RenderHoveredNames(double delta) {
|
||||
if (hadFog) Gfx_SetFog(true);
|
||||
}
|
||||
|
||||
static void Entity_ContextLost(struct Entity* e) {
|
||||
Entity_DeleteNameTex(e);
|
||||
}
|
||||
|
||||
static void Entities_ContextLost(void* obj) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
Entities.List[i]->VTABLE->ContextLost(Entities.List[i]);
|
||||
Entity_ContextLost(Entities.List[i]);
|
||||
}
|
||||
Gfx_DeleteTexture(&ShadowComponent_ShadowTex);
|
||||
}
|
||||
@ -311,7 +415,7 @@ static void Entities_ContextRecreated(void* obj) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
Entities.List[i]->VTABLE->ContextRecreated(Entities.List[i]);
|
||||
/* name redraw is deferred until rendered */
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,8 +423,8 @@ static void Entities_ChatFontChanged(void* obj) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
|
||||
Player_UpdateNameTex((struct Player*)Entities.List[i]);
|
||||
Entity_DeleteNameTex(Entities.List[i]);
|
||||
/* name redraw is deferred until rendered */
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,97 +570,6 @@ struct IGameComponent TabList_Component = {
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Player----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#define PLAYER_NAME_EMPTY_TEX -30000
|
||||
#define NAME_OFFSET 3 /* offset of back layer of name above an entity */
|
||||
|
||||
static void Player_MakeNameTexture(struct Player* player) {
|
||||
String colorlessName; char colorlessBuffer[STRING_SIZE];
|
||||
BitmapCol shadowCol = BITMAPCOL_CONST(80, 80, 80, 255);
|
||||
BitmapCol origWhiteCol;
|
||||
|
||||
struct DrawTextArgs args;
|
||||
bool bitmapped;
|
||||
String name;
|
||||
Size2D size;
|
||||
Bitmap bmp;
|
||||
|
||||
/* we want names to always be drawn not using the system font */
|
||||
bitmapped = Drawer2D_BitmappedText;
|
||||
Drawer2D_BitmappedText = true;
|
||||
name = String_FromRawArray(player->DisplayNameRaw);
|
||||
|
||||
Drawer2D_MakeFont(&args.font, 24, FONT_STYLE_NORMAL);
|
||||
DrawTextArgs_Make(&args, &name, &args.font, false);
|
||||
size = Drawer2D_MeasureText(&args);
|
||||
|
||||
if (size.Width == 0) {
|
||||
player->NameTex.ID = GFX_NULL;
|
||||
player->NameTex.X = PLAYER_NAME_EMPTY_TEX;
|
||||
} else {
|
||||
String_InitArray(colorlessName, colorlessBuffer);
|
||||
size.Width += NAME_OFFSET; size.Height += NAME_OFFSET;
|
||||
|
||||
Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
|
||||
{
|
||||
origWhiteCol = Drawer2D_Cols['f'];
|
||||
|
||||
Drawer2D_Cols['f'] = shadowCol;
|
||||
String_AppendColorless(&colorlessName, &name);
|
||||
args.text = colorlessName;
|
||||
Drawer2D_DrawText(&bmp, &args, NAME_OFFSET, NAME_OFFSET);
|
||||
|
||||
Drawer2D_Cols['f'] = origWhiteCol;
|
||||
args.text = name;
|
||||
Drawer2D_DrawText(&bmp, &args, 0, 0);
|
||||
}
|
||||
Drawer2D_Make2DTexture(&player->NameTex, &bmp, size, 0, 0);
|
||||
Mem_Free(bmp.Scan0);
|
||||
}
|
||||
Drawer2D_BitmappedText = bitmapped;
|
||||
}
|
||||
|
||||
void Player_UpdateNameTex(struct Player* player) {
|
||||
struct Entity* e = &player->Base;
|
||||
e->VTABLE->ContextLost(e);
|
||||
|
||||
if (Gfx.LostContext) return;
|
||||
Player_MakeNameTexture(player);
|
||||
}
|
||||
|
||||
static void Player_DrawName(struct Player* p) {
|
||||
VertexP3fT2fC4b vertices[4];
|
||||
PackedCol col = PACKEDCOL_WHITE;
|
||||
|
||||
struct Entity* e = &p->Base;
|
||||
struct Model* model;
|
||||
struct Matrix mat;
|
||||
Vec3 pos;
|
||||
float scale;
|
||||
Vec2 size;
|
||||
|
||||
if (p->NameTex.X == PLAYER_NAME_EMPTY_TEX) return;
|
||||
if (!p->NameTex.ID) Player_MakeNameTexture(p);
|
||||
Gfx_BindTexture(p->NameTex.ID);
|
||||
|
||||
model = e->Model;
|
||||
Vec3_TransformY(&pos, model->GetNameY(e), &e->Transform);
|
||||
|
||||
scale = model->NameScale * e->ModelScale.Y;
|
||||
scale = scale > 1.0f ? (1.0f/70.0f) : (scale/70.0f);
|
||||
size.X = p->NameTex.Width * scale; size.Y = p->NameTex.Height * scale;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && LocalPlayer_Instance.Hacks.CanSeeAllNames) {
|
||||
Matrix_Mul(&mat, &Gfx.View, &Gfx.Projection); /* TODO: This mul is slow, avoid it */
|
||||
/* Get W component of transformed position */
|
||||
scale = pos.X * mat.Row0.W + pos.Y * mat.Row1.W + pos.Z * mat.Row2.W + mat.Row3.W;
|
||||
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
|
||||
}
|
||||
|
||||
Particle_DoRender(&size, &pos, &p->NameTex.uv, col, vertices);
|
||||
Gfx_SetVertexFormat(VERTEX_FORMAT_P3FT2FC4B);
|
||||
Gfx_UpdateDynamicVb_IndexedTris(Gfx_texVb, vertices, 4);
|
||||
}
|
||||
|
||||
static struct Player* Player_FirstOtherWithSameSkin(struct Player* player) {
|
||||
struct Entity* entity = &player->Base;
|
||||
struct Player* p;
|
||||
@ -750,22 +763,10 @@ static void Player_Despawn(struct Entity* e) {
|
||||
Gfx_DeleteTexture(&e->TextureId);
|
||||
Player_ResetSkin(player);
|
||||
}
|
||||
e->VTABLE->ContextLost(e);
|
||||
Entity_ContextLost(e);
|
||||
}
|
||||
|
||||
static void Player_ContextLost(struct Entity* e) {
|
||||
struct Player* player = (struct Player*)e;
|
||||
Gfx_DeleteTexture(&player->NameTex.ID);
|
||||
player->NameTex.X = 0; /* X is used as an 'empty name' flag */
|
||||
}
|
||||
|
||||
static void Player_ContextRecreated(struct Entity* e) {
|
||||
struct Player* player = (struct Player*)e;
|
||||
Player_UpdateNameTex(player);
|
||||
}
|
||||
|
||||
void Player_SetName(struct Player* p, const String* name, const String* skin) {
|
||||
String_CopyToRawArray(p->DisplayNameRaw, name);
|
||||
void Player_SetSkin(struct Player* p, const String* skin) {
|
||||
String_CopyToRawArray(p->Base.SkinNameRaw, skin);
|
||||
}
|
||||
|
||||
@ -876,7 +877,7 @@ static void LocalPlayer_RenderModel(struct Entity* e, double deltaTime, float t)
|
||||
|
||||
static void LocalPlayer_RenderName(struct Entity* e) {
|
||||
if (!Camera.Active->isThirdPerson) return;
|
||||
Player_DrawName((struct Player*)e);
|
||||
Entity_DrawName(e);
|
||||
}
|
||||
|
||||
static void LocalPlayer_CheckJumpVelocity(void* obj) {
|
||||
@ -888,14 +889,15 @@ static void LocalPlayer_CheckJumpVelocity(void* obj) {
|
||||
|
||||
static struct EntityVTABLE localPlayer_VTABLE = {
|
||||
LocalPlayer_Tick, Player_Despawn, LocalPlayer_SetLocation, Entity_GetCol,
|
||||
LocalPlayer_RenderModel, LocalPlayer_RenderName, Player_ContextLost, Player_ContextRecreated,
|
||||
LocalPlayer_RenderModel, LocalPlayer_RenderName
|
||||
};
|
||||
static void LocalPlayer_Init(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
struct HacksComp* hacks = &p->Hacks;
|
||||
|
||||
Player_Init(&p->Base);
|
||||
Player_SetName((struct Player*)p, &Game_Username, &Game_Username);
|
||||
Entity_SetName(&p->Base, &Game_Username);
|
||||
Player_SetSkin((struct Player*)p, &Game_Username);
|
||||
Event_RegisterVoid(&UserEvents.HackPermissionsChanged, NULL, LocalPlayer_CheckJumpVelocity);
|
||||
|
||||
p->Collisions.Entity = &p->Base;
|
||||
@ -1110,17 +1112,17 @@ static void NetPlayer_RenderName(struct Entity* e) {
|
||||
|
||||
distance = Model_RenderDistance(e);
|
||||
threshold = Entities.NamesMode == NAME_MODE_ALL_UNSCALED ? 8192 * 8192 : 32 * 32;
|
||||
if (distance <= (float)threshold) Player_DrawName((struct Player*)p);
|
||||
if (distance <= (float)threshold) Entity_DrawName(e);
|
||||
}
|
||||
|
||||
struct EntityVTABLE netPlayer_VTABLE = {
|
||||
NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetCol,
|
||||
NetPlayer_RenderModel, NetPlayer_RenderName, Player_ContextLost, Player_ContextRecreated,
|
||||
NetPlayer_RenderModel, NetPlayer_RenderName
|
||||
};
|
||||
void NetPlayer_Init(struct NetPlayer* p, const String* displayName, const String* skinName) {
|
||||
void NetPlayer_Init(struct NetPlayer* p, const String* skinName) {
|
||||
Mem_Set(p, 0, sizeof(struct NetPlayer));
|
||||
Player_Init(&p->Base);
|
||||
Player_SetName((struct Player*)p, displayName, skinName);
|
||||
Player_SetSkin((struct Player*)p, skinName);
|
||||
p->Base.VTABLE = &netPlayer_VTABLE;
|
||||
}
|
||||
|
||||
|
15
src/Entity.h
15
src/Entity.h
@ -61,8 +61,6 @@ struct EntityVTABLE {
|
||||
PackedCol (*GetCol)(struct Entity* e);
|
||||
void (*RenderModel)(struct Entity* e, double deltaTime, float t);
|
||||
void (*RenderName)(struct Entity* e);
|
||||
void (*ContextLost)(struct Entity* e);
|
||||
void (*ContextRecreated)(struct Entity* e);
|
||||
};
|
||||
|
||||
/* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */
|
||||
@ -87,6 +85,8 @@ struct Entity {
|
||||
|
||||
struct AnimatedComp Anim;
|
||||
char SkinNameRaw[STRING_SIZE];
|
||||
char DisplayNameRaw[STRING_SIZE];
|
||||
struct Texture NameTex;
|
||||
};
|
||||
typedef bool (*Entity_TouchesCondition)(BlockID block);
|
||||
|
||||
@ -115,6 +115,9 @@ bool Entity_TouchesAnyRope(struct Entity* e);
|
||||
bool Entity_TouchesAnyLava(struct Entity* e);
|
||||
bool Entity_TouchesAnyWater(struct Entity* e);
|
||||
|
||||
/* Sets the nametag above the given entity's head */
|
||||
void Entity_SetName(struct Entity* e, const String* name);
|
||||
|
||||
/* Global data for all entities */
|
||||
/* (Actual entities may point to NetPlayers_List or elsewhere) */
|
||||
CC_VAR extern struct _EntitiesData {
|
||||
@ -162,14 +165,12 @@ CC_API void TabList_Set(EntityID id, const String* player, const String* list, c
|
||||
#define TabList_UNSAFE_GetPlayer(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.PlayerNames[id]);
|
||||
#define TabList_UNSAFE_GetList(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.ListNames[id]);
|
||||
#define TabList_UNSAFE_GetGroup(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.GroupNames[id]);
|
||||
#define Player_Layout struct Entity Base; char DisplayNameRaw[STRING_SIZE]; bool FetchedSkin; struct Texture NameTex;
|
||||
#define Player_Layout struct Entity Base; bool FetchedSkin;
|
||||
|
||||
/* Represents a player entity. */
|
||||
struct Player { Player_Layout };
|
||||
/* Sets the display name (name tag above entity) and skin name of the given player. */
|
||||
void Player_SetName(struct Player* player, const String* name, const String* skin);
|
||||
/* Remakes the texture for the name tag of the entity. */
|
||||
void Player_UpdateNameTex(struct Player* player);
|
||||
void Player_SetSkin(struct Player* player, const String* skin);
|
||||
/* Resets the skin of the entity to default. */
|
||||
void Player_ResetSkin(struct Player* player);
|
||||
|
||||
@ -179,7 +180,7 @@ struct NetPlayer {
|
||||
struct NetInterpComp Interp;
|
||||
bool ShouldRender;
|
||||
};
|
||||
void NetPlayer_Init(struct NetPlayer* player, const String* displayName, const String* skinName);
|
||||
void NetPlayer_Init(struct NetPlayer* player, const String* skinName);
|
||||
extern struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID];
|
||||
|
||||
/* Represents the user/player's own entity. */
|
||||
|
@ -231,7 +231,7 @@ void HeldBlockRenderer_Render(double delta) {
|
||||
|
||||
static struct EntityVTABLE heldEntity_VTABLE = {
|
||||
NULL, NULL, NULL, HeldBlockRenderer_GetCol,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL
|
||||
};
|
||||
static void HeldBlockRenderer_Init(void) {
|
||||
Entity_Init(&held_entity);
|
||||
|
@ -150,27 +150,27 @@ static void Protocol_CheckName(EntityID id, String* name, String* skin) {
|
||||
|
||||
static void Classic_ReadAbsoluteLocation(uint8_t* data, EntityID id, bool interpolate);
|
||||
static void Protocol_AddEntity(uint8_t* data, EntityID id, const String* displayName, const String* skinName, bool readPosition) {
|
||||
struct LocalPlayer* p;
|
||||
struct NetPlayer* pl;
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
struct Entity* e;
|
||||
|
||||
if (id != ENTITIES_SELF_ID) {
|
||||
if (Entities.List[id]) Entities_Remove(id);
|
||||
pl = &NetPlayers_List[id];
|
||||
e = &NetPlayers_List[id].Base;
|
||||
|
||||
NetPlayer_Init(pl, displayName, skinName);
|
||||
Entities.List[id] = &pl->Base;
|
||||
NetPlayer_Init((struct NetPlayer*)e, skinName);
|
||||
Entities.List[id] = e;
|
||||
Event_RaiseInt(&EntityEvents.Added, id);
|
||||
} else {
|
||||
p = &LocalPlayer_Instance;
|
||||
p->Base.VTABLE->Despawn(&p->Base);
|
||||
e = &LocalPlayer_Instance.Base;
|
||||
e->VTABLE->Despawn(e);
|
||||
/* Always reset the texture here, in case other network players are using the same skin as us */
|
||||
/* In that case, we don't want the fetching of new skin for us to delete the texture used by them */
|
||||
Player_ResetSkin((struct Player*)p);
|
||||
p->FetchedSkin = false;
|
||||
|
||||
Player_SetName((struct Player*)p, displayName, skinName);
|
||||
Player_UpdateNameTex((struct Player*)p);
|
||||
Player_SetSkin((struct Player*)p, skinName);
|
||||
}
|
||||
Entity_SetName(e, displayName);
|
||||
|
||||
if (!readPosition) return;
|
||||
Classic_ReadAbsoluteLocation(data, id, false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user