ClassiCube/ClassicalSharp/Entities/Entity.cs

178 lines
5.5 KiB
C#

// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using ClassicalSharp.Model;
using OpenTK;
#if USE16_BIT
using BlockID = System.UInt16;
#else
using BlockID = System.Byte;
#endif
namespace ClassicalSharp.Entities {
/// <summary> Contains a model, along with position, velocity, and rotation.
/// May also contain other fields and properties. </summary>
public abstract partial class Entity {
public Entity(Game game) {
this.game = game;
SkinType = game.DefaultPlayerSkinType;
anim = new AnimatedComponent(game, this);
}
/// <summary> The model of this entity. (used for collision detection and rendering) </summary>
public IModel Model;
/// <summary> The name of the model of this entity. </summary>
public string ModelName;
/// <summary> BlockID if model name is a vaid block id. </summary>
/// <remarks> This avoids needing to repeatedly parse ModelName as a byte. </remarks>
public BlockID ModelBlock;
/// <summary> Scale applied to the model for collision detection and rendering. </summary>
public Vector3 ModelScale = new Vector3(1.0f);
public byte ID;
public int TextureId = -1, MobTextureId = -1;
public short Health = 10;
public Vector3 Position;
public Vector3 Velocity;
public Vector3 OldVelocity;
public float HeadX, HeadY, RotX, RotY, RotZ;
protected Game game;
protected internal bool onGround;
internal float StepSize;
internal int tickCount;
internal Matrix4 transform;
public SkinType SkinType;
public AnimatedComponent anim;
public float uScale = 1, vScale = 1;
protected DateTime lastModelChange = new DateTime(1, 1, 1);
public bool NoShade = false;
/// <summary> Rotation of the entity's head horizontally. (i.e. looking north or east) </summary>
public float HeadYRadians {
get { return HeadY * Utils.Deg2Rad; }
set { HeadY = value * Utils.Rad2Deg; }
}
/// <summary> Rotation of the entity's head vertically. (i.e. looking up or down) </summary>
public float HeadXRadians {
get { return HeadX * Utils.Deg2Rad; }
set { HeadX = value * Utils.Rad2Deg; }
}
/// <summary> Returns the size of the model that is used for collision detection. </summary>
public Vector3 Size;
protected void UpdateModel() {
BlockModel model = Model as BlockModel;
if (model != null) model.CalcState(ModelBlock);
}
public abstract void Tick(double delta);
public abstract void SetLocation(LocationUpdate update, bool interpolate);
public abstract void Despawn();
/// <summary> Renders the entity's model, interpolating between the previous and next state. </summary>
public abstract void RenderModel(double deltaTime, float t);
/// <summary> Renders the entity's name over the top of its model. </summary>
/// <remarks> Assumes that RenderModel was previously called this frame. </remarks>
public abstract void RenderName();
public virtual void ContextLost() { }
public virtual void ContextRecreated() { }
/// <summary> Gets the position of the player's eye in the world. </summary>
public Vector3 EyePosition {
get { return new Vector3(Position.X,
Position.Y + Model.GetEyeY(this) * ModelScale.Y, Position.Z); }
}
/// <summary> Gets the block just underneath the player's feet position. </summary>
public BlockID BlockUnderFeet {
get { return GetBlock(new Vector3(Position.X, Position.Y - 0.01f, Position.Z)); }
}
/// <summary> Gets the block at player's eye position. </summary>
public BlockID BlockAtHead {
get { return GetBlock(EyePosition); }
}
protected BlockID GetBlock(Vector3 coords) {
return game.World.SafeGetBlock(Vector3I.Floor(coords));
}
public Matrix4 TransformMatrix(Vector3 scale, Vector3 pos) {
Matrix4 rotZ, rotX, rotY, translate, scaleM;
Matrix4.RotateX(out rotX, -RotX * Utils.Deg2Rad);
Matrix4.RotateY(out rotY, -RotY * Utils.Deg2Rad);
Matrix4.RotateZ(out rotZ, -RotZ * Utils.Deg2Rad);
Matrix4.Scale(out scaleM, scale.X, scale.Y, scale.Z);
Matrix4.Translate(out translate, pos.X, pos.Y, pos.Z);
return rotZ * rotX * rotY * scaleM * translate;
}
/// <summary> Gets the brightness colour of this entity. </summary>
public virtual int Colour() {
Vector3I P = Vector3I.Floor(EyePosition);
return game.World.IsValidPos(P) ? game.Lighting.LightCol(P.X, P.Y, P.Z) : game.Lighting.Outside;
}
/// <summary> Sets the model associated with this entity. </summary>
/// <param name="model"> Can be either 'name' or 'name'|'scale'. </param>
public void SetModel(string model) {
ModelScale = new Vector3(1.0f);
int sep = model.IndexOf('|');
string scale = sep == -1 ? null : model.Substring(sep + 1);
ModelName = sep == -1 ? model : model.Substring(0, sep);
if (Utils.CaselessEquals(model, "giant")) {
ModelName = "humanoid";
ModelScale *= 2;
}
ModelBlock = Block.Air;
if (Byte.TryParse(ModelName, out ModelBlock)) {
ModelName = "block";
}
Model = game.ModelCache.Get(ModelName);
ParseScale(scale);
lastModelChange = DateTime.UtcNow;
MobTextureId = -1;
UpdateModel();
UpdateModelBounds();
}
public void UpdateModelBounds() {
Size = Model.CollisionSize * ModelScale;
modelAABB = Model.PickingBounds;
modelAABB.Min *= ModelScale;
modelAABB.Max *= ModelScale;
}
void ParseScale(string scale) {
if (scale == null) return;
float value;
if (!Utils.TryParseDecimal(scale, out value)) return;
Utils.Clamp(ref value, 0.01f, Model.MaxScale);
ModelScale = new Vector3(value);
}
}
}