1 /**
2 Copyright: Copyright (c) 2016 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.block.plugin;
7 
8 import std.experimental.logger;
9 import std.array : array;
10 import cbor;
11 import pluginlib;
12 import voxelman.core.config : BlockId;
13 import voxelman.world.storage.coordinates;
14 import voxelman.block.utils;
15 import voxelman.utils.mapping;
16 
17 import voxelman.world.plugin;
18 import voxelman.world.clientworld;
19 
20 final class BlockManager : IResourceManager
21 {
22 private:
23 	Mapping!BlockInfo blockMapping;
24 
25 public:
26 	override string id() @property { return "voxelman.block.blockmanager"; }
27 	override void preInit()
28 	{
29 		regBaseBlocks(&regBlock);
30 	}
31 
32 	BlockInfoSetter regBlock(string name) {
33 		size_t id = blockMapping.put(BlockInfo(name));
34 		assert(id <= BlockId.max);
35 		return BlockInfoSetter(&blockMapping, id);
36 	}
37 }
38 
39 mixin template BlockPluginCommonImpl()
40 {
41 	private BlockManager bm;
42 	immutable string blockMappingKey = "voxelman.block.block_mapping";
43 
44 	override void registerResourceManagers(void delegate(IResourceManager) registerHandler)
45 	{
46 		registerHandler(bm = new BlockManager);
47 	}
48 
49 	override void registerResources(IResourceManagerRegistry resmanRegistry)
50 	{
51 		registerResourcesImpl(resmanRegistry);
52 	}
53 
54 	BlockInfoTable getBlocks()
55 	{
56 		return BlockInfoTable(cast(immutable)bm.blockMapping.infoArray);
57 	}
58 }
59 
60 final class BlockPluginClient : IPlugin
61 {
62 	mixin BlockPluginCommonImpl;
63 	// IPlugin stuff
64 	mixin IdAndSemverFrom!(voxelman.block.plugininfo);
65 
66 	override void init(IPluginManager pluginman)
67 	{
68 		auto clientWorld = pluginman.getPlugin!ClientWorld;
69 		clientWorld.idMapManager.regIdMapHandler(blockMappingKey, &handleBlockMap);
70 	}
71 
72 	void handleBlockMap(string[] blocks)
73 	{
74 		bm.blockMapping.setMapping(blocks);
75 	}
76 
77 	void registerResourcesImpl(IResourceManagerRegistry resmanRegistry){}
78 }
79 
80 final class BlockPluginServer : IPlugin
81 {
82 	mixin BlockPluginCommonImpl;
83 	// IPlugin stuff
84 	mixin IdAndSemverFrom!(voxelman.block.plugininfo);
85 
86 	void registerResourcesImpl(IResourceManagerRegistry resmanRegistry)
87 	{
88 		auto ioman = resmanRegistry.getResourceManager!IoManager;
89 		ioman.registerWorldLoadSaveHandlers(&readBlockMap, &writeBlockMap);
90 	}
91 
92 	override void init(IPluginManager pluginman)
93 	{
94 		auto serverWorld = pluginman.getPlugin!ServerWorld;
95 		serverWorld.idMapManager.regIdMap(blockMappingKey, bm.blockMapping.nameRange.array);
96 	}
97 
98 	void readBlockMap(ref PluginDataLoader loader)
99 	{
100 		ubyte[] data = loader.readEntry(blockMappingKey);
101 
102 		if (data.length)
103 		{
104 			string[] blocks = decodeCborSingleDup!(string[])(data);
105 			bm.blockMapping.setMapping(blocks);
106 		}
107 	}
108 
109 	void writeBlockMap(ref PluginDataSaver saver)
110 	{
111 		auto sink = saver.tempBuffer;
112 		size_t size = 0;
113 		auto blockInfos = bm.blockMapping.infoArray;
114 		size = encodeCborArrayHeader(sink[], blockInfos.length);
115 		foreach(info; blockInfos)
116 			size += encodeCbor(sink[size..$], info.name);
117 		saver.writeEntry(blockMappingKey, size);
118 	}
119 }