Custom Models (#537)

* wip custom models

* nameY and bounds stuff

* bobbing, pushes, usesHumanSkin

* parsing of json from blockbench

* heady

* body parts

* fix reference comment

* check part max limit

* update newtonsoft.json

* example of storing custommodel

* loading bbmodel and ccmodel files

* handle visibility toggle, warn for untextured/autouv cubes

* don't use template strings
old people ruling the world

* add hideFirstPersonArm, uScale, vScale

* pull u/vScale from bbmodel

* write raw floats

* maybe fix inflate, remove autouv notice
autouv isn't used for box style

* mirroring support

* rename ext to CustomModels, add RemoveModel packet type

* fix mirroring

* use scary unsafe unk's WriteF32

* send a ChangeModel packet after DefineModel for each entity with the defined model

* some chat command work

* store pixel sizes in ccmodel

* better StoredCustomModel impls

* fixes

* case-insensitive dicts

* spin anim, animModifier new packet field

* spin in blockbench name with anim modifier

* add OnBeforeChangeModelEvent, send custom models only if needed, and remove them when no longer needed

* tell other people to remove your model if you leave their map

* add update all models logic

* fix

* implement upload, use caseless everywhere

* add extra reserved bytes to packet

* undo custom self changes

* make Packet.MaxCustomModelParts public

* remove AABBF32

* split parts into own packet, send all uv coords instead of boxdesc

* undo self changes

* fix indents

* update to use firstPersonArm on CustomModelPart

* OOP

* undo specific plugin changes

* remove BoxDesc

* move CustomModel classes to own file

Co-authored-by: Goodlyay <zackxv7@yahoo.com>
This commit is contained in:
SpiralP 2020-06-24 18:06:18 -07:00 committed by GitHub
parent 21f8ed4cef
commit 15122aaebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 226 additions and 3 deletions

View File

@ -0,0 +1,74 @@
using System;
using MCGalaxy.Maths;
namespace MCGalaxy {
public class CustomModel {
public string name;
// humanoid defaults
public float nameY = 32.5f / 16.0f;
public float eyeY = 26.0f / 16.0f;
public Vec3F32 collisionBounds = new Vec3F32 {
X = (8.6f) / 16.0f,
Y = (28.1f) / 16.0f,
Z = (8.6f) / 16.0f
};
public Vec3F32 pickingBoundsMin = new Vec3F32 {
X = (-8) / 16.0f,
Y = (0) / 16.0f,
Z = (-4) / 16.0f
};
public Vec3F32 pickingBoundsMax = new Vec3F32 {
X = (8) / 16.0f,
Y = (32) / 16.0f,
Z = (4) / 16.0f
};
public bool bobbing = true;
public bool pushes = true;
// if true, uses skin from your account
public bool usesHumanSkin = true;
public bool calcHumanAnims = true;
public UInt16 uScale = 64;
public UInt16 vScale = 64;
public byte partCount;
}
public class CustomModelPart {
/* min and max vec3 points */
public Vec3F32 min;
public Vec3F32 max;
/* uv coords in order: top, bottom, front, back, left, right */
public UInt16[] u1;
public UInt16[] v1;
public UInt16[] u2;
public UInt16[] v2;
/* rotation origin point */
public Vec3F32 rotationOrigin;
public Vec3F32 rotation = new Vec3F32 {
X = 0.0f,
Y = 0.0f,
Z = 0.0f,
};
public CustomModelAnim anim = CustomModelAnim.None;
public float animModifier = 1.0f;
public bool fullbright = false;
public bool firstPersonArm = false;
}
public enum CustomModelAnim {
None = 0,
Head = 1,
LeftLeg = 2,
RightLeg = 3,
LeftArm = 4,
RightArm = 5,
SpinX = 6,
SpinY = 7,
SpinZ = 8,
SpinXVelocity = 9,
SpinYVelocity = 10,
SpinZVelocity = 11,
}
}

View File

@ -470,6 +470,7 @@
<Compile Include="Economy\MessageItems.cs" />
<Compile Include="Economy\NameItems.cs" />
<Compile Include="Economy\RankItem.cs" />
<Compile Include="Entity\CustomModel.cs" />
<Compile Include="Entity\Entities.cs" />
<Compile Include="Entity\Entity.cs" />
<Compile Include="Entity\ModelInfo.cs" />

View File

@ -73,5 +73,8 @@ namespace MCGalaxy.Network {
public const byte CpeVelocityControl = 47;
public const byte CpeDefineEffect = 48;
public const byte CpeSpawnEffect = 49;
public const byte CpeDefineModel = 50;
public const byte CpeDefineModelPart = 51;
public const byte CpeUndefineModel = 52;
}
}

View File

@ -457,7 +457,146 @@ namespace MCGalaxy.Network {
NetUtils.WriteI32((int)(originZ * 32), buffer, 22);
return buffer;
}
public const int MaxCustomModels = 64;
public const int MaxCustomModelParts = 64;
public static byte[] DefineModel(byte modelId, CustomModel customModel) {
// 116 = 1 + 1 + 64 + 1 + 2*4 + 3*4 + 2*3*4 + 2*2 + 1
byte[] buffer = new byte[116];
int i = 0;
buffer[i++] = Opcode.CpeDefineModel;
buffer[i++] = modelId;
// write model name
NetUtils.Write(customModel.name, buffer, i, false);
i += NetUtils.StringSize;
// write bool flags
byte flags = 0;
flags |= (byte)((customModel.bobbing ? 1 : 0) << 0);
flags |= (byte)((customModel.pushes ? 1 : 0) << 1);
flags |= (byte)((customModel.usesHumanSkin ? 1 : 0) << 2);
flags |= (byte)((customModel.calcHumanAnims ? 1 : 0) << 3);
buffer[i++] = flags;
// write nameY, eyeY
NetUtils.WriteF32(customModel.nameY, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.eyeY, buffer, i);
i += 4;
// write collisionBounds
NetUtils.WriteF32(customModel.collisionBounds.X, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.collisionBounds.Y, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.collisionBounds.Z, buffer, i);
i += 4;
// write pickingBoundsAABB
NetUtils.WriteF32(customModel.pickingBoundsMin.X, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.pickingBoundsMin.Y, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.pickingBoundsMin.Z, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.pickingBoundsMax.X, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.pickingBoundsMax.Y, buffer, i);
i += 4;
NetUtils.WriteF32(customModel.pickingBoundsMax.Z, buffer, i);
i += 4;
// write uScale, vScale
NetUtils.WriteU16(customModel.uScale, buffer, i);
i += 2;
NetUtils.WriteU16(customModel.vScale, buffer, i);
i += 2;
// write # CustomModelParts
buffer[i++] = customModel.partCount;
return buffer;
}
public static byte[] DefineModelPart(byte modelId, CustomModelPart part) {
// 104 = 1 + 1 + 3*4 + 3*4 + 6*(2*2 + 2*2) + 3*4 + 3*4 + 1 + 4 + 1
byte[] buffer = new byte[104];
int i = 0;
buffer[i++] = Opcode.CpeDefineModelPart;
buffer[i++] = modelId;
/* write min, max vec3 coords */
NetUtils.WriteF32(part.min.X, buffer, i);
i += 4;
NetUtils.WriteF32(part.min.Y, buffer, i);
i += 4;
NetUtils.WriteF32(part.min.Z, buffer, i);
i += 4;
NetUtils.WriteF32(part.max.X, buffer, i);
i += 4;
NetUtils.WriteF32(part.max.Y, buffer, i);
i += 4;
NetUtils.WriteF32(part.max.Z, buffer, i);
i += 4;
/* write u, v coords for our 6 faces */
for (int j = 0; j < 6; j++) {
NetUtils.WriteU16(part.u1[j], buffer, i);
i += 2;
NetUtils.WriteU16(part.v1[j], buffer, i);
i += 2;
NetUtils.WriteU16(part.u2[j], buffer, i);
i += 2;
NetUtils.WriteU16(part.v2[j], buffer, i);
i += 2;
}
/* write rotation origin point */
NetUtils.WriteF32(part.rotationOrigin.X, buffer, i);
i += 4;
NetUtils.WriteF32(part.rotationOrigin.Y, buffer, i);
i += 4;
NetUtils.WriteF32(part.rotationOrigin.Z, buffer, i);
i += 4;
/* write rotation angles */
NetUtils.WriteF32(part.rotation.X, buffer, i);
i += 4;
NetUtils.WriteF32(part.rotation.Y, buffer, i);
i += 4;
NetUtils.WriteF32(part.rotation.Z, buffer, i);
i += 4;
// write anim
buffer[i++] = (byte)part.anim;
// write animModifier
NetUtils.WriteF32(part.animModifier, buffer, i);
i += 4;
// write bool flags
byte flags = 0;
flags |= (byte)((part.fullbright ? 1 : 0) << 0);
flags |= (byte)((part.firstPersonArm ? 1 : 0) << 1);
buffer[i++] = flags;
return buffer;
}
public static byte[] UndefineModel(byte modelId) {
byte[] buffer = new byte[2];
int i = 0;
buffer[i++] = Opcode.CpeUndefineModel;
buffer[i++] = modelId;
return buffer;
}
#endregion

View File

@ -53,7 +53,12 @@ namespace MCGalaxy {
array[index++] = (byte)(value >> 8);
array[index++] = (byte)(value);
}
public unsafe static void WriteF32(float value, byte[] buffer, int i) {
int num = *(int*)&value;
NetUtils.WriteI32(num, buffer, i);
}
internal static int WritePos(Position pos, byte[] arr, int offset, bool extPos) {
if (!extPos) {
WriteI16((short)pos.X, arr, offset + 0);

View File

@ -51,7 +51,7 @@ namespace MCGalaxy {
new ExtEntry(CpeExt.InstantMOTD), new ExtEntry(CpeExt.FastMap),
new ExtEntry(CpeExt.ExtTextures), new ExtEntry(CpeExt.SetHotbar),
new ExtEntry(CpeExt.SetSpawnpoint), new ExtEntry(CpeExt.VelocityControl),
new ExtEntry(CpeExt.CustomParticles),
new ExtEntry(CpeExt.CustomParticles), new ExtEntry(CpeExt.CustomModels),
#if TEN_BIT_BLOCKS
new ExtEntry(CpeExt.ExtBlocks),
#endif
@ -221,6 +221,7 @@ namespace MCGalaxy {
public const string SetSpawnpoint = "SetSpawnpoint";
public const string VelocityControl = "VelocityControl";
public const string CustomParticles = "CustomParticles";
public const string CustomModels = "CustomModels";
}
public enum CpeMessageType : byte {