Add initial support for mobs

This commit is contained in:
Drew DeVault 2015-07-02 22:08:41 -06:00
parent b7ba71e095
commit e00cc2fe60
19 changed files with 792 additions and 1 deletions

View File

@ -5,6 +5,12 @@ namespace TrueCraft.API
{
public class PathResult
{
public PathResult()
{
Index = 0;
}
public IList<Coordinates3D> Waypoints;
public int Index;
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class CowEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.9, 1.3, 0.9);
}
}
public override short MaxHealth
{
get
{
return 10;
}
}
public override sbyte MobType
{
get
{
return 92;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class CreeperEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.6, 1.8, 0.6);
}
}
public override short MaxHealth
{
get
{
return 20;
}
}
public override sbyte MobType
{
get
{
return 50;
}
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class GhastEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(4.0);
}
}
public override short MaxHealth
{
get
{
return 10;
}
}
public override sbyte MobType
{
get
{
return 56;
}
}
public override bool BeginUpdate()
{
// Ghasts can fly, no need to work out gravity
// TODO: Think about how to deal with walls and such
return false;
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class GiantZombieEntity : ZombieEntity
{
public override Size Size
{
get
{
return new Size(0.6, 1.8, 0.6) * 6;
}
}
public override short MaxHealth
{
get
{
return 100;
}
}
public override sbyte MobType
{
get
{
return 53;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class HenEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.4, 0.3, 0.4);
}
}
public override short MaxHealth
{
get
{
return 4;
}
}
public override sbyte MobType
{
get
{
return 93;
}
}
}
}

View File

@ -0,0 +1,138 @@
using System;
using TrueCraft.API.Networking;
using TrueCraft.Core.Networking.Packets;
using TrueCraft.API.Entities;
using TrueCraft.API;
using TrueCraft.API.Server;
using System.Linq;
namespace TrueCraft.Core.Entities
{
public abstract class MobEntity : LivingEntity, IAABBEntity
{
public MobEntity()
{
Speed = 1; // TODO: WTF
}
public override IPacket SpawnPacket
{
get
{
return new SpawnMobPacket(EntityID, MobType,
MathHelper.CreateAbsoluteInt(Position.X),
MathHelper.CreateAbsoluteInt(Position.Y),
MathHelper.CreateAbsoluteInt(Position.Z),
MathHelper.CreateRotationByte(Yaw),
MathHelper.CreateRotationByte(Pitch),
Metadata);
}
}
public abstract sbyte MobType { get; }
public virtual void TerrainCollision(Vector3 collisionPoint, Vector3 collisionDirection)
{
// This space intentionally left blank
}
public BoundingBox BoundingBox
{
get
{
return new BoundingBox(Position, Position + Size);
}
}
public virtual bool BeginUpdate()
{
EnablePropertyChange = false;
return true;
}
public virtual void EndUpdate(Vector3 newPosition)
{
EnablePropertyChange = true;
Position = newPosition;
}
public float AccelerationDueToGravity
{
get
{
return 0.08f;
}
}
public float Drag
{
get
{
return 0.02f;
}
}
public float TerminalVelocity
{
get
{
return 3.92f;
}
}
public PathResult CurrentPath { get; set; }
/// <summary>
/// Mob's current speed in m/s.
/// </summary>
public virtual double Speed { get; }
protected DateTime CurrentNodeStart = DateTime.MinValue;
public void Face(Vector3 target)
{
var diff = target - Position;
Yaw = (float)MathHelper.RadiansToDegrees(-(Math.Atan2(diff.X, diff.Z) - Math.PI) + Math.PI); // "Flip" over the 180 mark
}
protected void AdvancePath(bool faceRoute = true)
{
if (CurrentPath != null)
{
if (CurrentNodeStart == DateTime.MinValue)
CurrentNodeStart = DateTime.UtcNow;
// Advance along path
var target = (Vector3)CurrentPath.Waypoints[CurrentPath.Index];
var diff = target - Position;
var max = (DateTime.UtcNow - CurrentNodeStart).TotalSeconds * Speed;
if (faceRoute)
Face(target);
diff.Clamp(max);
Position += diff;
if (Position == target)
{
CurrentPath.Index++;
if (CurrentPath.Index >= CurrentPath.Waypoints.Count)
{
CurrentPath = null;
CurrentNodeStart = DateTime.MinValue;
// TODO: Raise path complete event or something?
}
}
}
}
public override void Update(IEntityManager entityManager)
{
AdvancePath();
var nearby = entityManager.EntitiesInRange(Position, 30);
var player = nearby.FirstOrDefault(e => e is PlayerEntity);
if (player != null)
{
Face(player.Position);
}
base.Update(entityManager);
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class PigEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.9);
}
}
public override short MaxHealth
{
get
{
return 10;
}
}
public override sbyte MobType
{
get
{
return 90;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class SheepEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.9, 1.3, 0.9);
}
}
public override short MaxHealth
{
get
{
return 8;
}
}
public override sbyte MobType
{
get
{
return 91;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class SkeletonEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.6, 1.8, 0.6);
}
}
public override short MaxHealth
{
get
{
return 20;
}
}
public override sbyte MobType
{
get
{
return 51;
}
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class SlimeEntity : MobEntity
{
public byte SlimeSize { get; set; }
public SlimeEntity() : this(4)
{
}
public SlimeEntity(byte size)
{
SlimeSize = size;
}
public override MetadataDictionary Metadata
{
get
{
var meta = base.Metadata;
meta[16] = new MetadataByte(SlimeSize);
return meta;
}
}
public override Size Size
{
get
{
return new Size(0.6 * SlimeSize);
}
}
public override short MaxHealth
{
get
{
return (short)(Math.Pow(SlimeSize, 2));
}
}
public override sbyte MobType
{
get
{
return 55;
}
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using TrueCraft.API.Networking;
using TrueCraft.API;
using TrueCraft.Core.Networking.Packets;
namespace TrueCraft.Core.Entities
{
public class SpiderEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(1.4, 0.9, 1.4);
}
}
public override short MaxHealth
{
get
{
return 16;
}
}
public override sbyte MobType
{
get
{
return 52;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class SquidEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.95);
}
}
public override short MaxHealth
{
get
{
return 10;
}
}
public override sbyte MobType
{
get
{
return 94;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class ZombieEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.6, 1.8, 0.6);
}
}
public override short MaxHealth
{
get
{
return 20;
}
}
public override sbyte MobType
{
get
{
return 54;
}
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using TrueCraft.API;
namespace TrueCraft.Core.Entities
{
public class ZombiePigmanEntity : MobEntity
{
public override Size Size
{
get
{
return new Size(0.6, 1.8, 0.6);
}
}
public override short MaxHealth
{
get
{
return 20;
}
}
public override sbyte MobType
{
get
{
return 57;
}
}
}
}

View File

@ -11,11 +11,23 @@ namespace TrueCraft.Core.Networking.Packets
{
public byte ID { get { return 0x18; } }
public SpawnMobPacket(int entityId, sbyte type, int x, int y, int z, sbyte yaw, sbyte pitch, MetadataDictionary metadata)
{
EntityID = entityId;
MobType = type;
X = x;
Y = y;
Z = z;
Yaw = yaw;
Pitch = pitch;
Metadata = metadata;
}
public int EntityID;
public sbyte MobType;
public int X, Y, Z;
public sbyte Yaw, Pitch;
public MetadataDictionary Metadata; // TODO: Import metadata implementation from Craft.Net
public MetadataDictionary Metadata;
public void ReadPacket(IMinecraftStream stream)
{

View File

@ -330,6 +330,20 @@
<Compile Include="Lighting\WorldLighting.cs" />
<Compile Include="AI\AStarPathFinder.cs" />
<Compile Include="AI\PriorityQueue.cs" />
<Compile Include="Entities\SpiderEntity.cs" />
<Compile Include="Entities\MobEntity.cs" />
<Compile Include="Entities\CreeperEntity.cs" />
<Compile Include="Entities\SkeletonEntity.cs" />
<Compile Include="Entities\GiantZombieEntity.cs" />
<Compile Include="Entities\ZombieEntity.cs" />
<Compile Include="Entities\SlimeEntity.cs" />
<Compile Include="Entities\GhastEntity.cs" />
<Compile Include="Entities\ZombiePigmanEntity.cs" />
<Compile Include="Entities\PigEntity.cs" />
<Compile Include="Entities\SheepEntity.cs" />
<Compile Include="Entities\CowEntity.cs" />
<Compile Include="Entities\HenEntity.cs" />
<Compile Include="Entities\SquidEntity.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

View File

@ -1,6 +1,14 @@
using TrueCraft.API.Networking;
using TrueCraft.Core.Networking.Packets;
using TrueCraft.API;
using System;
using TrueCraft.API.Entities;
using TrueCraft.Core;
using System.Collections.Generic;
using System.Linq;
using TrueCraft.Core.AI;
using TrueCraft.Core.Entities;
using System.Threading.Tasks;
namespace TrueCraft.Commands
{
@ -37,6 +45,167 @@ namespace TrueCraft.Commands
}
}
public class SpawnCommand : Command
{
public override string Name
{
get { return "spawn"; }
}
public override string Description
{
get { return "Spawns a mob."; }
}
public override string[] Aliases
{
get { return new string[0]; }
}
public override void Handle(IRemoteClient client, string alias, string[] arguments)
{
if (arguments.Length != 1)
{
Help(client, alias, arguments);
return;
}
var entityTypes = new List<Type>();
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var t in assembly.GetTypes())
{
if (typeof(IEntity).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)
entityTypes.Add(t);
}
}
arguments[0] = arguments[0].ToUpper();
var type = entityTypes.SingleOrDefault(t => t.Name.ToUpper() == arguments[0] + "ENTITY");
if (type == null)
{
client.SendMessage(ChatColor.Red + "Unknown entity type.");
return;
}
var entity = (IEntity)Activator.CreateInstance(type);
var em = client.Server.GetEntityManagerForWorld(client.World);
entity.Position = client.Entity.Position + MathHelper.FowardVector(client.Entity.Yaw) * 3;
em.SpawnEntity(entity);
}
public override void Help(IRemoteClient client, string alias, string[] arguments)
{
client.SendMessage("/spawn [type]: Spawns a mob of that type.");
}
}
public class ToMeCommand : Command
{
public override string Name
{
get { return "tome"; }
}
public override string Description
{
get { return "Moves a mob towards your position."; }
}
public override string[] Aliases
{
get { return new string[0]; }
}
public override void Handle(IRemoteClient client, string alias, string[] arguments)
{
if (arguments.Length != 1)
{
Help(client, alias, arguments);
return;
}
int id;
if (!int.TryParse(arguments[0], out id))
{
Help(client, alias, arguments);
return;
}
var manager = client.Server.GetEntityManagerForWorld(client.World);
var entity = manager.GetEntityByID(id) as MobEntity;
if (entity == null)
{
client.SendMessage(ChatColor.Red + "An entity with that ID does not exist in this world.");
return;
}
Task.Factory.StartNew(() =>
{
var astar = new AStarPathFinder();
var path = astar.FindPath(client.World, entity.BoundingBox, (Coordinates3D)entity.Position, (Coordinates3D)client.Entity.Position);
if (path == null)
{
client.SendMessage(ChatColor.Red + "It is impossible for this entity to reach you.");
return;
}
entity.CurrentPath = path;
});
}
public override void Help(IRemoteClient client, string alias, string[] arguments)
{
client.SendMessage("/tome [id]: Moves a mob to your position.");
}
}
public class DestroyCommand : Command
{
public override string Name
{
get { return "destroy"; }
}
public override string Description
{
get { return "Destroys a mob. Violently."; }
}
public override string[] Aliases
{
get { return new string[0]; }
}
public override void Handle(IRemoteClient client, string alias, string[] arguments)
{
if (arguments.Length != 1)
{
Help(client, alias, arguments);
return;
}
int id;
if (!int.TryParse(arguments[0], out id))
{
Help(client, alias, arguments);
return;
}
var manager = client.Server.GetEntityManagerForWorld(client.World);
var entity = manager.GetEntityByID(id) as MobEntity;
if (entity == null)
{
client.SendMessage(ChatColor.Red + "An entity with that ID does not exist in this world.");
return;
}
manager.DespawnEntity(entity);
}
public override void Help(IRemoteClient client, string alias, string[] arguments)
{
client.SendMessage("/destroy [id]: " + Description);
}
}
public class TrashCommand : Command
{
public override string Name

View File

@ -316,6 +316,9 @@ namespace TrueCraft
catch (OperationCanceledException)
{
}
catch (NullReferenceException)
{
}
var packets = PacketReader.ReadPackets(this, e.Buffer, e.Offset, e.BytesTransferred);