Skip to content

Commit a91347a

Browse files
added furnace and iron and gold tools
1 parent a7cd4c5 commit a91347a

File tree

22 files changed

+913
-8
lines changed

22 files changed

+913
-8
lines changed

include/block/builtin/fluid.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class Fluid : public BlockDescriptor
324324
return b.descriptor->isReplaceableByFluid();
325325
}
326326
public:
327-
virtual void tick(BlockUpdateSet &blockUpdateSet, World &world, const Block &block, BlockIterator blockIterator, WorldLockManager &lock_manager, BlockUpdateKind kind) const
327+
virtual void tick(BlockUpdateSet &blockUpdateSet, World &world, const Block &block, BlockIterator blockIterator, WorldLockManager &lock_manager, BlockUpdateKind kind) const override
328328
{
329329
if(kind == BlockUpdateKind::FluidUpdateNotify)
330330
{

include/block/builtin/furnace.h

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
/*
2+
* Copyright (C) 2012-2015 Jacob R. Lifshay
3+
* This file is part of Voxels.
4+
*
5+
* Voxels is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* Voxels is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with Voxels; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18+
* MA 02110-1301, USA.
19+
*
20+
*/
21+
#ifndef BLOCK_FURNACE_H_INCLUDED
22+
#define BLOCK_FURNACE_H_INCLUDED
23+
24+
#include "block/builtin/full_block.h"
25+
#include "item/item.h"
26+
#include "entity/builtin/tile.h"
27+
#include <mutex>
28+
#include "texture/texture_atlas.h"
29+
#include <cassert>
30+
#include "util/util.h"
31+
#include "util/global_instance_maker.h"
32+
#include "item/builtin/tools/tools.h"
33+
#include "util/logging.h"
34+
35+
namespace programmerjake
36+
{
37+
namespace voxels
38+
{
39+
namespace ui
40+
{
41+
namespace builtin
42+
{
43+
class FurnaceUi;
44+
}
45+
}
46+
47+
namespace Blocks
48+
{
49+
namespace builtin
50+
{
51+
52+
class Furnace final : public FullBlock
53+
{
54+
friend class ui::builtin::FurnaceUi;
55+
private:
56+
struct FurnaceData final
57+
{
58+
std::atomic_bool hasEntity = {false};
59+
std::recursive_mutex lock;
60+
ItemStack outputStack;
61+
ItemStack inputStack;
62+
ItemStack fuelStack;
63+
float burnTimeLeft = 0.0f;
64+
float currentElapsedSmeltTime = 0.0f;
65+
unsigned transferToFuelStack(ItemStack &sourceStack, unsigned transferCount)
66+
{
67+
if(!sourceStack.good())
68+
return 0;
69+
unsigned maxStackCount = sourceStack.item.descriptor->getMaxFurnaceFuelStackCount();
70+
if(fuelStack.count >= maxStackCount)
71+
return 0;
72+
unsigned maxTransferCount = maxStackCount - fuelStack.count;
73+
if(transferCount > maxTransferCount)
74+
transferCount = maxTransferCount;
75+
return fuelStack.transfer(sourceStack, transferCount);
76+
}
77+
unsigned transferFromFuelStack(ItemStack &destStack, unsigned transferCount)
78+
{
79+
return destStack.transfer(fuelStack, transferCount);
80+
}
81+
bool consumeFuel()
82+
{
83+
if(!fuelStack.good())
84+
return false;
85+
float burnTime = fuelStack.item.descriptor->getFurnaceBurnTime();
86+
if(burnTime <= 0)
87+
return false;
88+
ItemStack temp;
89+
if(0 == temp.transfer(fuelStack, 1))
90+
return false;
91+
burnTimeLeft += burnTime;
92+
if(!fuelStack.good())
93+
{
94+
fuelStack = temp.item.descriptor->getItemAfterBurnInFurnace();
95+
}
96+
getDebugLog() << L"consumeFuel" << postnl;
97+
return true;
98+
}
99+
bool canProgressSmeltIgnoringFuel()
100+
{
101+
if(!inputStack.good())
102+
return false;
103+
Item smeltedItem = inputStack.item.descriptor->getSmeltedItem(inputStack.item);
104+
if(!smeltedItem.good())
105+
return false;
106+
ItemStack temp = outputStack;
107+
if(0 == temp.insert(smeltedItem))
108+
return false;
109+
return true;
110+
}
111+
bool canSmeltIgnoringFuel()
112+
{
113+
if(!canProgressSmeltIgnoringFuel())
114+
return false;
115+
if(currentElapsedSmeltTime + eps >= inputStack.item.descriptor->getSmeltTime())
116+
return true;
117+
return false;
118+
}
119+
void smeltItem()
120+
{
121+
if(!inputStack.good())
122+
return;
123+
Item smeltedItem = inputStack.item.descriptor->getSmeltedItem(inputStack.item);
124+
if(!smeltedItem.good())
125+
return;
126+
if(0 == outputStack.insert(smeltedItem))
127+
return;
128+
currentElapsedSmeltTime -= inputStack.item.descriptor->getSmeltTime();
129+
inputStack.remove(inputStack.item);
130+
if(!inputStack.good())
131+
currentElapsedSmeltTime = 0;
132+
getDebugLog() << L"smeltItem" << postnl;
133+
}
134+
};
135+
struct FurnaceBlockData final : BlockData
136+
{
137+
std::shared_ptr<FurnaceData> data;
138+
FurnaceBlockData(std::shared_ptr<FurnaceData> data)
139+
: data(data)
140+
{
141+
}
142+
};
143+
const Entities::builtin::TileEntity *tileEntity;
144+
const bool burning;
145+
public:
146+
const BlockFace facing;
147+
private:
148+
static TextureDescriptor getFaceTexture(BlockFace facing, bool burning, BlockFace face)
149+
{
150+
if(facing == face)
151+
{
152+
if(burning)
153+
return TextureAtlas::FurnaceFrontOn.td();
154+
return TextureAtlas::FurnaceFrontOff.td();
155+
}
156+
if(getBlockFaceOutDirection(face).y == 0)
157+
return TextureAtlas::FurnaceSide.td();
158+
return TextureAtlas::DispenserDropperPistonFurnaceFrame.td();
159+
}
160+
static std::wstring makeName(BlockFace facing, bool burning)
161+
{
162+
std::wstring retval = L"builtin.furnace(facing=";
163+
switch(facing)
164+
{
165+
case BlockFace::NX:
166+
retval += L"NX";
167+
break;
168+
case BlockFace::PX:
169+
retval += L"PX";
170+
break;
171+
case BlockFace::NY:
172+
retval += L"NY";
173+
break;
174+
case BlockFace::PY:
175+
retval += L"PY";
176+
break;
177+
case BlockFace::NZ:
178+
retval += L"NZ";
179+
break;
180+
default:
181+
retval += L"PZ";
182+
break;
183+
}
184+
retval += L",burning=";
185+
if(burning)
186+
retval += L"true";
187+
else
188+
retval += L"false";
189+
retval += L")";
190+
return retval;
191+
}
192+
Furnace(BlockFace facing, bool burning)
193+
: FullBlock(makeName(facing, burning), LightProperties(burning ? Lighting::Lighting::makeArtificialLighting(13) : Lighting(), Lighting::makeMaxLight()), RayCasting::BlockCollisionMaskGround,
194+
true, true, true, true, true, true,
195+
getFaceTexture(facing, burning, BlockFace::NX), getFaceTexture(facing, burning, BlockFace::PX),
196+
getFaceTexture(facing, burning, BlockFace::NY), getFaceTexture(facing, burning, BlockFace::PY),
197+
getFaceTexture(facing, burning, BlockFace::NZ), getFaceTexture(facing, burning, BlockFace::PZ),
198+
RenderLayer::Opaque),
199+
tileEntity(nullptr), burning(burning), facing(facing)
200+
{
201+
tileEntity = new Entities::builtin::TileEntity(this, (Entities::builtin::TileEntity::MoveHandlerType)&Furnace::entityMove);
202+
}
203+
~Furnace()
204+
{
205+
delete tileEntity;
206+
}
207+
void handleSmelt(std::shared_ptr<FurnaceData> data, std::unique_lock<std::recursive_mutex> &lockIt, World &world, WorldLockManager &lock_manager, double deltaTime, bool hasFuel) const
208+
{
209+
if(!data->canProgressSmeltIgnoringFuel())
210+
{
211+
data->currentElapsedSmeltTime = 0;
212+
return;
213+
}
214+
getDebugLog() << L"currentElapsedSmeltTime = " << data->currentElapsedSmeltTime << L", burnTimeLeft = " << data->burnTimeLeft << postnl;
215+
if(!hasFuel)
216+
{
217+
data->currentElapsedSmeltTime -= 2 * deltaTime;
218+
if(data->currentElapsedSmeltTime < 0)
219+
data->currentElapsedSmeltTime = 0;
220+
return;
221+
}
222+
data->currentElapsedSmeltTime += deltaTime;
223+
while(data->canSmeltIgnoringFuel())
224+
{
225+
data->smeltItem();
226+
}
227+
}
228+
void entityMove(Block b, BlockIterator bi, World &world, WorldLockManager &lock_manager, double deltaTime) const
229+
{
230+
assert(b.data != nullptr);
231+
std::shared_ptr<FurnaceData> data = static_cast<FurnaceBlockData *>(b.data.get())->data;
232+
lock_manager.clear();
233+
std::unique_lock<std::recursive_mutex> lockIt(data->lock);
234+
if(data->burnTimeLeft < deltaTime)
235+
{
236+
double deltaTimeLeft = deltaTime;
237+
while(data->burnTimeLeft < deltaTimeLeft)
238+
{
239+
if(data->burnTimeLeft > 0)
240+
handleSmelt(data, lockIt, world, lock_manager, data->burnTimeLeft, true);
241+
deltaTimeLeft -= data->burnTimeLeft;
242+
data->burnTimeLeft = 0;
243+
if(!data->canProgressSmeltIgnoringFuel())
244+
break;
245+
if(!data->consumeFuel())
246+
break;
247+
}
248+
if(data->burnTimeLeft < deltaTimeLeft)
249+
handleSmelt(data, lockIt, world, lock_manager, deltaTimeLeft - data->burnTimeLeft, false);
250+
}
251+
else
252+
{
253+
data->burnTimeLeft -= deltaTime;
254+
handleSmelt(data, lockIt, world, lock_manager, deltaTime, true);
255+
}
256+
bool newBurning = (data->burnTimeLeft > 0);
257+
if(burning != newBurning)
258+
{
259+
world.setBlock(bi, lock_manager, Block(descriptor(facing, newBurning), b.data));
260+
}
261+
}
262+
struct FurnaceMaker final
263+
{
264+
enum_array<enum_array<Furnace *, bool>, BlockFace> furnaces;
265+
FurnaceMaker()
266+
{
267+
for(BlockFace facing : enum_traits<BlockFace>())
268+
{
269+
for(bool v : enum_traits<bool>())
270+
{
271+
furnaces[facing][v] = nullptr;
272+
if(getBlockFaceOutDirection(facing).y == 0)
273+
furnaces[facing][v] = new Furnace(facing, v);
274+
}
275+
}
276+
}
277+
~FurnaceMaker()
278+
{
279+
for(auto &i : furnaces)
280+
for(auto v : i)
281+
delete v;
282+
}
283+
};
284+
static const Furnace *pointer(BlockFace facing, bool burning)
285+
{
286+
return global_instance_maker<FurnaceMaker>::getInstance()->furnaces[facing][burning];
287+
}
288+
static BlockDescriptorPointer descriptor(BlockFace facing, bool burning)
289+
{
290+
return pointer(facing, burning);
291+
}
292+
public:
293+
static const Furnace *pointer(BlockFace facing = BlockFace::NX)
294+
{
295+
return pointer(facing, false);
296+
}
297+
static BlockDescriptorPointer descriptor(BlockFace facing = BlockFace::NX)
298+
{
299+
return pointer(facing);
300+
}
301+
virtual bool isHelpingToolKind(Item tool) const override
302+
{
303+
return dynamic_cast<const Items::builtin::tools::Pickaxe *>(tool.descriptor) != nullptr;
304+
}
305+
virtual void onBreak(World &world, Block b, BlockIterator bi, WorldLockManager &lock_manager, Item &tool) const override;
306+
virtual bool onUse(World &world, Block b, BlockIterator bi, WorldLockManager &lock_manager, std::shared_ptr<Player> player) const override;
307+
virtual float getHardness() const override
308+
{
309+
return 3.5f;
310+
}
311+
virtual ToolLevel getToolLevel() const override
312+
{
313+
return ToolLevel_Wood;
314+
}
315+
virtual void tick(BlockUpdateSet &blockUpdateSet, World &world, const Block &block, BlockIterator blockIterator, WorldLockManager &lock_manager, BlockUpdateKind kind) const override
316+
{
317+
if(block.data == nullptr)
318+
{
319+
blockUpdateSet.emplace_back(blockIterator.position(), Block(this, BlockDataPointer<FurnaceBlockData>(new FurnaceBlockData(std::make_shared<FurnaceData>()))));
320+
return;
321+
}
322+
std::shared_ptr<FurnaceData> data = static_cast<FurnaceBlockData *>(block.data.get())->data;
323+
if(tileEntity && !data->hasEntity.exchange(true))
324+
{
325+
tileEntity->addToWorld(world, lock_manager, blockIterator.position(), block, &data->hasEntity);
326+
}
327+
}
328+
};
329+
330+
}
331+
}
332+
}
333+
}
334+
335+
#endif // BLOCK_FURNACE_H_INCLUDED

0 commit comments

Comments
 (0)