summary refs log tree commit diff
path: root/src/Entity.h
blob: c3e2dc34ea23b15d446342380b34b96626096d7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#ifndef CC_ENTITY_H
#define CC_ENTITY_H
#include "EntityComponents.h"
#include "Physics.h"
#include "Constants.h"
#include "PackedCol.h"
#include "String.h"
/* Represents an in-game entity.
   Copyright 2014-2023 ClassiCube | Licensed under BSD-3
*/
struct Model;
struct IGameComponent;
struct ScheduledTask;
struct LocalPlayer;

extern struct IGameComponent TabList_Component;
extern struct IGameComponent Entities_Component;

#ifdef CC_BUILD_SPLITSCREEN
#define MAX_LOCAL_PLAYERS 4
#else
#define MAX_LOCAL_PLAYERS 1
#endif
#define MAX_NET_PLAYERS   255

/* Offset used to avoid floating point roundoff errors. */
#define ENTITY_ADJUSTMENT 0.001f
#define ENTITIES_MAX_COUNT (MAX_NET_PLAYERS + MAX_LOCAL_PLAYERS)
#define ENTITIES_SELF_ID 255

enum NameMode {
	NAME_MODE_NONE, NAME_MODE_HOVERED, NAME_MODE_ALL, NAME_MODE_ALL_HOVERED, NAME_MODE_ALL_UNSCALED, NAME_MODE_COUNT
};
extern const char* const NameMode_Names[NAME_MODE_COUNT];

enum ShadowMode {
	SHADOW_MODE_NONE, SHADOW_MODE_SNAP_TO_BLOCK, SHADOW_MODE_CIRCLE, SHADOW_MODE_CIRCLE_ALL, SHADOW_MODE_COUNT
};
extern const char* const ShadowMode_Names[SHADOW_MODE_COUNT];

enum EntityType { ENTITY_TYPE_NONE, ENTITY_TYPE_PLAYER };

/* Which fields are included/valid in a LocationUpdate */
#define LU_HAS_POS   0x01
#define LU_HAS_PITCH 0x02
#define LU_HAS_YAW   0x04
#define LU_HAS_ROTX  0x08
#define LU_HAS_ROTZ  0x10

/* 0-11-00000 How to move the entity when position field is included */
#define LU_POS_MODEMASK   0x60

/* 0-00-00000 Entity is instantly teleported to update->pos */
#define LU_POS_ABSOLUTE_INSTANT 0x00
/* 0-01-00000 Entity is smoothly moved to update->pos */
#define LU_POS_ABSOLUTE_SMOOTH  0x20
/* 0-10-00000 Entity is smoothly moved to current position + update->pos */
#define LU_POS_RELATIVE_SMOOTH  0x40
/* 0-11-00000 Entity is offset/shifted by update->pos */
#define LU_POS_RELATIVE_SHIFT   0x60

/* If set, then linearly interpolates between current and new angles */
/* If not set, then current angles are immediately updated to new angles */
#define LU_ORI_INTERPOLATE 0x80

/* Represents a location update for an entity. Can be a relative position, full position, and/or an orientation update. */
struct LocationUpdate {
	Vec3 pos;
	float pitch, yaw, rotX, rotZ;
	cc_uint8 flags;
};

/* Represents a position and orientation state */
struct EntityLocation { Vec3 pos; float pitch, yaw, rotX, rotY, rotZ; };

struct Entity;
struct EntityVTABLE {
	void (*Tick)(struct Entity* e, float delta);
	void (*Despawn)(struct Entity* e);
	void (*SetLocation)(struct Entity* e, struct LocationUpdate* update);
	PackedCol (*GetCol)(struct Entity* e);
	void (*RenderModel)(struct Entity* e, float delta, float t);
	cc_bool (*ShouldRenderName)(struct Entity* e);
};

/* Skin is still being downloaded asynchronously */
#define SKIN_FETCH_DOWNLOADING 1
/* Skin was downloaded or copied from another entity with the same skin. */
#define SKIN_FETCH_COMPLETED   2

/* true to restrict model scale (needed for local player, giant model collisions are too costly) */
#define ENTITY_FLAG_MODEL_RESTRICTED_SCALE 0x01
/* Whether the ModelVB field of this Entity instance refers to valid memory */
/* This is just a hack to work around CEF plugin which declares Entity structs instances, */
/*   but those instances are declared using the older struct definition which lacked the ModelVB field */
/* And therefore trying to access the ModelVB Field in entity struct instances created by the CEF plugin */
/*   results in attempting to read or write data from potentially invalid memory */
#define ENTITY_FLAG_HAS_MODELVB 0x02
/* Whether in classic mode, to slightly adjust this entity downwards when rendering it */
/*  to replicate the behaviour of the original vanilla classic client */
#define ENTITY_FLAG_CLASSIC_ADJUST 0x04

/* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */
struct Entity {
	const struct EntityVTABLE* VTABLE;
	Vec3 Position;
	/* NOTE: Do NOT change order of yaw/pitch, this will break models in plugins */
	float Pitch, Yaw, RotX, RotY, RotZ;
	Vec3 Velocity;

	struct Model* Model;
	BlockID ModelBlock; /* BlockID, if model name was originally a valid block. */
	cc_uint8 Flags;
	cc_bool ShouldRender;
	struct AABB ModelAABB;
	Vec3 ModelScale, Size;
	int _skinReqID;
	
	cc_uint8 SkinType;
	cc_uint8 SkinFetchState;
	cc_bool NoShade, OnGround;
	GfxResourceID TextureId, MobTextureId;
	float uScale, vScale;
	struct Matrix Transform;

	struct AnimatedComp Anim;
	char SkinRaw[STRING_SIZE];
	char NameRaw[STRING_SIZE];
	struct Texture NameTex;

	/* Previous and next intended location of the entity */
	/*  Current state is linearly interpolated between prev and next */
	struct EntityLocation prev, next;
	GfxResourceID ModelVB;
};
typedef cc_bool (*Entity_TouchesCondition)(BlockID block);

/* Initialises non-zero fields of the given entity. */
void Entity_Init(struct Entity* e);
/* Gets the position of the eye of the given entity's model. */
Vec3 Entity_GetEyePosition(struct Entity* e);
/* Returns the height of the eye of the given entity's model. */
/* (i.e. distance to eye from feet/base of the model) */
float Entity_GetEyeHeight(struct Entity* e);
/* Calculates the transformation matrix applied when rendering the given entity. */
CC_API void Entity_GetTransform(struct Entity* e, Vec3 pos, Vec3 scale, struct Matrix* m);
void Entity_GetPickingBounds(struct Entity* e, struct AABB* bb);
/* Gets the current collision bounds of the given entity. */
void Entity_GetBounds(struct Entity* e, struct AABB* bb);
/* Sets the model of the entity. (i.e its appearance) */
CC_API void Entity_SetModel(struct Entity* e, const cc_string* model);
/* Updates cached Size and ModelAABB of the given entity. */
/* NOTE: Only needed when manually changing Model or ModelScale. */
/* Entity_SetModel already calls this method. */
void Entity_UpdateModelBounds(struct Entity* e);

/* Whether the given entity is touching any blocks meeting the given condition */
CC_API cc_bool Entity_TouchesAny(struct AABB* bb, Entity_TouchesCondition cond);
cc_bool Entity_TouchesAnyRope(struct Entity* e);
cc_bool Entity_TouchesAnyLava(struct Entity* e);
cc_bool Entity_TouchesAnyWater(struct Entity* e);

/* Sets the nametag above the given entity's head */
void Entity_SetName(struct Entity* e, const cc_string* name);
/* Sets the skin name of the given entity. */
void Entity_SetSkin(struct Entity* e, const cc_string* skin);
void Entity_LerpAngles(struct Entity* e, float t);

/* Global data for all entities */
/* (Actual entities may point to NetPlayers_List or elsewhere) */
CC_VAR extern struct _EntitiesData {
	struct Entity* List[ENTITIES_MAX_COUNT];
	cc_uint8 NamesMode, ShadowsMode;
	struct LocalPlayer* CurPlayer;
} Entities;

/* Ticks all entities */
void Entities_Tick(struct ScheduledTask* task);
/* Renders all entities */
void Entities_RenderModels(float delta, float t);
/* Removes the given entity, raising EntityEvents.Removed event */
void Entities_Remove(EntityID id);
/* Gets the ID of the closest entity to the given entity */
/* Returns -1 if there is no other entity nearby */
int Entities_GetClosest(struct Entity* src);

#define TABLIST_MAX_NAMES 256
/* Data for all entries in tab list */
CC_VAR extern struct _TabListData {
	/* Buffer indices for player/list/group names */
	/* Use TabList_UNSAFE_GetPlayer/List/Group to get these names */
	/* NOTE: An Offset of 0 means the entry is unused */
	cc_uint16 NameOffsets[TABLIST_MAX_NAMES];
	/* Position/Order of this entry within the group */
	cc_uint8  GroupRanks[TABLIST_MAX_NAMES];
	struct StringsBuffer _buffer;
	/* Whether the tablist entry is automatically removed */
	/*  when the entity with the same ID is removed */
	cc_uint8 _entityLinked[TABLIST_MAX_NAMES >> 3];
} TabList;

/* Removes the tab list entry with the given ID, raising TabListEvents.Removed event */
CC_API void TabList_Remove(EntityID id);
/* Sets the data for the tab list entry with the given id */
/* Raises TabListEvents.Changed if replacing, TabListEvents.Added if a new entry */
CC_API void TabList_Set(EntityID id, const cc_string* player, const cc_string* list, const cc_string* group, cc_uint8 rank);

/* Raw unformatted name (for Tab name auto complete) */
#define TabList_UNSAFE_GetPlayer(id) StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets[id] - 3)
/* Formatted name for display in tab list */
#define TabList_UNSAFE_GetList(id)   StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets[id] - 2)
/* Name of the group this entry is in (e.g. rank name, map name) */
#define TabList_UNSAFE_GetGroup(id)  StringsBuffer_UNSAFE_Get(&TabList._buffer, TabList.NameOffsets[id] - 1)

#define TabList_EntityLinked_Get(id)   (TabList._entityLinked[id >> 3] & (1 << (id & 0x7)))
#define TabList_EntityLinked_Set(id)   (TabList._entityLinked[id >> 3] |=  (cc_uint8)(1 << (id & 0x7)))
#define TabList_EntityLinked_Reset(id) (TabList._entityLinked[id >> 3] &= (cc_uint8)~(1 << (id & 0x7)))


/* Represents another entity in multiplayer */
struct NetPlayer {
	struct Entity Base;
	struct NetInterpComp Interp;
};
CC_API void NetPlayer_Init(struct NetPlayer* player);
extern struct NetPlayer NetPlayers_List[MAX_NET_PLAYERS];

struct LocalPlayerInput;
struct LocalPlayerInput {
	void (*GetMovement)(struct LocalPlayer* p, float* xMoving, float* zMoving);
	struct LocalPlayerInput* next;
};
void LocalPlayerInput_Add(struct LocalPlayerInput* source);
void LocalPlayerInput_Remove(struct LocalPlayerInput* source);

/* Represents the user/player's own entity. */
struct LocalPlayer {
	struct Entity Base;
	Vec3 Spawn, OldVelocity;
	float SpawnYaw, SpawnPitch, ReachDistance;
	struct HacksComp Hacks;
	struct TiltComp Tilt;
	struct InterpComp Interp;
	struct CollisionsComp Collisions;
	struct PhysicsComp Physics;
	cc_bool _warnedRespawn, _warnedFly, _warnedNoclip, _warnedZoom;
	cc_uint8 index;
};

extern struct LocalPlayer LocalPlayer_Instances[MAX_LOCAL_PLAYERS];
/* Returns how high (in blocks) the player can jump. */
float LocalPlayer_JumpHeight(struct LocalPlayer* p);
/* Interpolates current position and orientation between Interp.Prev and Interp.Next */
void LocalPlayer_SetInterpPosition(struct LocalPlayer* p, float t);
void LocalPlayer_ResetJumpVelocity(struct LocalPlayer* p);
cc_bool LocalPlayer_CheckCanZoom(struct LocalPlayer* p);
/* Moves local player back to spawn point. */
void LocalPlayers_MoveToSpawn(struct LocationUpdate* update);
void LocalPlayer_CalcDefaultSpawn(struct LocalPlayer* p, struct LocationUpdate* update);
#endif