1 /**
2 Copyright: Copyright (c) 2016-2018 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 voxelman.graphics;
9 import voxelman.log;
10 import voxelman.math;
11 import std.array : array;
12 import cbor;
13 import pluginlib;
14 import voxelman.core.config : BlockId;
15 import voxelman.world.storage;
16 import voxelman.world.block;
17 import voxelman.utils.mapping;
18 import voxelman.globalconfig;
19 
20 import voxelman.world.serverworld;
21 import voxelman.world.clientworld;
22 
23 enum TEX_TILE_SIZE = 32;
24 enum TEX_TILE_SIZE_VEC = ivec2(TEX_TILE_SIZE, TEX_TILE_SIZE);
25 
26 final class BlockManager : IResourceManager
27 {
28 private:
29 	Mapping!BlockInfo blockMapping;
30 
31 public:
32 	override string id() @property { return "voxelman.block.blockmanager"; }
33 	override void preInit()
34 	{
35 		regBaseBlocks(&regBlock);
36 		sideTable = sideIntersectionTable(NUM_SIDE_MASKS);
37 		setSideTable(sideTable);
38 	}
39 
40 	BlockInfoSetter regBlock(string name)
41 	{
42 		size_t id = blockMapping.put(BlockInfo(name));
43 		assert(id <= BlockId.max);
44 		return BlockInfoSetter(&blockMapping, id);
45 	}
46 
47 	BlockInfoTable getBlocks()
48 	{
49 		return BlockInfoTable(cast(immutable)blockMapping.infoArray, sideTable);
50 	}
51 
52 	// returns size_t.max if not found
53 	size_t getId(string name)
54 	{
55 		return blockMapping.id(name);
56 	}
57 
58 	SideIntersectionTable sideTable;
59 }
60 
61 mixin template BlockPluginCommonImpl()
62 {
63 	private BlockManager bm;
64 	auto dbKey = IoKey("voxelman.block.block_mapping");
65 
66 	override void registerResourceManagers(void delegate(IResourceManager) registerHandler)
67 	{
68 		registerHandler(bm = new BlockManager);
69 	}
70 
71 	BlockInfoTable getBlocks()
72 	{
73 		return bm.getBlocks;
74 	}
75 }
76 
77 final class BlockPluginClient : IPlugin
78 {
79 	mixin BlockPluginCommonImpl;
80 	// IPlugin stuff
81 	mixin IdAndSemverFrom!"voxelman.block.plugininfo";
82 	TextureAtlas texAtlas;
83 
84 	override void preInit()
85 	{
86 		texAtlas = new TextureAtlas(256);
87 	}
88 
89 	override void init(IPluginManager pluginman)
90 	{
91 		auto clientWorld = pluginman.getPlugin!ClientWorld;
92 		clientWorld.idMapManager.regIdMapHandler(dbKey.str, &handleBlockMap);
93 		loadTextures();
94 	}
95 
96 	void loadTextures()
97 	{
98 		// fill 0 texture with white color
99 		texAtlas.insert(TEX_TILE_SIZE_VEC, Color4ub(255, 255, 255));
100 
101 		SpriteRef[string] texMap = loadNamedSpriteSheet(BUILD_TO_ROOT_PATH~"res/tex/blocks", texAtlas, TEX_TILE_SIZE_VEC);
102 
103 		Sprite sprite;
104 		SpriteRef missingTexture = texMap.get("missing-texture", null);
105 
106 		if (missingTexture is null)
107 		{
108 			ivec2 atlasPos = texAtlas.insert(TEX_TILE_SIZE_VEC, Color4ub(0, 255, 255));
109 			sprite.atlasRect = irect(atlasPos, TEX_TILE_SIZE_VEC);
110 			missingTexture = &sprite;
111 		}
112 
113 		irect getAtlasRect(string name) {
114 			return texMap.get(name, missingTexture).atlasRect;
115 		}
116 
117 		foreach(ref BlockInfo binfo; bm.blockMapping.infoArray)
118 		{
119 			irect rect = getAtlasRect(binfo.name);
120 			ubyte[2] uv = [cast(ubyte)(rect.x / TEX_TILE_SIZE), cast(ubyte)(rect.y / TEX_TILE_SIZE)];
121 			binfo.uv = uv;
122 			infof("%s uv: %s", binfo.name, uv);
123 		}
124 	}
125 
126 	void handleBlockMap(string[] blocks)
127 	{
128 		bm.blockMapping.setMapping(blocks);
129 	}
130 }
131 
132 final class BlockPluginServer : IPlugin
133 {
134 	mixin BlockPluginCommonImpl;
135 	// IPlugin stuff
136 	mixin IdAndSemverFrom!"voxelman.block.plugininfo";
137 
138 	override void registerResources(IResourceManagerRegistry resmanRegistry)
139 	{
140 		auto ioman = resmanRegistry.getResourceManager!IoManager;
141 		ioman.registerWorldLoadSaveHandlers(&readBlockMap, &writeBlockMap);
142 	}
143 
144 	override void init(IPluginManager pluginman)
145 	{
146 		auto serverWorld = pluginman.getPlugin!ServerWorld;
147 		serverWorld.idMapManager.regIdMapHandler(dbKey.str, () => bm.blockMapping.nameRange.array);
148 	}
149 
150 	void readBlockMap(ref PluginDataLoader loader)
151 	{
152 		loader.readMapping(dbKey, bm.blockMapping);
153 	}
154 
155 	void writeBlockMap(ref PluginDataSaver saver)
156 	{
157 		saver.writeMapping(dbKey, bm.blockMapping);
158 	}
159 }