mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-16 11:06:06 -04:00
Simplify code related to entity skins
This commit is contained in:
parent
f527fdaa44
commit
ec39ee90a7
418
src/Entity.c
418
src/Entity.c
@ -67,11 +67,14 @@ static PackedCol Entity_GetCol(struct Entity* e) {
|
||||
}
|
||||
|
||||
void Entity_Init(struct Entity* e) {
|
||||
static const String model = String_FromConst("humanoid");
|
||||
e->ModelScale = Vec3_Create1(1.0f);
|
||||
e->uScale = 1.0f;
|
||||
e->vScale = 1.0f;
|
||||
e->uScale = 1.0f;
|
||||
e->vScale = 1.0f;
|
||||
e->StepSize = 0.5f;
|
||||
e->SkinNameRaw[0] = '\0';
|
||||
e->DisplayNameRaw[0] = '\0';
|
||||
Entity_SetModel(e, &model);
|
||||
}
|
||||
|
||||
Vec3 Entity_GetEyePosition(struct Entity* e) {
|
||||
@ -316,6 +319,194 @@ void Entity_SetName(struct Entity* e, const String* name) {
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Entity skins-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static struct Entity* Entity_FirstOtherWithSameSkinAndFetchedSkin(struct Entity* except) {
|
||||
struct Entity* e;
|
||||
String skin, eSkin;
|
||||
int i;
|
||||
|
||||
skin = String_FromRawArray(except->SkinNameRaw);
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i] || Entities.List[i] == except) continue;
|
||||
|
||||
e = Entities.List[i];
|
||||
eSkin = String_FromRawArray(e->SkinNameRaw);
|
||||
if (e->FetchedSkin && String_Equals(&skin, &eSkin)) return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copies skin data from another entity */
|
||||
static void Entity_CopySkin(struct Entity* dst, struct Entity* src) {
|
||||
String skin;
|
||||
dst->TextureId = src->TextureId;
|
||||
dst->SkinType = src->SkinType;
|
||||
dst->uScale = src->uScale;
|
||||
dst->vScale = src->vScale;
|
||||
|
||||
/* Custom mob textures */
|
||||
dst->MobTextureId = GFX_NULL;
|
||||
skin = String_FromRawArray(dst->SkinNameRaw);
|
||||
if (Utils_IsUrlPrefix(&skin, 0)) dst->MobTextureId = dst->TextureId;
|
||||
}
|
||||
|
||||
/* Resets skin data for the given entity */
|
||||
static void Entity_ResetSkin(struct Entity* e) {
|
||||
e->uScale = 1.0f; e->vScale = 1.0f;
|
||||
e->MobTextureId = GFX_NULL;
|
||||
e->TextureId = GFX_NULL;
|
||||
e->SkinType = SKIN_64x32;
|
||||
}
|
||||
|
||||
/* Copies or resets skin data for all entity with same skin */
|
||||
static void Entity_SetSkinAll(struct Entity* source, bool reset) {
|
||||
struct Entity* e;
|
||||
String skin, eSkin;
|
||||
int i;
|
||||
|
||||
skin = String_FromRawArray(source->SkinNameRaw);
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
|
||||
e = Entities.List[i];
|
||||
eSkin = String_FromRawArray(e->SkinNameRaw);
|
||||
if (!String_Equals(&skin, &eSkin)) continue;
|
||||
|
||||
if (reset) {
|
||||
Entity_ResetSkin(e);
|
||||
} else {
|
||||
Entity_CopySkin(e, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clears hat area from a skin bitmap if it's completely white or black,
|
||||
so skins edited with Microsoft Paint or similiar don't have a solid hat */
|
||||
static void Entity_ClearHat(Bitmap* bmp, uint8_t skinType) {
|
||||
int sizeX = (bmp->Width / 64) * 32;
|
||||
int yScale = skinType == SKIN_64x32 ? 32 : 64;
|
||||
int sizeY = (bmp->Height / yScale) * 16;
|
||||
int x, y;
|
||||
|
||||
/* determine if we actually need filtering */
|
||||
for (y = 0; y < sizeY; y++) {
|
||||
BitmapCol* row = Bitmap_GetRow(bmp, y) + sizeX;
|
||||
for (x = 0; x < sizeX; x++) {
|
||||
if (row[x].A != 255) return;
|
||||
}
|
||||
}
|
||||
|
||||
/* only perform filtering when the entire hat is opaque */
|
||||
uint32_t white = PackedCol_ARGB(255, 255, 255, 255);
|
||||
uint32_t black = PackedCol_ARGB(0, 0, 0, 255);
|
||||
for (y = 0; y < sizeY; y++) {
|
||||
uint32_t* row = Bitmap_RawRow(bmp, y) + sizeX;
|
||||
for (x = 0; x < sizeX; x++) {
|
||||
uint32_t pixel = row[x];
|
||||
if (pixel == white || pixel == black) row[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensures skin is a power of two size, resizing if needed. */
|
||||
static void Entity_EnsurePow2(struct Entity* e, Bitmap* bmp) {
|
||||
uint32_t stride;
|
||||
int width, height;
|
||||
Bitmap scaled;
|
||||
int y;
|
||||
|
||||
width = Math_NextPowOf2(bmp->Width);
|
||||
height = Math_NextPowOf2(bmp->Height);
|
||||
if (width == bmp->Width && height == bmp->Height) return;
|
||||
|
||||
Bitmap_Allocate(&scaled, width, height);
|
||||
e->uScale = (float)bmp->Width / width;
|
||||
e->vScale = (float)bmp->Height / height;
|
||||
stride = bmp->Width * 4;
|
||||
|
||||
for (y = 0; y < bmp->Height; y++) {
|
||||
BitmapCol* src = Bitmap_GetRow(bmp, y);
|
||||
BitmapCol* dst = Bitmap_GetRow(&scaled, y);
|
||||
Mem_Copy(dst, src, stride);
|
||||
}
|
||||
|
||||
Mem_Free(bmp->Scan0);
|
||||
*bmp = scaled;
|
||||
}
|
||||
|
||||
static void Entity_CheckSkin(struct Entity* e) {
|
||||
struct Entity* first;
|
||||
String url, skin = String_FromRawArray(e->SkinNameRaw);
|
||||
|
||||
struct HttpRequest item;
|
||||
struct Stream mem;
|
||||
Bitmap bmp;
|
||||
ReturnCode res;
|
||||
|
||||
if (!e->FetchedSkin && e->Model->UsesSkin) {
|
||||
first = Entity_FirstOtherWithSameSkinAndFetchedSkin(e);
|
||||
if (!first) {
|
||||
Http_AsyncGetSkin(&skin);
|
||||
} else {
|
||||
Entity_CopySkin(e, first);
|
||||
}
|
||||
e->FetchedSkin = true;
|
||||
}
|
||||
|
||||
if (!Http_GetResult(&skin, &item)) return;
|
||||
if (!item.Success) { Entity_SetSkinAll(e, true); return; }
|
||||
Stream_ReadonlyMemory(&mem, item.Data, item.Size);
|
||||
|
||||
if ((res = Png_Decode(&bmp, &mem))) {
|
||||
url = String_FromRawArray(item.URL);
|
||||
Logger_Warn2(res, "decoding", &url);
|
||||
Mem_Free(bmp.Scan0); return;
|
||||
}
|
||||
|
||||
Gfx_DeleteTexture(&e->TextureId);
|
||||
Entity_SetSkinAll(e, true);
|
||||
Entity_EnsurePow2(e, &bmp);
|
||||
e->SkinType = Utils_CalcSkinType(&bmp);
|
||||
|
||||
if (bmp.Width > Gfx.MaxTexWidth || bmp.Height > Gfx.MaxTexHeight) {
|
||||
Chat_Add1("&cSkin %s is too large", &skin);
|
||||
} else if (e->SkinType != SKIN_INVALID) {
|
||||
if (e->Model->UsesHumanSkin) Entity_ClearHat(&bmp, e->SkinType);
|
||||
e->TextureId = Gfx_CreateTexture(&bmp, true, false);
|
||||
Entity_SetSkinAll(e, false);
|
||||
}
|
||||
Mem_Free(bmp.Scan0);
|
||||
}
|
||||
|
||||
/* Returns true if no other entities are sharing this skin texture */
|
||||
static bool Entity_CanDeleteTexture(struct Entity* except) {
|
||||
int i;
|
||||
if (!except->TextureId) return false;
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i] || Entities.List[i] == except) continue;
|
||||
if (Entities.List[i]->TextureId == except->TextureId) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CC_NOINLINE static void Entity_DeleteSkin(struct Entity* e) {
|
||||
if (Entity_CanDeleteTexture(e)) {
|
||||
Gfx_DeleteTexture(&e->TextureId);
|
||||
}
|
||||
|
||||
Entity_ResetSkin(e);
|
||||
e->FetchedSkin = false;
|
||||
}
|
||||
|
||||
void Entity_SetSkin(struct Entity* e, const String* skin) {
|
||||
Entity_DeleteSkin(e);
|
||||
String_CopyToRawArray(e->SkinNameRaw, skin);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*--------------------------------------------------------Entities---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
@ -471,7 +662,6 @@ void Entities_DrawShadows(void) {
|
||||
if (Entities.ShadowsMode == SHADOW_MODE_CIRCLE_ALL) {
|
||||
for (i = 0; i < ENTITIES_SELF_ID; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
|
||||
ShadowComponent_Draw(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
@ -567,218 +757,11 @@ struct IGameComponent TabList_Component = {
|
||||
};
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*---------------------------------------------------------Player----------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static struct Player* Player_FirstOtherWithSameSkin(struct Player* player) {
|
||||
struct Entity* entity = &player->Base;
|
||||
struct Player* p;
|
||||
String skin, pSkin;
|
||||
int i;
|
||||
|
||||
skin = String_FromRawArray(entity->SkinNameRaw);
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i] || Entities.List[i] == entity) continue;
|
||||
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
|
||||
|
||||
p = (struct Player*)Entities.List[i];
|
||||
pSkin = String_FromRawArray(p->Base.SkinNameRaw);
|
||||
if (String_Equals(&skin, &pSkin)) return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct Player* Player_FirstOtherWithSameSkinAndFetchedSkin(struct Player* player) {
|
||||
struct Entity* entity = &player->Base;
|
||||
struct Player* p;
|
||||
String skin, pSkin;
|
||||
int i;
|
||||
|
||||
skin = String_FromRawArray(entity->SkinNameRaw);
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i] || Entities.List[i] == entity) continue;
|
||||
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
|
||||
|
||||
p = (struct Player*)Entities.List[i];
|
||||
pSkin = String_FromRawArray(p->Base.SkinNameRaw);
|
||||
if (p->FetchedSkin && String_Equals(&skin, &pSkin)) return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copies skin data from another player */
|
||||
static void Player_CopySkin(struct Player* player, struct Player* from) {
|
||||
struct Entity* dst = &player->Base;
|
||||
struct Entity* src = &from->Base;
|
||||
String skin;
|
||||
|
||||
dst->TextureId = src->TextureId;
|
||||
dst->SkinType = src->SkinType;
|
||||
dst->uScale = src->uScale;
|
||||
dst->vScale = src->vScale;
|
||||
|
||||
/* Custom mob textures */
|
||||
dst->MobTextureId = GFX_NULL;
|
||||
skin = String_FromRawArray(dst->SkinNameRaw);
|
||||
if (Utils_IsUrlPrefix(&skin, 0)) dst->MobTextureId = dst->TextureId;
|
||||
}
|
||||
|
||||
/* Resets skin data for the given player */
|
||||
void Player_ResetSkin(struct Player* player) {
|
||||
struct Entity* e = &player->Base;
|
||||
e->uScale = 1.0f; e->vScale = 1.0f;
|
||||
e->MobTextureId = GFX_NULL;
|
||||
e->TextureId = GFX_NULL;
|
||||
e->SkinType = SKIN_64x32;
|
||||
}
|
||||
|
||||
/* Copies or resets skin data for all players with same skin */
|
||||
static void Player_SetSkinAll(struct Player* player, bool reset) {
|
||||
struct Entity* entity = &player->Base;
|
||||
struct Player* p;
|
||||
String skin, pSkin;
|
||||
int i;
|
||||
|
||||
skin = String_FromRawArray(entity->SkinNameRaw);
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
|
||||
|
||||
p = (struct Player*)Entities.List[i];
|
||||
pSkin = String_FromRawArray(p->Base.SkinNameRaw);
|
||||
if (!String_Equals(&skin, &pSkin)) continue;
|
||||
|
||||
if (reset) {
|
||||
Player_ResetSkin(p);
|
||||
} else {
|
||||
Player_CopySkin(p, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clears hat area from a skin bitmap if it's completely white or black,
|
||||
so skins edited with Microsoft Paint or similiar don't have a solid hat */
|
||||
static void Player_ClearHat(Bitmap* bmp, uint8_t skinType) {
|
||||
int sizeX = (bmp->Width / 64) * 32;
|
||||
int yScale = skinType == SKIN_64x32 ? 32 : 64;
|
||||
int sizeY = (bmp->Height / yScale) * 16;
|
||||
int x, y;
|
||||
|
||||
/* determine if we actually need filtering */
|
||||
for (y = 0; y < sizeY; y++) {
|
||||
BitmapCol* row = Bitmap_GetRow(bmp, y) + sizeX;
|
||||
for (x = 0; x < sizeX; x++) {
|
||||
if (row[x].A != 255) return;
|
||||
}
|
||||
}
|
||||
|
||||
/* only perform filtering when the entire hat is opaque */
|
||||
uint32_t white = PackedCol_ARGB(255, 255, 255, 255);
|
||||
uint32_t black = PackedCol_ARGB(0, 0, 0, 255);
|
||||
for (y = 0; y < sizeY; y++) {
|
||||
uint32_t* row = Bitmap_RawRow(bmp, y) + sizeX;
|
||||
for (x = 0; x < sizeX; x++) {
|
||||
uint32_t pixel = row[x];
|
||||
if (pixel == white || pixel == black) row[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensures skin is a power of two size, resizing if needed. */
|
||||
static void Player_EnsurePow2(struct Player* p, Bitmap* bmp) {
|
||||
uint32_t stride;
|
||||
int width, height;
|
||||
Bitmap scaled;
|
||||
int y;
|
||||
|
||||
width = Math_NextPowOf2(bmp->Width);
|
||||
height = Math_NextPowOf2(bmp->Height);
|
||||
if (width == bmp->Width && height == bmp->Height) return;
|
||||
|
||||
Bitmap_Allocate(&scaled, width, height);
|
||||
p->Base.uScale = (float)bmp->Width / width;
|
||||
p->Base.vScale = (float)bmp->Height / height;
|
||||
stride = bmp->Width * 4;
|
||||
|
||||
for (y = 0; y < bmp->Height; y++) {
|
||||
BitmapCol* src = Bitmap_GetRow(bmp, y);
|
||||
BitmapCol* dst = Bitmap_GetRow(&scaled, y);
|
||||
Mem_Copy(dst, src, stride);
|
||||
}
|
||||
|
||||
Mem_Free(bmp->Scan0);
|
||||
*bmp = scaled;
|
||||
}
|
||||
|
||||
static void Player_CheckSkin(struct Player* p) {
|
||||
struct Entity* e = &p->Base;
|
||||
struct Player* first;
|
||||
String url, skin = String_FromRawArray(e->SkinNameRaw);
|
||||
|
||||
struct HttpRequest item;
|
||||
struct Stream mem;
|
||||
Bitmap bmp;
|
||||
ReturnCode res;
|
||||
|
||||
if (!p->FetchedSkin && e->Model->UsesSkin) {
|
||||
first = Player_FirstOtherWithSameSkinAndFetchedSkin(p);
|
||||
if (!first) {
|
||||
Http_AsyncGetSkin(&skin);
|
||||
} else {
|
||||
Player_CopySkin(p, first);
|
||||
}
|
||||
p->FetchedSkin = true;
|
||||
}
|
||||
|
||||
if (!Http_GetResult(&skin, &item)) return;
|
||||
if (!item.Success) { Player_SetSkinAll(p, true); return; }
|
||||
Stream_ReadonlyMemory(&mem, item.Data, item.Size);
|
||||
|
||||
if ((res = Png_Decode(&bmp, &mem))) {
|
||||
url = String_FromRawArray(item.URL);
|
||||
Logger_Warn2(res, "decoding", &url);
|
||||
Mem_Free(bmp.Scan0); return;
|
||||
}
|
||||
|
||||
Gfx_DeleteTexture(&e->TextureId);
|
||||
Player_SetSkinAll(p, true);
|
||||
Player_EnsurePow2(p, &bmp);
|
||||
e->SkinType = Utils_CalcSkinType(&bmp);
|
||||
|
||||
if (bmp.Width > Gfx.MaxTexWidth || bmp.Height > Gfx.MaxTexHeight) {
|
||||
Chat_Add1("&cSkin %s is too large", &skin);
|
||||
} else if (e->SkinType != SKIN_INVALID) {
|
||||
if (e->Model->UsesHumanSkin) Player_ClearHat(&bmp, e->SkinType);
|
||||
e->TextureId = Gfx_CreateTexture(&bmp, true, false);
|
||||
Player_SetSkinAll(p, false);
|
||||
}
|
||||
Mem_Free(bmp.Scan0);
|
||||
}
|
||||
|
||||
static void Player_Despawn(struct Entity* e) {
|
||||
struct Player* player = (struct Player*)e;
|
||||
struct Player* first = Player_FirstOtherWithSameSkin(player);
|
||||
|
||||
if (!first) {
|
||||
Gfx_DeleteTexture(&e->TextureId);
|
||||
Player_ResetSkin(player);
|
||||
}
|
||||
Entity_DeleteSkin(e);
|
||||
Entity_ContextLost(e);
|
||||
}
|
||||
|
||||
void Player_SetSkin(struct Player* p, const String* skin) {
|
||||
String_CopyToRawArray(p->Base.SkinNameRaw, skin);
|
||||
}
|
||||
|
||||
static void Player_Init(struct Entity* e) {
|
||||
static const String model = String_FromConst("humanoid");
|
||||
Entity_Init(e);
|
||||
|
||||
e->StepSize = 0.5f;
|
||||
e->EntityType = ENTITY_TYPE_PLAYER;
|
||||
Entity_SetModel(e, &model);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------LocalPlayer--------------------------------------------------------*
|
||||
@ -862,7 +845,7 @@ static void LocalPlayer_Tick(struct Entity* e, double delta) {
|
||||
AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta);
|
||||
TiltComp_Update(&p->Tilt, delta);
|
||||
|
||||
Player_CheckSkin((struct Player*)p);
|
||||
Entity_CheckSkin(&p->Base);
|
||||
SoundComp_Tick(wasOnGround);
|
||||
}
|
||||
|
||||
@ -895,9 +878,9 @@ static void LocalPlayer_Init(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
struct HacksComp* hacks = &p->Hacks;
|
||||
|
||||
Player_Init(&p->Base);
|
||||
Entity_Init(&p->Base);
|
||||
Entity_SetName(&p->Base, &Game_Username);
|
||||
Player_SetSkin((struct Player*)p, &Game_Username);
|
||||
Entity_SetSkin(&p->Base, &Game_Username);
|
||||
Event_RegisterVoid(&UserEvents.HackPermissionsChanged, NULL, LocalPlayer_CheckJumpVelocity);
|
||||
|
||||
p->Collisions.Entity = &p->Base;
|
||||
@ -1089,7 +1072,7 @@ static void NetPlayer_SetLocation(struct Entity* e, struct LocationUpdate* updat
|
||||
|
||||
static void NetPlayer_Tick(struct Entity* e, double delta) {
|
||||
struct NetPlayer* p = (struct NetPlayer*)e;
|
||||
Player_CheckSkin((struct Player*)p);
|
||||
Entity_CheckSkin(e);
|
||||
NetInterpComp_AdvanceState(&p->Interp);
|
||||
AnimatedComp_Update(e, p->Interp.Prev.Pos, p->Interp.Next.Pos, delta);
|
||||
}
|
||||
@ -1119,10 +1102,9 @@ struct EntityVTABLE netPlayer_VTABLE = {
|
||||
NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetCol,
|
||||
NetPlayer_RenderModel, NetPlayer_RenderName
|
||||
};
|
||||
void NetPlayer_Init(struct NetPlayer* p, const String* skinName) {
|
||||
void NetPlayer_Init(struct NetPlayer* p) {
|
||||
Mem_Set(p, 0, sizeof(struct NetPlayer));
|
||||
Player_Init(&p->Base);
|
||||
Player_SetSkin((struct Player*)p, skinName);
|
||||
Entity_Init(&p->Base);
|
||||
p->Base.VTABLE = &netPlayer_VTABLE;
|
||||
}
|
||||
|
||||
|
19
src/Entity.h
19
src/Entity.h
@ -77,7 +77,8 @@ struct Entity {
|
||||
Vec3 ModelScale, Size;
|
||||
float StepSize;
|
||||
|
||||
uint8_t SkinType, EntityType;
|
||||
uint8_t SkinType;
|
||||
bool FetchedSkin;
|
||||
bool NoShade, OnGround;
|
||||
GfxResourceID TextureId, MobTextureId;
|
||||
float uScale, vScale;
|
||||
@ -117,6 +118,8 @@ bool Entity_TouchesAnyWater(struct Entity* e);
|
||||
|
||||
/* Sets the nametag above the given entity's head */
|
||||
void Entity_SetName(struct Entity* e, const String* name);
|
||||
/* Sets the skin name of the given entity. */
|
||||
void Entity_SetSkin(struct Entity* e, const String* skin);
|
||||
|
||||
/* Global data for all entities */
|
||||
/* (Actual entities may point to NetPlayers_List or elsewhere) */
|
||||
@ -165,27 +168,19 @@ 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; 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_SetSkin(struct Player* player, const String* skin);
|
||||
/* Resets the skin of the entity to default. */
|
||||
void Player_ResetSkin(struct Player* player);
|
||||
|
||||
/* Represents another entity in multiplayer */
|
||||
struct NetPlayer {
|
||||
Player_Layout
|
||||
struct Entity Base;
|
||||
struct NetInterpComp Interp;
|
||||
bool ShouldRender;
|
||||
};
|
||||
void NetPlayer_Init(struct NetPlayer* player, const String* skinName);
|
||||
void NetPlayer_Init(struct NetPlayer* player);
|
||||
extern struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID];
|
||||
|
||||
/* Represents the user/player's own entity. */
|
||||
struct LocalPlayer {
|
||||
Player_Layout
|
||||
struct Entity Base;
|
||||
Vec3 Spawn, OldVelocity;
|
||||
float SpawnRotY, SpawnHeadX, ReachDistance;
|
||||
struct HacksComp Hacks;
|
||||
|
@ -157,19 +157,13 @@ static void Protocol_AddEntity(uint8_t* data, EntityID id, const String* display
|
||||
if (Entities.List[id]) Entities_Remove(id);
|
||||
e = &NetPlayers_List[id].Base;
|
||||
|
||||
NetPlayer_Init((struct NetPlayer*)e, skinName);
|
||||
NetPlayer_Init((struct NetPlayer*)e);
|
||||
Entities.List[id] = e;
|
||||
Event_RaiseInt(&EntityEvents.Added, id);
|
||||
} else {
|
||||
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_SetSkin((struct Player*)p, skinName);
|
||||
}
|
||||
Entity_SetSkin(e, skinName);
|
||||
Entity_SetName(e, displayName);
|
||||
|
||||
if (!readPosition) return;
|
||||
|
Loading…
x
Reference in New Issue
Block a user