diff --git a/ClassicalSharp.csproj b/ClassicalSharp.csproj
index d64f3d1cc..d907eef38 100644
--- a/ClassicalSharp.csproj
+++ b/ClassicalSharp.csproj
@@ -117,6 +117,7 @@
+
diff --git a/Entities/Player.cs b/Entities/Player.cs
index bbacbb9b3..a04083de6 100644
--- a/Entities/Player.cs
+++ b/Entities/Player.cs
@@ -1,5 +1,6 @@
using System;
using OpenTK;
+using ClassicalSharp.Model;
using ClassicalSharp.Renderers;
namespace ClassicalSharp {
@@ -27,7 +28,8 @@ namespace ClassicalSharp {
public Game Window;
public byte ID;
public string DisplayName, SkinName;
- public string ModelName = "humanoid";
+ public string ModelName;
+ public IModel Model;
protected PlayerRenderer renderer;
public SkinType SkinType;
@@ -35,6 +37,7 @@ namespace ClassicalSharp {
ID = id;
Window = window;
SkinType = Window.DefaultPlayerSkinType;
+ SetModel( "humanoid" );
}
/// Gets the block just underneath the player's feet position.
@@ -94,5 +97,10 @@ namespace ClassicalSharp {
rightArmXRot += idleXRot;
leftArmXRot -= idleXRot;
}
+
+ public void SetModel( string modelName ) {
+ ModelName = modelName;
+ Model = Window.ModelCache.GetModel( ModelName );
+ }
}
}
\ No newline at end of file
diff --git a/Game/Game.cs b/Game/Game.cs
index 1bce8038a..422142619 100644
--- a/Game/Game.cs
+++ b/Game/Game.cs
@@ -45,7 +45,7 @@ namespace ClassicalSharp {
public ParticleManager ParticleManager;
public PickingRenderer Picking;
public PickedPos SelectedPos;
- public IModel ModelCache;
+ public ModelCache ModelCache;
internal string skinServer, chatInInputBuffer;
public bool CanUseThirdPersonCamera = true;
FpsScreen fpsScreen;
@@ -143,7 +143,7 @@ namespace ClassicalSharp {
protected override void OnLoad( EventArgs e ) {
Graphics = new OpenGLApi();
- ModelCache = new PlayerModel( this );
+ ModelCache = new ModelCache( this );
AsyncDownloader = new AsyncDownloader( skinServer );
PrintGraphicsInfo();
Bitmap terrainBmp = new Bitmap( "terrain.png" );
diff --git a/Model/ModelCache.cs b/Model/ModelCache.cs
new file mode 100644
index 000000000..71d71f3a8
--- /dev/null
+++ b/Model/ModelCache.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+
+namespace ClassicalSharp.Model {
+
+ public class ModelCache {
+
+ Game window;
+ public ModelCache( Game window ) {
+ this.window = window;
+ cache["humanoid"] = new PlayerModel( window );
+ }
+
+ Dictionary cache = new Dictionary();
+ public IModel GetModel( string modelName ) {
+ IModel model;
+ byte blockId;
+ if( Byte.TryParse( modelName, out blockId ) ) {
+ if( !cache.TryGetValue( "block", out model ) ) {
+ model = new BlockModel( window );
+ cache["block"] = model;
+ }
+ return model;
+ } else {
+ if( !cache.TryGetValue( modelName, out model ) ) {
+ model = InitModel( modelName );
+ if( model != null ) {
+ cache[modelName] = model;
+ } else {
+ model = cache["humanoid"]; // fallback to default
+ }
+ }
+ return model;
+ }
+ }
+
+ IModel InitModel( string modelName ) {
+ if( modelName == "chicken" ) {
+ return new ChickenModel( window );
+ } else if( modelName == "creeper" ) {
+ return new CreeperModel( window );
+ } else if( modelName == "pig" ) {
+ return new PigModel( window );
+ } else if( modelName == "skeleton" ) {
+ return new SkeletonModel( window );
+ } else if( modelName == "zombie" ) {
+ return new ZombieModel( window );
+ }
+ return null;
+ }
+
+ public void Dispose() {
+ foreach( var entry in cache ) {
+ entry.Value.Dispose();
+ }
+ }
+ }
+}
diff --git a/Network/NetworkProcessor.cs b/Network/NetworkProcessor.cs
index 0e9a95469..2a77c9ac8 100644
--- a/Network/NetworkProcessor.cs
+++ b/Network/NetworkProcessor.cs
@@ -147,12 +147,11 @@ namespace ClassicalSharp {
// === CPE support list ===
// TextHotKey : unlikely
// ExtPlayerList : yes (only version 1, not 2)
- // ChangeModel : planned
// EnvWeatherType : unlikely
static string[] clientExtensions = new string[] {
"EmoteFix", "ClickDistance", "HeldBlock", "BlockPermissions",
"SelectionCuboid", "MessageTypes", "CustomBlocks", "EnvColors",
- "HackControl", "EnvMapAppearance", "ExtPlayerList",
+ "HackControl", "EnvMapAppearance", "ExtPlayerList", "ChangeModel",
};
@@ -635,6 +634,16 @@ namespace ClassicalSharp {
Window.RaiseBlockPermissionsChanged();
} break;
+ case PacketId.CpeChangeModel:
+ {
+ byte playerId = reader.ReadUInt8();
+ string modelName = reader.ReadString().ToLowerInvariant();
+ Player player = playerId == 0xFF ? Window.LocalPlayer : Window.NetPlayers[playerId];
+ if( player != null ) {
+ player.SetModel( modelName );
+ }
+ } break;
+
case PacketId.CpeEnvSetMapApperance:
{
string url = reader.ReadString();
@@ -715,10 +724,9 @@ namespace ClassicalSharp {
}
void UpdateLocation( byte playerId, LocationUpdate update, bool interpolate ) {
- if( playerId == 0xFF ) {
- Window.LocalPlayer.SetLocation( update, interpolate );
- } else {
- Window.NetPlayers[playerId].SetLocation( update, interpolate );
+ Player player = playerId == 0xFF ? Window.LocalPlayer : Window.NetPlayers[playerId];
+ if( player != null ) {
+ player.SetLocation( update, interpolate );
}
}
#endregion
diff --git a/Rendering/PlayerRenderer.cs b/Rendering/PlayerRenderer.cs
index df4e554a1..e49a43745 100644
--- a/Rendering/PlayerRenderer.cs
+++ b/Rendering/PlayerRenderer.cs
@@ -37,14 +37,14 @@ namespace ClassicalSharp.Renderers {
public void Render( double deltaTime ) {
pos = Player.Position;
- Window.ModelCache.RenderModel( Player, this );
+ Player.Model.RenderModel( Player, this );
DrawName();
}
const float nameScale = 50f;
private void DrawName() {
Graphics.PushMatrix();
- Graphics.Translate( pos.X, pos.Y + Window.ModelCache.NameYOffset, pos.Z );
+ Graphics.Translate( pos.X, pos.Y + Player.Model.NameYOffset, pos.Z );
// Do this to always have names facing the player
float yaw = Window.LocalPlayer.YawDegrees;
Graphics.RotateY( 0f - yaw );