From a305c6dbab1c1e061c1afb2f7b52110cd1de1d6c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 4 Jan 2015 13:09:40 +1100 Subject: [PATCH] Implement ChangeModel CPE extension, fix potential crash. --- ClassicalSharp.csproj | 1 + Entities/Player.cs | 10 ++++++- Game/Game.cs | 4 +-- Model/ModelCache.cs | 58 +++++++++++++++++++++++++++++++++++++ Network/NetworkProcessor.cs | 20 +++++++++---- Rendering/PlayerRenderer.cs | 4 +-- 6 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 Model/ModelCache.cs 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 );