Skip to content

Commit faa3516

Browse files
authored
Merge pull request #21 from CobwebSMP/resource-packs
Resource packs
2 parents b5d0db5 + c5661ec commit faa3516

File tree

5 files changed

+118
-30
lines changed

5 files changed

+118
-30
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ FakesAssemblies/
193193
src/MiNET/MiNET.Console/dist
194194
src/MiNET/MiNET.Console/Worlds
195195
src/MiNET/MiNET.Console/Plugins
196+
src/MiNET/MiNET.Console/ResourcePacks
196197
src/MiNET/MiNET.Console/start.bat
197198
src/MiNET/MiNET.Console/server.conf
198199

src/MiNET/MiNET.Console/server.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ Save.Enabled=true
8383
#Enable Redstone functions? true - yes. false - no.
8484
RedstoneEnabled=true
8585

86+
#Force accepte resource packs to join the server. true - yes. false - no.
87+
ForceResourcePacks=false
88+
8689
# ======================================= ADVANCED =======================================
8790
# Change this only on purpose. Don't touch if you are not sure.
8891

@@ -110,6 +113,9 @@ WorldDirectory=Worlds
110113
#Where is plugins located?
111114
PluginDirectory=Plugins
112115

116+
#Where is resource packs located?
117+
ResourceDirectory=ResourcePacks
118+
113119

114120
# ======================================= END =======================================
115121
# There is nothing. Just stuff for development

src/MiNET/MiNET/Player.cs

Lines changed: 83 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
using System.Linq;
3333
using System.Net;
3434
using System.Numerics;
35+
using System.Reflection;
3536
using System.Threading;
37+
using System.Security.Cryptography;
3638
using fNbt;
3739
using log4net;
3840
using MiNET.Blocks;
@@ -52,6 +54,7 @@
5254
using MiNET.Utils.Vectors;
5355
using MiNET.Worlds;
5456
using Newtonsoft.Json;
57+
using System.IO.Compression;
5558

5659
namespace MiNET
5760
{
@@ -106,6 +109,8 @@ public class Player : Entity, IMcpeMessageHandler
106109

107110
public DamageCalculator DamageCalculator { get; set; } = new DamageCalculator();
108111

112+
public TexturePackInfos PlayerPackData { get; set; }
113+
public Dictionary<string, string> PlayerPackMap = new Dictionary<string, string>();
109114

110115
public Player(MiNetServer server, IPEndPoint endPoint) : base(EntityType.None, null)
111116
{
@@ -171,15 +176,25 @@ public virtual void HandleMcpeResourcePackChunkRequest(McpeResourcePackChunkRequ
171176
string result = JsonConvert.SerializeObject(message, jsonSerializerSettings);
172177
Log.Debug($"{message.GetType().Name}\n{result}");
173178

174-
var content = File.ReadAllBytes(@"D:\Temp\ResourcePackChunkData_8f760cf7-2ca4-44ab-ab60-9be2469b9777.zip");
179+
var content = File.ReadAllBytes(PlayerPackMap[message.packageId]);
180+
175181
McpeResourcePackChunkData chunkData = McpeResourcePackChunkData.CreateObject();
176-
chunkData.packageId = "5abdb963-4f3f-4d97-8482-88e2049ab149";
177-
chunkData.chunkIndex = 0; // Package index ?
178-
chunkData.progress = 0; // Long, maybe timestamp?
179-
chunkData.payload = content;
182+
chunkData.packageId = message.packageId;
183+
chunkData.chunkIndex = message.chunkIndex;
184+
chunkData.progress = 16384 * message.chunkIndex;
185+
chunkData.payload = GetChunk(content, (int)chunkData.chunkIndex, 16384);
180186
SendPacket(chunkData);
181187
}
182188

189+
public static byte[] GetChunk(byte[] content, int chunkIndex, int chunkSize)
190+
{
191+
int start = chunkIndex * chunkSize;
192+
int length = Math.Min(chunkSize, content.Length - start);
193+
byte[] chunk = new byte[length];
194+
Array.Copy(content, start, chunk, 0, length);
195+
return chunk;
196+
}
197+
183198
public virtual void HandleMcpePurchaseReceipt(McpePurchaseReceipt message)
184199
{
185200
}
@@ -297,21 +312,32 @@ public virtual void HandleMcpeSetLocalPlayerAsInitialized(McpeSetLocalPlayerAsIn
297312
OnLocalPlayerIsInitialized(new PlayerEventArgs(this));
298313
}
299314

300-
private bool _serverHaveResources = false;
315+
private bool _serverHaveResources = true;
301316

302317
public virtual void HandleMcpeResourcePackClientResponse(McpeResourcePackClientResponse message)
303318
{
304319
if (Log.IsDebugEnabled) Log.Debug($"Handled packet 0x{message.Id:X2}\n{Packet.HexDump(message.Bytes)}");
305320

306321
if (message.responseStatus == 2)
307322
{
308-
McpeResourcePackDataInfo dataInfo = McpeResourcePackDataInfo.CreateObject();
309-
dataInfo.packageId = "5abdb963-4f3f-4d97-8482-88e2049ab149";
310-
dataInfo.maxChunkSize = 1048576;
311-
dataInfo.chunkCount = 1;
312-
dataInfo.compressedPackageSize = 359901; // Lenght of data
313-
dataInfo.hash = new byte[] {57, 38, 13, 50, 39, 63, 88, 63, 59, 27, 63, 63, 63, 63, 6, 63, 54, 7, 84, 63, 47, 91, 63, 120, 63, 120, 42, 5, 104, 2, 63, 18};
314-
SendPacket(dataInfo);
323+
foreach (string packid in message.resourcepackids)
324+
{
325+
var uuid = packid.Substring(0, Math.Min(packid.Length, 36));
326+
var content = File.ReadAllBytes(PlayerPackMap[uuid]);
327+
328+
SHA256 sha256 = SHA256.Create();
329+
byte[] packHash = sha256.ComputeHash(content);
330+
331+
McpeResourcePackDataInfo dataInfo = McpeResourcePackDataInfo.CreateObject();
332+
dataInfo.packageId = uuid;
333+
dataInfo.maxChunkSize = 16384;
334+
dataInfo.chunkCount = (uint) Math.Ceiling((double) content.Count() / 16384);
335+
dataInfo.compressedPackageSize = (ulong) content.Count();
336+
dataInfo.hash = packHash;
337+
dataInfo.isPremium = false;
338+
dataInfo.packType = 6;
339+
SendPacket(dataInfo);
340+
}
315341
return;
316342
}
317343
else if (message.responseStatus == 3)
@@ -332,6 +358,8 @@ public virtual void HandleMcpeResourcePackClientResponse(McpeResourcePackClientR
332358
{
333359
MiNetServer.FastThreadPool.QueueUserWorkItem(() => { Start(null); });
334360
}
361+
PlayerPackData.Clear();
362+
PlayerPackMap.Clear();
335363
return;
336364
}
337365
}
@@ -341,18 +369,45 @@ public virtual void SendResourcePacksInfo()
341369
McpeResourcePacksInfo packInfo = McpeResourcePacksInfo.CreateObject();
342370
if (_serverHaveResources)
343371
{
344-
packInfo.mustAccept = false;
345-
packInfo.behahaviorpackinfos = new ResourcePackInfos
372+
var packInfos = new TexturePackInfos();
373+
var directory = Config.GetProperty("ResourceDirectory", Path.GetDirectoryName(new Uri(Assembly.GetEntryAssembly().Location).LocalPath));
374+
packInfo.mustAccept = Config.GetProperty("ForceResourcePacks", false);
375+
376+
foreach (var zipPack in Directory.GetFiles(directory, "*.zip"))
346377
{
347-
new ResourcePackInfo()
378+
var archive = ZipFile.OpenRead(zipPack);
379+
var packDir = archive.Entries[0].FullName.Substring(0, archive.Entries[0].FullName.IndexOf('/'));
380+
381+
if (packDir == null)
348382
{
349-
UUID = "5abdb963-4f3f-4d97-8482-88e2049ab149",
350-
Version = "0.0.1",
351-
Size = 359901
352-
},
353-
};
354-
}
383+
Log.Error($"Invalid resource pack {zipPack}. Wrong folder structure");
384+
continue;
385+
}
386+
387+
var entry = archive.GetEntry($"{packDir}/manifest.json");
355388

389+
if (entry == null)
390+
{
391+
Log.Error($"Invalid resource pack {packDir}. Unable to locate manifest.json");
392+
continue;
393+
}
394+
395+
using (var stream = entry.Open())
396+
using (var reader = new StreamReader(stream))
397+
{
398+
string jsonContent = reader.ReadToEnd();
399+
manifestStructure obj = JsonConvert.DeserializeObject<manifestStructure>(jsonContent);
400+
packInfos.Add(new TexturePackInfo {
401+
UUID = obj.Header.Uuid,
402+
Version = $"{obj.Header.Version[0]}.{obj.Header.Version[1]}.{obj.Header.Version[2]}",
403+
Size = (ulong) File.ReadAllBytes(zipPack).Count(),
404+
});
405+
PlayerPackMap.Add(obj.Header.Uuid, zipPack);
406+
}
407+
}
408+
PlayerPackData = packInfos;
409+
packInfo.texturepacks = packInfos;
410+
}
356411
SendPacket(packInfo);
357412
}
358413

@@ -363,15 +418,13 @@ public virtual void SendResourcePackStack()
363418

364419
if (_serverHaveResources)
365420
{
366-
packStack.mustAccept = false;
367-
packStack.resourcepackidversions = new ResourcePackIdVersions
421+
packStack.mustAccept = Config.GetProperty("ForceResourcePacks", false);
422+
var packVersions = new ResourcePackIdVersions();
423+
foreach (var packData in PlayerPackData)
368424
{
369-
new PackIdVersion()
370-
{
371-
Id = "5abdb963-4f3f-4d97-8482-88e2049ab149",
372-
Version = "0.0.1"
373-
},
374-
};
425+
packVersions.Add(new PackIdVersion { Id = packData.UUID, Version = packData.Version });
426+
}
427+
packStack.resourcepackidversions = packVersions;
375428
}
376429

377430
SendPacket(packStack);

src/MiNET/MiNET/Utils/ResourcePacks.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,27 @@ public enum ResourcePackType : byte
108108
Skins = 7,
109109
WorldTemplate = 8
110110
}
111+
112+
public class Header
113+
{
114+
public string Description { get; set; }
115+
public string Name { get; set; }
116+
public string Uuid { get; set; }
117+
public List<int> Version { get; set; }
118+
public List<int> MinEngineVersion { get; set; }
119+
}
120+
121+
public class Module
122+
{
123+
public string Type { get; set; }
124+
public string Uuid { get; set; }
125+
public List<int> Version { get; set; }
126+
}
127+
128+
public class manifestStructure
129+
{
130+
public int FormatVersion { get; set; }
131+
public Header Header { get; set; }
132+
public List<Module> Modules { get; set; }
133+
}
111134
}

src/MiNET/MiNET/Worlds/LevelDbProvider.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public void Initialize()
7878
{
7979
BasePath ??= Config.GetProperty("WorldDirectory", "Worlds").Trim();
8080
var pluginDir = Config.GetProperty("PluginDirectory", "Plugins").Trim();
81+
var resourceDir = Config.GetProperty("ResourceDirectory", "ResourcePacks").Trim();
8182

8283
var directory = new DirectoryInfo(Path.Combine(BasePath, "db"));
8384

@@ -109,6 +110,10 @@ public void Initialize()
109110
{
110111
Directory.CreateDirectory(pluginDir);
111112
}
113+
if (!Directory.Exists(resourceDir))
114+
{
115+
Directory.CreateDirectory(resourceDir);
116+
}
112117
SaveLevelInfo(LevelInfo);
113118
}
114119

0 commit comments

Comments
 (0)