diff options
-rw-r--r-- | CONTRIBUTING.md | 6 | ||||
-rw-r--r-- | CONTRIBUTORS | 1 | ||||
-rw-r--r-- | README.md | 21 | ||||
-rw-r--r-- | Server/Plugins/APIDump/APIDesc.lua | 52 | ||||
-rw-r--r-- | Server/Plugins/APIDump/Classes/Plugins.lua | 4 | ||||
-rw-r--r-- | Server/Plugins/APIDump/Classes/World.lua | 88 | ||||
-rw-r--r-- | Server/Plugins/APIDump/Hooks/OnPlayerOpeningWindow.lua | 20 | ||||
-rw-r--r-- | Server/Plugins/APIDump/InfoFile.html | 28 | ||||
-rw-r--r-- | Server/Plugins/APIDump/main_APIDump.lua | 2 | ||||
-rw-r--r-- | Server/Plugins/InfoDump.lua | 8 | ||||
-rw-r--r-- | Server/Plugins/TestLuaRocks/TestLuaRocks.lua | 24 | ||||
-rw-r--r-- | SetFlags.cmake | 3 | ||||
-rw-r--r-- | dev-docs/.gitignore (renamed from docs/.gitignore) | 0 | ||||
-rw-r--r-- | dev-docs/API class inheritance - blockentities.gv (renamed from docs/API class inheritance - blockentities.gv) | 0 | ||||
-rw-r--r-- | dev-docs/API class inheritance - entities.gv (renamed from docs/API class inheritance - entities.gv) | 0 | ||||
-rw-r--r-- | dev-docs/Cubeset file format.html (renamed from docs/Cubeset file format.html) | 0 | ||||
-rw-r--r-- | dev-docs/Generator.html (renamed from docs/Generator.html) | 0 | ||||
-rw-r--r-- | dev-docs/Login sequence.txt (renamed from docs/Login sequence.txt) | 0 | ||||
-rw-r--r-- | dev-docs/NBT Examples/single chunk NBT data.txt (renamed from docs/NBT Examples/single chunk NBT data.txt) | 0 | ||||
-rw-r--r-- | dev-docs/NBT Examples/tile entities.txt (renamed from docs/NBT Examples/tile entities.txt) | 0 | ||||
-rw-r--r-- | dev-docs/Object ownership.gv (renamed from docs/Object ownership.gv) | 0 | ||||
-rw-r--r-- | dev-docs/Plugin API.md | 3 | ||||
-rw-r--r-- | dev-docs/SocketThreads states.gv (renamed from docs/SocketThreads states.gv) | 0 | ||||
-rw-r--r-- | dev-docs/Springs.ods (renamed from docs/Springs.ods) | bin | 27173 -> 27173 bytes | |||
-rw-r--r-- | dev-docs/_files.txt (renamed from docs/_files.txt) | 0 | ||||
-rw-r--r-- | dev-docs/img/biomalheights.jpg (renamed from docs/img/biomalheights.jpg) | bin | 77747 -> 77747 bytes | |||
-rw-r--r-- | dev-docs/img/biomeheights.jpg (renamed from docs/img/biomeheights.jpg) | bin | 16432 -> 16432 bytes | |||
-rw-r--r-- | dev-docs/img/biomeheightsavg.jpg (renamed from docs/img/biomeheightsavg.jpg) | bin | 14946 -> 14946 bytes | |||
-rw-r--r-- | dev-docs/img/biomes.jpg (renamed from docs/img/biomes.jpg) | bin | 12833 -> 12833 bytes | |||
-rw-r--r-- | dev-docs/img/densitymap.jpg (renamed from docs/img/densitymap.jpg) | bin | 29301 -> 29301 bytes | |||
-rw-r--r-- | dev-docs/img/distortedvoronoibiomes.png (renamed from docs/img/distortedvoronoibiomes.png) | bin | 6012 -> 6012 bytes | |||
-rw-r--r-- | dev-docs/img/finishers.jpg (renamed from docs/img/finishers.jpg) | bin | 14701 -> 14701 bytes | |||
-rw-r--r-- | dev-docs/img/gaussprobability.jpg (renamed from docs/img/gaussprobability.jpg) | bin | 12994 -> 12994 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_add_islands.png (renamed from docs/img/grownexample_add_islands.png) | bin | 1707 -> 1707 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_alt_biomes.png (renamed from docs/img/grownexample_alt_biomes.png) | bin | 1760 -> 1760 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_beaches.png (renamed from docs/img/grownexample_beaches.png) | bin | 1615 -> 1615 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_biome_edges.png (renamed from docs/img/grownexample_biome_edges.png) | bin | 1497 -> 1497 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_biomes.png (renamed from docs/img/grownexample_biomes.png) | bin | 1703 -> 1703 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_grp_edges.png (renamed from docs/img/grownexample_grp_edges.png) | bin | 1457 -> 1457 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_in1.png (renamed from docs/img/grownexample_in1.png) | bin | 1477 -> 1477 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_in2.png (renamed from docs/img/grownexample_in2.png) | bin | 1274 -> 1274 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_in3.png (renamed from docs/img/grownexample_in3.png) | bin | 1532 -> 1532 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_in_alt.png (renamed from docs/img/grownexample_in_alt.png) | bin | 1476 -> 1476 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_in_river.png (renamed from docs/img/grownexample_in_river.png) | bin | 1169 -> 1169 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_m_biomes.png (renamed from docs/img/grownexample_m_biomes.png) | bin | 1842 -> 1842 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_mix_river.png (renamed from docs/img/grownexample_mix_river.png) | bin | 1586 -> 1586 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_river.png (renamed from docs/img/grownexample_river.png) | bin | 1202 -> 1202 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_set_rnd.png (renamed from docs/img/grownexample_set_rnd.png) | bin | 1616 -> 1616 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_smooth.png (renamed from docs/img/grownexample_smooth.png) | bin | 1449 -> 1449 bytes | |||
-rw-r--r-- | dev-docs/img/grownexample_zoom.png (renamed from docs/img/grownexample_zoom.png) | bin | 2167 -> 2167 bytes | |||
-rw-r--r-- | dev-docs/img/heightmap.jpg (renamed from docs/img/heightmap.jpg) | bin | 27951 -> 27951 bytes | |||
-rw-r--r-- | dev-docs/img/jittergrid.jpg (renamed from docs/img/jittergrid.jpg) | bin | 18522 -> 18522 bytes | |||
-rw-r--r-- | dev-docs/img/jittergridlocality.jpg (renamed from docs/img/jittergridlocality.jpg) | bin | 15026 -> 15026 bytes | |||
-rw-r--r-- | dev-docs/img/multistepmapbiomes.png (renamed from docs/img/multistepmapbiomes.png) | bin | 11103 -> 11103 bytes | |||
-rw-r--r-- | dev-docs/img/multistepmapdistance.jpg (renamed from docs/img/multistepmapdistance.jpg) | bin | 16536 -> 16536 bytes | |||
-rw-r--r-- | dev-docs/img/multistepmapgrid.jpg (renamed from docs/img/multistepmapgrid.jpg) | bin | 22910 -> 22910 bytes | |||
-rw-r--r-- | dev-docs/img/perlin.jpg (renamed from docs/img/perlin.jpg) | bin | 24105 -> 24105 bytes | |||
-rw-r--r-- | dev-docs/img/perlincompositor1.jpg (renamed from docs/img/perlincompositor1.jpg) | bin | 15457 -> 15457 bytes | |||
-rw-r--r-- | dev-docs/img/perlincompositor2.jpg (renamed from docs/img/perlincompositor2.jpg) | bin | 29005 -> 29005 bytes | |||
-rw-r--r-- | dev-docs/img/perlincompositor3.jpg (renamed from docs/img/perlincompositor3.jpg) | bin | 21119 -> 21119 bytes | |||
-rw-r--r-- | dev-docs/img/perlinheightmap.jpg (renamed from docs/img/perlinheightmap.jpg) | bin | 53543 -> 53543 bytes | |||
-rw-r--r-- | dev-docs/img/perlinrivers1.jpg (renamed from docs/img/perlinrivers1.jpg) | bin | 20688 -> 20688 bytes | |||
-rw-r--r-- | dev-docs/img/perlinrivers2.jpg (renamed from docs/img/perlinrivers2.jpg) | bin | 28926 -> 28926 bytes | |||
-rw-r--r-- | dev-docs/img/perlinrivers3.jpg (renamed from docs/img/perlinrivers3.jpg) | bin | 28791 -> 28791 bytes | |||
-rw-r--r-- | dev-docs/img/roofprobability.jpg (renamed from docs/img/roofprobability.jpg) | bin | 16679 -> 16679 bytes | |||
-rw-r--r-- | dev-docs/img/smallfoliageclumps.jpg (renamed from docs/img/smallfoliageclumps.jpg) | bin | 15867 -> 15867 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_1.png (renamed from docs/img/smoothedgrown_1.png) | bin | 2082 -> 2082 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_2.png (renamed from docs/img/smoothedgrown_2.png) | bin | 1815 -> 1815 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_3.png (renamed from docs/img/smoothedgrown_3.png) | bin | 1701 -> 1701 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_4.png (renamed from docs/img/smoothedgrown_4.png) | bin | 1571 -> 1571 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_5.png (renamed from docs/img/smoothedgrown_5.png) | bin | 1537 -> 1537 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_6.png (renamed from docs/img/smoothedgrown_6.png) | bin | 1546 -> 1546 bytes | |||
-rw-r--r-- | dev-docs/img/smoothedgrown_7.png (renamed from docs/img/smoothedgrown_7.png) | bin | 1363 -> 1363 bytes | |||
-rw-r--r-- | dev-docs/img/temperaturehumiditydecisionhills.jpg (renamed from docs/img/temperaturehumiditydecisionhills.jpg) | bin | 32979 -> 32979 bytes | |||
-rw-r--r-- | dev-docs/img/temperaturehumiditydecisionsimple.jpg (renamed from docs/img/temperaturehumiditydecisionsimple.jpg) | bin | 18201 -> 18201 bytes | |||
-rw-r--r-- | dev-docs/img/terraincomposition.jpg (renamed from docs/img/terraincomposition.jpg) | bin | 15748 -> 15748 bytes | |||
-rw-r--r-- | dev-docs/img/terrainheight.jpg (renamed from docs/img/terrainheight.jpg) | bin | 11009 -> 11009 bytes | |||
-rw-r--r-- | dev-docs/img/twolevelbiomes.png (renamed from docs/img/twolevelbiomes.png) | bin | 33816 -> 33816 bytes | |||
-rw-r--r-- | dev-docs/img/twolevellargeareas.jpg (renamed from docs/img/twolevellargeareas.jpg) | bin | 17419 -> 17419 bytes | |||
-rw-r--r-- | dev-docs/img/twolevelsmallareas.jpg (renamed from docs/img/twolevelsmallareas.jpg) | bin | 23550 -> 23550 bytes | |||
-rw-r--r-- | dev-docs/img/twolevelsmallgrid.jpg (renamed from docs/img/twolevelsmallgrid.jpg) | bin | 39141 -> 39141 bytes | |||
-rw-r--r-- | dev-docs/img/vanilla_springs_huge.png (renamed from docs/img/vanilla_springs_huge.png) | bin | 29827 -> 29827 bytes | |||
-rw-r--r-- | dev-docs/img/voronoi.png (renamed from docs/img/voronoi.png) | bin | 19306 -> 19306 bytes | |||
-rw-r--r-- | dev-docs/img/voronoijitterbiomes.png (renamed from docs/img/voronoijitterbiomes.png) | bin | 4268 -> 4268 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_1.png (renamed from docs/img/zoomedgrown_1.png) | bin | 817 -> 817 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_2.png (renamed from docs/img/zoomedgrown_2.png) | bin | 880 -> 880 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_3.png (renamed from docs/img/zoomedgrown_3.png) | bin | 955 -> 955 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_4.png (renamed from docs/img/zoomedgrown_4.png) | bin | 1116 -> 1116 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_5.png (renamed from docs/img/zoomedgrown_5.png) | bin | 1516 -> 1516 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_6.png (renamed from docs/img/zoomedgrown_6.png) | bin | 2033 -> 2033 bytes | |||
-rw-r--r-- | dev-docs/img/zoomedgrown_7.png (renamed from docs/img/zoomedgrown_7.png) | bin | 2978 -> 2978 bytes | |||
-rw-r--r-- | dev-docs/js/ValueMap.js (renamed from docs/js/ValueMap.js) | 0 | ||||
-rw-r--r-- | dev-docs/js/grown.js (renamed from docs/js/grown.js) | 0 | ||||
-rw-r--r-- | dev-docs/style.css (renamed from docs/style.css) | 0 | ||||
-rw-r--r-- | src/Bindings/DeprecatedBindings.cpp | 117 | ||||
-rw-r--r-- | src/Bindings/DiffAPIDesc.lua | 11 | ||||
-rw-r--r-- | src/Bindings/LuaState.cpp | 42 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 2 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.cpp | 36 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.h | 12 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 77 | ||||
-rw-r--r-- | src/Bindings/Plugin.h | 1 | ||||
-rw-r--r-- | src/Bindings/PluginLua.cpp | 10 | ||||
-rw-r--r-- | src/Bindings/PluginLua.h | 1 | ||||
-rw-r--r-- | src/Bindings/PluginManager.cpp | 19 | ||||
-rw-r--r-- | src/Bindings/PluginManager.h | 3 | ||||
-rw-r--r-- | src/BlockArea.cpp | 4 | ||||
-rw-r--r-- | src/BlockEntities/BeaconEntity.cpp | 5 | ||||
-rw-r--r-- | src/BlockEntities/ChestEntity.cpp | 26 | ||||
-rw-r--r-- | src/BlockEntities/EnderChestEntity.cpp | 10 | ||||
-rw-r--r-- | src/BlockEntities/MobSpawnerEntity.cpp | 4 | ||||
-rw-r--r-- | src/BlockInServerPluginInterface.h | 3 | ||||
-rw-r--r-- | src/BlockInfo.h | 5 | ||||
-rw-r--r-- | src/Blocks/BlockBed.h | 2 | ||||
-rw-r--r-- | src/Blocks/BlockButton.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockLever.h | 2 | ||||
-rw-r--r-- | src/Blocks/BlockVine.h | 2 | ||||
-rw-r--r-- | src/Blocks/WorldInterface.h | 10 | ||||
-rw-r--r-- | src/BoundingBox.cpp | 20 | ||||
-rw-r--r-- | src/BoundingBox.h | 24 | ||||
-rw-r--r-- | src/Chunk.cpp | 156 | ||||
-rw-r--r-- | src/Chunk.h | 15 | ||||
-rw-r--r-- | src/ChunkDef.h | 67 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 45 | ||||
-rw-r--r-- | src/ChunkMap.h | 26 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 29 | ||||
-rw-r--r-- | src/ClientHandle.h | 5 | ||||
-rw-r--r-- | src/Cuboid.cpp | 40 | ||||
-rw-r--r-- | src/Cuboid.h | 42 | ||||
-rw-r--r-- | src/Entities/ArrowEntity.cpp | 18 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 51 | ||||
-rw-r--r-- | src/Entities/Entity.h | 4 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 20 | ||||
-rw-r--r-- | src/Entities/Player.h | 2 | ||||
-rw-r--r-- | src/Entities/ProjectileEntity.cpp | 22 | ||||
-rw-r--r-- | src/Entities/ProjectileEntity.h | 2 | ||||
-rw-r--r-- | src/Entities/SplashPotionEntity.h | 4 | ||||
-rw-r--r-- | src/Generating/ChunkDesc.cpp | 1 | ||||
-rw-r--r-- | src/Generating/ChunkDesc.h | 2 | ||||
-rw-r--r-- | src/Generating/FinishGen.cpp | 4 | ||||
-rw-r--r-- | src/Generating/Prefab.cpp | 4 | ||||
-rw-r--r-- | src/Generating/VillageGen.cpp | 5 | ||||
-rw-r--r-- | src/Item.cpp | 13 | ||||
-rw-r--r-- | src/Item.h | 20 | ||||
-rw-r--r-- | src/Items/ItemBoat.h | 5 | ||||
-rw-r--r-- | src/Items/ItemBow.h | 11 | ||||
-rw-r--r-- | src/Items/ItemFishingRod.h | 9 | ||||
-rw-r--r-- | src/Items/ItemHandler.h | 2 | ||||
-rw-r--r-- | src/Items/ItemItemFrame.h | 7 | ||||
-rw-r--r-- | src/Items/ItemMinecart.h | 19 | ||||
-rw-r--r-- | src/Items/ItemPainting.h | 7 | ||||
-rw-r--r-- | src/MobSpawner.cpp | 13 | ||||
-rw-r--r-- | src/MobSpawner.h | 10 | ||||
-rw-r--r-- | src/Mobs/Blaze.cpp | 14 | ||||
-rw-r--r-- | src/Mobs/Ghast.cpp | 13 | ||||
-rw-r--r-- | src/Mobs/Monster.cpp | 83 | ||||
-rw-r--r-- | src/Mobs/Monster.h | 16 | ||||
-rw-r--r-- | src/Mobs/Ocelot.cpp | 28 | ||||
-rw-r--r-- | src/Mobs/Ocelot.h | 3 | ||||
-rw-r--r-- | src/Mobs/Skeleton.cpp | 14 | ||||
-rw-r--r-- | src/Mobs/Slime.cpp | 4 | ||||
-rw-r--r-- | src/Mobs/Wither.cpp | 13 | ||||
-rw-r--r-- | src/Mobs/Wither.h | 1 | ||||
-rw-r--r-- | src/Mobs/Wolf.h | 2 | ||||
-rw-r--r-- | src/Protocol/Packetizer.h | 5 | ||||
-rw-r--r-- | src/Protocol/Protocol.h | 2 | ||||
-rw-r--r-- | src/Protocol/ProtocolRecognizer.cpp | 6 | ||||
-rw-r--r-- | src/Protocol/ProtocolRecognizer.h | 7 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_12.cpp | 759 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_12.h | 59 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_8.cpp | 16 | ||||
-rw-r--r-- | src/Protocol/Protocol_1_9.cpp | 17 | ||||
-rw-r--r-- | src/SetChunkData.cpp | 1 | ||||
-rw-r--r-- | src/SetChunkData.h | 8 | ||||
-rw-r--r-- | src/Simulator/DelayedFluidSimulator.cpp | 12 | ||||
-rw-r--r-- | src/Simulator/DelayedFluidSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/FireSimulator.cpp | 14 | ||||
-rw-r--r-- | src/Simulator/FireSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/FloodyFluidSimulator.cpp | 2 | ||||
-rw-r--r-- | src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h | 4 | ||||
-rw-r--r-- | src/Simulator/NoopFluidSimulator.h | 6 | ||||
-rw-r--r-- | src/Simulator/NoopRedstoneSimulator.h | 6 | ||||
-rw-r--r-- | src/Simulator/RedstoneSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/SandSimulator.cpp | 20 | ||||
-rw-r--r-- | src/Simulator/SandSimulator.h | 2 | ||||
-rw-r--r-- | src/Simulator/Simulator.cpp | 31 | ||||
-rw-r--r-- | src/Simulator/Simulator.h | 4 | ||||
-rw-r--r-- | src/Simulator/SimulatorManager.cpp | 4 | ||||
-rw-r--r-- | src/Simulator/SimulatorManager.h | 2 | ||||
-rw-r--r-- | src/Simulator/VaporizeFluidSimulator.cpp | 16 | ||||
-rw-r--r-- | src/Simulator/VaporizeFluidSimulator.h | 2 | ||||
-rw-r--r-- | src/StringUtils.cpp | 36 | ||||
-rw-r--r-- | src/StringUtils.h | 3 | ||||
-rw-r--r-- | src/UI/ChestWindow.cpp | 8 | ||||
-rw-r--r-- | src/UI/SlotArea.h | 3 | ||||
-rw-r--r-- | src/UI/Window.h | 2 | ||||
-rw-r--r-- | src/World.cpp | 272 | ||||
-rw-r--r-- | src/World.h | 45 | ||||
-rw-r--r-- | src/WorldStorage/NBTChunkSerializer.cpp | 15 | ||||
-rwxr-xr-x | src/WorldStorage/WSSAnvil.cpp | 118 | ||||
-rwxr-xr-x | src/WorldStorage/WSSAnvil.h | 3 |
202 files changed, 2241 insertions, 860 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4cd96afdd..ad10f1e69 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,6 +21,12 @@ Here are the conventions: - `ThisIsAProperFunction()` `This_is_bad()` `this_is_bad()` `GoodVariableName` `badVariableName`. * All member variables start with `m_`, all function parameters start with `a_`, all class names start with `c`. - `class cMonster { int m_Health; int DecreaseHealth(int a_Amount); }` + * Function parameters that are coordinates should be passed using an appropriate storage container, and not as three separate arguments. + - e.g. for a block position, Vector3i. For an entity position, Vector3d. For a chunk coordinate, cChunkCoords. + - For a 3-dimensional box of blocks, use cCuboid. For an axis-aligned bounding box, use cBoundingBox. + * Parameters smaller than 4 elements (e.g. Vector3, cChunkCoords) should be passed by value. All other parameters should be passed by const reference, where applicable. + - `Foo(Vector3d a_Param1, const cCuboid & a_Param2)` + - See the discussion in issue #3853 * Put spaces after commas. `Vector3d(1, 2, 3)` instead of `Vector3d(1,2,3)` * Put spaces before and after every operator. - `a = b + c;` diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 84af3215a..2b3c877d9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -55,6 +55,7 @@ tonibm19 UltraCoderRU Warmist WebFreak001 +williamhatcher (Helped with API documentation updates and bug fixes) worktycho xoft (Mattes Dolak/madmaxoft on GH) Yeeeeezus (Donated AlchemistVillage prefabs) @@ -1,11 +1,12 @@ -Cuberite [![Build Status](https://img.shields.io/travis/cuberite/cuberite/master.svg?style=flat)](https://travis-ci.org/cuberite/cuberite) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/1930.svg)](https://scan.coverity.com/projects/1930) +Cuberite [![Build Status](https://img.shields.io/travis/cuberite/cuberite/master.svg?style=flat)](https://travis-ci.org/cuberite/cuberite) [![Circle CI Build Status](https://circleci.com/gh/cuberite/cuberite.svg?&style=shield +)](https://circleci.com/gh/cuberite/cuberite) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/cuberite/cuberite?svg=true)](https://ci.appveyor.com/project/madmaxoft/mcserver) ======== Cuberite is a Minecraft-compatible multiplayer game server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API. Cuberite is compatible with the vanilla Minecraft client. Cuberite can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis. -We currently support Release 1.8 - 1.12 Minecraft protocol versions. +We currently support Release 1.8 - 1.12.1 Minecraft protocol versions. Subscribe to [the newsletter](https://cuberite.org/news/#subscribe) for important updates and project news. @@ -15,18 +16,21 @@ Installation There are several ways to obtain Cuberite. #### Binaries - - The easiest method is downloading for Windows or Linux from the [Project site](https://cuberite.org/). - - You can use the EasyInstall script for Linux and macOS, which automatically downloads the correct binary. The script is described below. - - You can also obtain a binary from the [buildserver archive](https://builds.cuberite.org/). + +- The easiest method is downloading for Windows or Linux from the [Project site](https://cuberite.org/). +- You can use the EasyInstall script for Linux and macOS, which automatically downloads the correct binary. The script is described below. +- You can also obtain a binary from the [buildserver archive](https://builds.cuberite.org/). ##### The EasyInstall script + This script will download the correct binary from the project site. curl -sSfL https://download.cuberite.org | sh #### Compiling - - You can compile automatically for Linux / *nix with the `compile.sh` script. The script is described below. - - You can also compile manually. See [COMPILING.md](https://github.com/cuberite/cuberite/blob/master/COMPILING.md). + +- You can compile automatically for Linux / *nix with the `compile.sh` script. The script is described below. +- You can also compile manually. See [COMPILING.md](https://github.com/cuberite/cuberite/blob/master/COMPILING.md). Compiling may provide better performance (1.5-3x as fast) and it supports more operating systems. @@ -36,7 +40,8 @@ This script downloads the source code and compiles it. The script is smart enoug sh -c "$(wget -O - https://compile.cuberite.org)" #### Hosted services - - Hosted Cuberite is available via [Gamocosm](https://gamocosm.com/). + +- Hosted Cuberite is available via [Gamocosm](https://gamocosm.com/). Contributing ------------ diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua index 9e920d429..ce6277533 100644 --- a/Server/Plugins/APIDump/APIDesc.lua +++ b/Server/Plugins/APIDump/APIDesc.lua @@ -202,7 +202,7 @@ return Type = "string", }, }, - Notes = "Returns the name of the sound that is played when placing the block of this type.", + Notes = "(<b>DEPRECATED</b>) Not used by cuberite internally and always returns an empty string.", }, GetSpreadLightFalloff = { @@ -378,16 +378,6 @@ return Type = "bool", Notes = "Can a piston break this block?", }, - m_PlaceSound = - { - Type = "string", - Notes = "The name of the sound that is placed when a block is placed.", - }, - m_RequiresSpecialTool = - { - Type = "bool", - Notes = "Does this block require a tool to drop?", - }, m_SpreadLightFalloff = { Type = "number", @@ -6703,7 +6693,7 @@ These ItemGrids are available in the API and can be manipulated by the plugins, }, { Name = "Lore", - Type = "string", + Type = "table", IsOptional = true, }, }, @@ -6957,10 +6947,10 @@ These ItemGrids are available in the API and can be manipulated by the plugins, Type = "number", Notes = "The item type. One of E_ITEM_ or E_BLOCK_ constants", }, - m_Lore = + m_LoreTable = { - Type = "string", - Notes = "The lore for an item. Line breaks are represented by the ` character.", + Type = "table", + Notes = "The lore for an item. Represented as an array table of lines.", }, m_RepairCost = { @@ -8039,6 +8029,17 @@ This class is used by plugins wishing to display a custom window to the player, }, Notes = "Returns the cItemGrid object representing the internal storage in this window", }, + SetOnClicked = + { + Params = + { + { + Name = "OnClickedCallback", + Type = "function", + }, + }, + Notes = "Sets the function that the window will call when it is about to process a click from a player. See {{#additionalinfo_1|below}} for the signature of the callback function.", + }, SetOnClosing = { Params = @@ -8071,6 +8072,17 @@ This class is used by plugins wishing to display a custom window to the player, ]], }, { + Header = "OnClicked Callback", + Contents = [[ + This callback, settable via the SetOnClicked() function, will be called when the player clicks a slot in the window. The callback can cancel the click.</p> +<pre class="prettyprint lang-lua"> +function OnWindowClicked(a_Window, a_Player, a_SlotNum, a_ClickAction, a_ClickedItem) +</pre> + <p> + The a_Window parameter is the cLuaWindow object representing the window, a_Player is the player who made the click, a_SlotNum is the slot the player clicked, a_ClickAction is the type of click the player made, and a_ClickedItem is the item the player clicked on, if applicable. If the function returns true, the click is cancelled (internally, the server resends the window slots to the player to keep the player in sync). + ]], + }, + { Header = "OnClosing Callback", Contents = [[ This callback, settable via the SetOnClosing() function, will be called when the player tries to close the window, or the window is closed for any other reason (such as a player disconnecting).</p> @@ -8096,7 +8108,7 @@ function OnWindowSlotChanged(a_Window, a_SlotNum) { Header = "Example", Contents = [[ - This example is taken from the Debuggers plugin, used to test the API functionality. It opens a window and refuse to close it 3 times. It also logs slot changes to the server console. + This example is taken from the Debuggers plugin, used to test the API functionality. It opens a window and refuse to close it 3 times. It also logs slot changes to the server console and prevents shift-clicking in the window. <pre class="prettyprint lang-lua"> -- Callback that refuses to close the window twice, then allows: local Attempt = 1; @@ -8111,10 +8123,18 @@ local OnSlotChanged = function(Window, SlotNum) LOG("Window \"" .. Window:GetWindowTitle() .. "\" slot " .. SlotNum .. " changed."); end +-- Prevent shift-clicking: +local OnClicked = function(Window, ClickingPlayer, SlotNum, ClickAction, ClickedItem) + if ClickAction == caShiftLeftClick then + return true + end +end + -- Set window contents: -- a_Player is a cPlayer object received from the outside of this code fragment local Window = cLuaWindow(cWindow.wtHopper, 3, 3, "TestWnd"); Window:SetSlot(a_Player, 0, cItem(E_ITEM_DIAMOND, 64)); +Window:SetOnClicked(OnClicked); Window:SetOnClosing(OnClosing); Window:SetOnSlotChanged(OnSlotChanged); diff --git a/Server/Plugins/APIDump/Classes/Plugins.lua b/Server/Plugins/APIDump/Classes/Plugins.lua index c00735412..e22f4e3a0 100644 --- a/Server/Plugins/APIDump/Classes/Plugins.lua +++ b/Server/Plugins/APIDump/Classes/Plugins.lua @@ -840,6 +840,10 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); { Notes = "Called when the player has moved and the movement is now being applied.", }, + HOOK_PLAYER_OPENING_WINDOW = + { + Notes = "Called when the player is about to open a window. The plugin can return true to cancel the window opening.", + }, HOOK_PLAYER_PLACED_BLOCK = { Notes = "Called when the player has just placed a block", diff --git a/Server/Plugins/APIDump/Classes/World.lua b/Server/Plugins/APIDump/Classes/World.lua index e452db2ff..62d71828f 100644 --- a/Server/Plugins/APIDump/Classes/World.lua +++ b/Server/Plugins/APIDump/Classes/World.lua @@ -3353,53 +3353,77 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i }, WakeUpSimulators = { - Params = { + Params = { - Name = "BlockX", - Type = "number", - }, - { - Name = "BlockY", - Type = "number", + { + Name = "Block", + Type = "Vector3i", + }, }, + Notes = "Wakes up the simulators for the specified block.", + }, + { + Params = { - Name = "BlockZ", - Type = "number", + { + Name = "BlockX", + Type = "number", + }, + { + Name = "BlockY", + Type = "number", + }, + { + Name = "BlockZ", + Type = "number", + }, }, + Notes = "Wakes up the simulators for the specified block. (DEPRECATED, use vector-parametered version)", }, - Notes = "Wakes up the simulators for the specified block.", }, WakeUpSimulatorsInArea = { - Params = { + Params = { - Name = "MinBlockX", - Type = "number", - }, - { - Name = "MaxBlockX", - Type = "number", - }, - { - Name = "MinBlockY", - Type = "number", - }, - { - Name = "MaxBlockY", - Type = "number", - }, - { - Name = "MinBlockZ", - Type = "number", + { + Name = "Area", + Type = "cCuboid", + }, }, + Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive).", + }, + { + Params = { - Name = "MaxBlockZ", - Type = "number", + { + Name = "MinBlockX", + Type = "number", + }, + { + Name = "MaxBlockX", + Type = "number", + }, + { + Name = "MinBlockY", + Type = "number", + }, + { + Name = "MaxBlockY", + Type = "number", + }, + { + Name = "MinBlockZ", + Type = "number", + }, + { + Name = "MaxBlockZ", + Type = "number", + }, }, + Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive). (DEPRECATED, use vector-parametered version)", }, - Notes = "Wakes up the simulators for all the blocks in the specified area (edges inclusive).", }, }, AdditionalInfo = diff --git a/Server/Plugins/APIDump/Hooks/OnPlayerOpeningWindow.lua b/Server/Plugins/APIDump/Hooks/OnPlayerOpeningWindow.lua new file mode 100644 index 000000000..04563df89 --- /dev/null +++ b/Server/Plugins/APIDump/Hooks/OnPlayerOpeningWindow.lua @@ -0,0 +1,20 @@ +return +{ + HOOK_PLAYER_OPENING_WINDOW = + { + CalledWhen = "Called when a player is about to open a window", + DefaultFnName = "OnPlayerOpeningWindow", -- also used as pagename + Desc = [[ + This hook is called when a player is about to open a window, e.g. when they click on a chest or a furnace. + ]], + Params = + { + { Name = "Player", Type = "{{cPlayer}}", Notes = "The player who is opening the window" }, + { Name = "Window", Type = "{{cWindow}}", Notes = "The window that is being opened" }, + }, + Returns = [[ + If the function returns false or no value, the next plugin's callback is called, and finally + Cuberite will process the opening window. If the function returns true, no other callback is called for this event. + ]], + }, -- HOOK_PLAYER_OPENING_WINDOW +} diff --git a/Server/Plugins/APIDump/InfoFile.html b/Server/Plugins/APIDump/InfoFile.html index e293931f2..4b35a41be 100644 --- a/Server/Plugins/APIDump/InfoFile.html +++ b/Server/Plugins/APIDump/InfoFile.html @@ -20,6 +20,7 @@ <li><a href="#Commands">Commands table</a></li> <li><a href="#ConsoleCommands">ConsoleCommands table</a></li> <li><a href="#Permissions">Permissions table</a></li> + <li><a href="#Categories">Categories table</a></li> <li><a href="#Using">Using the file in code</a></li> <li><a href="#Examples">Examples</a></li> </ul> @@ -34,7 +35,10 @@ <p>Last, but not least, we want to make a plugin repository on the web in the future, a repository that would store plugins, their descriptions, comments. It makes sense that the centralized information can be parsed by the repository automatically, so that advanced things, such as searching for a plugin based on a command, or determining whether two plugins collide command-wise, are possible.</p> - <p>After this file format has been devised, a tool has been written that allows for an easy generation of the documentation for the plugin in various formats. It outputs the documentation in a format that is perfect for pasting into the forum. It generates documentation in a Markup format to use in README.md on GitHub and similar sites. The clever thing is that you don't need to keep all those formats in sync manually - you edit the Info.lua file and this tool will re-generate the documentation for you.</p> + <p>A tool has been written that allows for an easy generation of the documentation for the plugin in various formats. It outputs the documentation in a format that is perfect for pasting into the forum. It generates documentation in a Markup format to use in README.md on GitHub and similar sites. The clever thing is that you don't need to keep all those formats in sync manually - you edit the Info.lua file and this tool will re-generate the documentation for you. + <br> + To generate documentation for the plugin, activate the DumpInfo plugin on a cuberite server with your plugin installed, and use the webadmin interface to "Dump" the plugin information. This will create a README.md suitable for uploading to your git repo, and a forum_info.txt, which can be copy-pasted into a forum post. + </p> <p>So to sum up, the Info.lua file contains the plugins' commands, console commands, their permissions and possibly the overall plugin documentation, in a structured manner that can be parsed by a program, yet is human readable and editable.</p> @@ -56,6 +60,7 @@ g_PluginInfo = Commands = {}, ConsoleCommands = {}, Permissions = {}, + Categories = {}, } </pre> <p>As you can see, the structure is pretty straightforward. Note that the order of the elements inside the table is not important (Lua property).</p> @@ -115,6 +120,7 @@ Commands = ["/cmd2"] = { Alias = {"/c2", "//c2" }, + Category = "Something", Subcommands = { sub1 = -- This declares a "/cmd2 sub1" command @@ -150,6 +156,8 @@ Commands = <p>The permission element specifies that the command is only available with the specified permission. Note that the permission for subcommand's parent isn't checked when the subcommand is called. This means that specifying the permission for a command that has subcommands has no effect whatsoever, but is discouraged because we may add processing for that in the future.</p> + <p>The optional Categories table provides descriptions for command categories in the generated documentation. The documentation generator will group the commands by their specified Category ("General" by default) and each category will have the specified description written to it.</p> + <p>The ParameterCombinations table is used only for generating the documentation, it lists the various combinations of parameters that the command supports. It's worth specifying even if the command supports only one combination, because that combination will get documented this way.</p> <p>The Alias member specifies any possible aliases for the command. Each alias is registered separately and if there is a subcommand table, it is applied to all aliases, just as one would expect. You can specify either a single string as the value (if there's only one alias), or a table of strings for multiple aliases. Commands with no aliases do not need to specify this member at all.</p> @@ -217,6 +225,24 @@ Permissions = <hr /> + <a name="Categories"><h2>Categories</h2></a> + + <p>The optional Categories table provides descriptions for categories in the generated documentation. Commands can have categories with or without category descriptions in this table. The documentation generator will output a table of listed categories along with their description.</p> +<pre class="prettyprint lang-lua"> +Categories = +{ + General = + { + Description = "A general, yet somehow vague description of the default category." + }, + Something = + { + Description = "Some descriptive words which form sentences pertaining to this set of commands use and goals." + }, +}, +</pre> + + <hr /> <a name="Using"><h2>Using the file in code</h2></a> <p>Just writing the Info.lua file and saving it to the plugin folder is not enough for it to actually be used. Your plugin needs to include the following boilerplate code, preferably in its Initialize() function:</p> diff --git a/Server/Plugins/APIDump/main_APIDump.lua b/Server/Plugins/APIDump/main_APIDump.lua index 0f1476ef7..fd243b25f 100644 --- a/Server/Plugins/APIDump/main_APIDump.lua +++ b/Server/Plugins/APIDump/main_APIDump.lua @@ -168,7 +168,7 @@ end --- Returns the timestamp in HTML format -- The timestamp will be inserted to all generated HTML files local function GetHtmlTimestamp() - return string.format("<div id='timestamp'>Generated on %s, Build ID %s, Commit %s</div>", + return string.format("<div id='timestamp'>Generated by <a href='https://github.com/cuberite/cuberite/tree/master/Server/Plugins/APIDump'>APIDump</a> on %s, Build ID %s, Commit %s</div>", os.date("%Y-%m-%d %H:%M:%S"), cRoot:GetBuildID(), cRoot:GetBuildCommitID() ) diff --git a/Server/Plugins/InfoDump.lua b/Server/Plugins/InfoDump.lua index 4dde35978..494ddd85f 100644 --- a/Server/Plugins/InfoDump.lua +++ b/Server/Plugins/InfoDump.lua @@ -306,7 +306,7 @@ local function WriteCommandsCategoryForum(a_Category, f) if (CategoryName == "") then CategoryName = "General" end - f:write("\n[size=Large]", ForumizeString(a_Category.DisplayName or CategoryName), "[/size]\n") + f:write("\n[size=large]", ForumizeString(a_Category.DisplayName or CategoryName), "[/size]\n") -- Write description: if (a_Category.Description ~= "") then @@ -377,7 +377,7 @@ local function DumpCommandsForum(a_PluginInfo, f) return end - f:write("\n[size=X-Large]Commands[/size]\n") + f:write("\n[size=x-large]Commands[/size]\n") -- Dump per-category commands: for idx, cat in ipairs(Categories) do @@ -425,7 +425,7 @@ local function DumpAdditionalInfoForum(a_PluginInfo, f) for idx, info in ipairs(a_PluginInfo.AdditionalInfo) do if ((info.Title ~= nil) and (info.Contents ~= nil)) then - f:write("\n[size=X-Large]", ForumizeString(info.Title), "[/size]\n") + f:write("\n[size=x-large]", ForumizeString(info.Title), "[/size]\n") f:write(ForumizeString(info.Contents), "\n") end end @@ -530,7 +530,7 @@ local function DumpPermissionsForum(a_PluginInfo, f) end -- Dump the permissions: - f:write("\n[size=X-Large]Permissions[/size]\n[list]\n") + f:write("\n[size=x-large]Permissions[/size]\n[list]\n") for idx, perm in ipairs(Permissions) do f:write(" - [color=red]", perm.Name, "[/color] - ") f:write(ForumizeString(perm.Info.Description or "")) diff --git a/Server/Plugins/TestLuaRocks/TestLuaRocks.lua b/Server/Plugins/TestLuaRocks/TestLuaRocks.lua index a4c2be6f8..44a545032 100644 --- a/Server/Plugins/TestLuaRocks/TestLuaRocks.lua +++ b/Server/Plugins/TestLuaRocks/TestLuaRocks.lua @@ -20,14 +20,14 @@ local http = require("socket.http"); -LOGINFO("Trying to download a webpage..."); -local body, code, headers = http.request('https://forum.cuberite.org/'); -LOG("code: " .. tostring(code)); -LOG("headers: "); +LOGINFO("Trying to download a webpage...") +local body, code, headers = http.request('https://forum.cuberite.org/') +LOG("code: " .. tostring(code)) +LOG("headers: ") for k, v in pairs(headers or {}) do - LOG(" " .. k .. ": " .. v); + LOG(" " .. k .. ": " .. v) end -LOG("body length: " .. string.len(body)); +LOG("body length: " .. string.len(body)) @@ -35,15 +35,15 @@ LOG("body length: " .. string.len(body)); function Initialize(a_Plugin) if (socket == nil) then - LOG("LuaSocket not found"); + LOGWARNING("LuaSocket not found") else - LOG("LuaSocket loaded"); + LOG("LuaSocket loaded") end if (log30 == nil) then - LOG("30log not found"); + LOGWARNING("30log not found") else - LOG("30log loaded"); + LOG("30log loaded") end - LOGINFO("Preventing plugin load so that it may be requested again from the webadmin."); - return false; + LOGINFO("Reload plugin from console or webadmin to rerun tests.") + return false end diff --git a/SetFlags.cmake b/SetFlags.cmake index 18d5be236..e0eb05ef1 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -108,7 +108,10 @@ macro(set_flags) endif() if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm") + # mbed TLS uses the frame pointer's register in inline assembly: + # https://tls.mbed.org/kb/development/arm-thumb-error-r7-cannot-be-used-in-asm-here set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fomit-frame-pointer") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fomit-frame-pointer") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") diff --git a/docs/.gitignore b/dev-docs/.gitignore index f6caf1c11..f6caf1c11 100644 --- a/docs/.gitignore +++ b/dev-docs/.gitignore diff --git a/docs/API class inheritance - blockentities.gv b/dev-docs/API class inheritance - blockentities.gv index 966588c5f..966588c5f 100644 --- a/docs/API class inheritance - blockentities.gv +++ b/dev-docs/API class inheritance - blockentities.gv diff --git a/docs/API class inheritance - entities.gv b/dev-docs/API class inheritance - entities.gv index 4e167e1d3..4e167e1d3 100644 --- a/docs/API class inheritance - entities.gv +++ b/dev-docs/API class inheritance - entities.gv diff --git a/docs/Cubeset file format.html b/dev-docs/Cubeset file format.html index 6ead2e700..6ead2e700 100644 --- a/docs/Cubeset file format.html +++ b/dev-docs/Cubeset file format.html diff --git a/docs/Generator.html b/dev-docs/Generator.html index 4d17826c1..4d17826c1 100644 --- a/docs/Generator.html +++ b/dev-docs/Generator.html diff --git a/docs/Login sequence.txt b/dev-docs/Login sequence.txt index df9d386c6..df9d386c6 100644 --- a/docs/Login sequence.txt +++ b/dev-docs/Login sequence.txt diff --git a/docs/NBT Examples/single chunk NBT data.txt b/dev-docs/NBT Examples/single chunk NBT data.txt index 905d6465c..905d6465c 100644 --- a/docs/NBT Examples/single chunk NBT data.txt +++ b/dev-docs/NBT Examples/single chunk NBT data.txt diff --git a/docs/NBT Examples/tile entities.txt b/dev-docs/NBT Examples/tile entities.txt index e16ae45a7..e16ae45a7 100644 --- a/docs/NBT Examples/tile entities.txt +++ b/dev-docs/NBT Examples/tile entities.txt diff --git a/docs/Object ownership.gv b/dev-docs/Object ownership.gv index 29e0407a6..29e0407a6 100644 --- a/docs/Object ownership.gv +++ b/dev-docs/Object ownership.gv diff --git a/dev-docs/Plugin API.md b/dev-docs/Plugin API.md new file mode 100644 index 000000000..6a0fd9a0e --- /dev/null +++ b/dev-docs/Plugin API.md @@ -0,0 +1,3 @@ +# Looking for the API documentation for Lua plugins? + +See the [cuberite website](api.cuberite.org) or browse the [source](https://github.com/cuberite/cuberite/tree/master/Server/Plugins/APIDump). diff --git a/docs/SocketThreads states.gv b/dev-docs/SocketThreads states.gv index 5afaa5370..5afaa5370 100644 --- a/docs/SocketThreads states.gv +++ b/dev-docs/SocketThreads states.gv diff --git a/docs/Springs.ods b/dev-docs/Springs.ods Binary files differindex 4b3559f1d..4b3559f1d 100644 --- a/docs/Springs.ods +++ b/dev-docs/Springs.ods diff --git a/docs/_files.txt b/dev-docs/_files.txt index 85a4253c1..85a4253c1 100644 --- a/docs/_files.txt +++ b/dev-docs/_files.txt diff --git a/docs/img/biomalheights.jpg b/dev-docs/img/biomalheights.jpg Binary files differindex a01faef87..a01faef87 100644 --- a/docs/img/biomalheights.jpg +++ b/dev-docs/img/biomalheights.jpg diff --git a/docs/img/biomeheights.jpg b/dev-docs/img/biomeheights.jpg Binary files differindex 9dda27b0e..9dda27b0e 100644 --- a/docs/img/biomeheights.jpg +++ b/dev-docs/img/biomeheights.jpg diff --git a/docs/img/biomeheightsavg.jpg b/dev-docs/img/biomeheightsavg.jpg Binary files differindex c8217cafc..c8217cafc 100644 --- a/docs/img/biomeheightsavg.jpg +++ b/dev-docs/img/biomeheightsavg.jpg diff --git a/docs/img/biomes.jpg b/dev-docs/img/biomes.jpg Binary files differindex 59c23b870..59c23b870 100644 --- a/docs/img/biomes.jpg +++ b/dev-docs/img/biomes.jpg diff --git a/docs/img/densitymap.jpg b/dev-docs/img/densitymap.jpg Binary files differindex a7a7b3f36..a7a7b3f36 100644 --- a/docs/img/densitymap.jpg +++ b/dev-docs/img/densitymap.jpg diff --git a/docs/img/distortedvoronoibiomes.png b/dev-docs/img/distortedvoronoibiomes.png Binary files differindex d56dff347..d56dff347 100644 --- a/docs/img/distortedvoronoibiomes.png +++ b/dev-docs/img/distortedvoronoibiomes.png diff --git a/docs/img/finishers.jpg b/dev-docs/img/finishers.jpg Binary files differindex 06f7485c3..06f7485c3 100644 --- a/docs/img/finishers.jpg +++ b/dev-docs/img/finishers.jpg diff --git a/docs/img/gaussprobability.jpg b/dev-docs/img/gaussprobability.jpg Binary files differindex 77da24748..77da24748 100644 --- a/docs/img/gaussprobability.jpg +++ b/dev-docs/img/gaussprobability.jpg diff --git a/docs/img/grownexample_add_islands.png b/dev-docs/img/grownexample_add_islands.png Binary files differindex f69faaaf1..f69faaaf1 100644 --- a/docs/img/grownexample_add_islands.png +++ b/dev-docs/img/grownexample_add_islands.png diff --git a/docs/img/grownexample_alt_biomes.png b/dev-docs/img/grownexample_alt_biomes.png Binary files differindex 866d774e2..866d774e2 100644 --- a/docs/img/grownexample_alt_biomes.png +++ b/dev-docs/img/grownexample_alt_biomes.png diff --git a/docs/img/grownexample_beaches.png b/dev-docs/img/grownexample_beaches.png Binary files differindex a84fb0eff..a84fb0eff 100644 --- a/docs/img/grownexample_beaches.png +++ b/dev-docs/img/grownexample_beaches.png diff --git a/docs/img/grownexample_biome_edges.png b/dev-docs/img/grownexample_biome_edges.png Binary files differindex 58de63aef..58de63aef 100644 --- a/docs/img/grownexample_biome_edges.png +++ b/dev-docs/img/grownexample_biome_edges.png diff --git a/docs/img/grownexample_biomes.png b/dev-docs/img/grownexample_biomes.png Binary files differindex ecd8af29b..ecd8af29b 100644 --- a/docs/img/grownexample_biomes.png +++ b/dev-docs/img/grownexample_biomes.png diff --git a/docs/img/grownexample_grp_edges.png b/dev-docs/img/grownexample_grp_edges.png Binary files differindex 2ac32b9a6..2ac32b9a6 100644 --- a/docs/img/grownexample_grp_edges.png +++ b/dev-docs/img/grownexample_grp_edges.png diff --git a/docs/img/grownexample_in1.png b/dev-docs/img/grownexample_in1.png Binary files differindex 2238886ab..2238886ab 100644 --- a/docs/img/grownexample_in1.png +++ b/dev-docs/img/grownexample_in1.png diff --git a/docs/img/grownexample_in2.png b/dev-docs/img/grownexample_in2.png Binary files differindex 9ef9f6ae2..9ef9f6ae2 100644 --- a/docs/img/grownexample_in2.png +++ b/dev-docs/img/grownexample_in2.png diff --git a/docs/img/grownexample_in3.png b/dev-docs/img/grownexample_in3.png Binary files differindex 95d6608b5..95d6608b5 100644 --- a/docs/img/grownexample_in3.png +++ b/dev-docs/img/grownexample_in3.png diff --git a/docs/img/grownexample_in_alt.png b/dev-docs/img/grownexample_in_alt.png Binary files differindex 59979ed62..59979ed62 100644 --- a/docs/img/grownexample_in_alt.png +++ b/dev-docs/img/grownexample_in_alt.png diff --git a/docs/img/grownexample_in_river.png b/dev-docs/img/grownexample_in_river.png Binary files differindex 58556369d..58556369d 100644 --- a/docs/img/grownexample_in_river.png +++ b/dev-docs/img/grownexample_in_river.png diff --git a/docs/img/grownexample_m_biomes.png b/dev-docs/img/grownexample_m_biomes.png Binary files differindex c3d7079ae..c3d7079ae 100644 --- a/docs/img/grownexample_m_biomes.png +++ b/dev-docs/img/grownexample_m_biomes.png diff --git a/docs/img/grownexample_mix_river.png b/dev-docs/img/grownexample_mix_river.png Binary files differindex 81899a8c7..81899a8c7 100644 --- a/docs/img/grownexample_mix_river.png +++ b/dev-docs/img/grownexample_mix_river.png diff --git a/docs/img/grownexample_river.png b/dev-docs/img/grownexample_river.png Binary files differindex cb07f44dd..cb07f44dd 100644 --- a/docs/img/grownexample_river.png +++ b/dev-docs/img/grownexample_river.png diff --git a/docs/img/grownexample_set_rnd.png b/dev-docs/img/grownexample_set_rnd.png Binary files differindex 5b7a2d254..5b7a2d254 100644 --- a/docs/img/grownexample_set_rnd.png +++ b/dev-docs/img/grownexample_set_rnd.png diff --git a/docs/img/grownexample_smooth.png b/dev-docs/img/grownexample_smooth.png Binary files differindex bfd43f6ef..bfd43f6ef 100644 --- a/docs/img/grownexample_smooth.png +++ b/dev-docs/img/grownexample_smooth.png diff --git a/docs/img/grownexample_zoom.png b/dev-docs/img/grownexample_zoom.png Binary files differindex 7afffe50b..7afffe50b 100644 --- a/docs/img/grownexample_zoom.png +++ b/dev-docs/img/grownexample_zoom.png diff --git a/docs/img/heightmap.jpg b/dev-docs/img/heightmap.jpg Binary files differindex c7eb5c865..c7eb5c865 100644 --- a/docs/img/heightmap.jpg +++ b/dev-docs/img/heightmap.jpg diff --git a/docs/img/jittergrid.jpg b/dev-docs/img/jittergrid.jpg Binary files differindex f8066aa72..f8066aa72 100644 --- a/docs/img/jittergrid.jpg +++ b/dev-docs/img/jittergrid.jpg diff --git a/docs/img/jittergridlocality.jpg b/dev-docs/img/jittergridlocality.jpg Binary files differindex 64414c878..64414c878 100644 --- a/docs/img/jittergridlocality.jpg +++ b/dev-docs/img/jittergridlocality.jpg diff --git a/docs/img/multistepmapbiomes.png b/dev-docs/img/multistepmapbiomes.png Binary files differindex d32ac3d8e..d32ac3d8e 100644 --- a/docs/img/multistepmapbiomes.png +++ b/dev-docs/img/multistepmapbiomes.png diff --git a/docs/img/multistepmapdistance.jpg b/dev-docs/img/multistepmapdistance.jpg Binary files differindex 9f7cfd11b..9f7cfd11b 100644 --- a/docs/img/multistepmapdistance.jpg +++ b/dev-docs/img/multistepmapdistance.jpg diff --git a/docs/img/multistepmapgrid.jpg b/dev-docs/img/multistepmapgrid.jpg Binary files differindex 51dd81c46..51dd81c46 100644 --- a/docs/img/multistepmapgrid.jpg +++ b/dev-docs/img/multistepmapgrid.jpg diff --git a/docs/img/perlin.jpg b/dev-docs/img/perlin.jpg Binary files differindex 499fcdeae..499fcdeae 100644 --- a/docs/img/perlin.jpg +++ b/dev-docs/img/perlin.jpg diff --git a/docs/img/perlincompositor1.jpg b/dev-docs/img/perlincompositor1.jpg Binary files differindex 0d8f93cd9..0d8f93cd9 100644 --- a/docs/img/perlincompositor1.jpg +++ b/dev-docs/img/perlincompositor1.jpg diff --git a/docs/img/perlincompositor2.jpg b/dev-docs/img/perlincompositor2.jpg Binary files differindex 11fc5b51d..11fc5b51d 100644 --- a/docs/img/perlincompositor2.jpg +++ b/dev-docs/img/perlincompositor2.jpg diff --git a/docs/img/perlincompositor3.jpg b/dev-docs/img/perlincompositor3.jpg Binary files differindex 46a2583ba..46a2583ba 100644 --- a/docs/img/perlincompositor3.jpg +++ b/dev-docs/img/perlincompositor3.jpg diff --git a/docs/img/perlinheightmap.jpg b/dev-docs/img/perlinheightmap.jpg Binary files differindex d941a2fc6..d941a2fc6 100644 --- a/docs/img/perlinheightmap.jpg +++ b/dev-docs/img/perlinheightmap.jpg diff --git a/docs/img/perlinrivers1.jpg b/dev-docs/img/perlinrivers1.jpg Binary files differindex b11373fa7..b11373fa7 100644 --- a/docs/img/perlinrivers1.jpg +++ b/dev-docs/img/perlinrivers1.jpg diff --git a/docs/img/perlinrivers2.jpg b/dev-docs/img/perlinrivers2.jpg Binary files differindex bbbcaa276..bbbcaa276 100644 --- a/docs/img/perlinrivers2.jpg +++ b/dev-docs/img/perlinrivers2.jpg diff --git a/docs/img/perlinrivers3.jpg b/dev-docs/img/perlinrivers3.jpg Binary files differindex 3cf043e6e..3cf043e6e 100644 --- a/docs/img/perlinrivers3.jpg +++ b/dev-docs/img/perlinrivers3.jpg diff --git a/docs/img/roofprobability.jpg b/dev-docs/img/roofprobability.jpg Binary files differindex e7a155113..e7a155113 100644 --- a/docs/img/roofprobability.jpg +++ b/dev-docs/img/roofprobability.jpg diff --git a/docs/img/smallfoliageclumps.jpg b/dev-docs/img/smallfoliageclumps.jpg Binary files differindex 4cc6cbc00..4cc6cbc00 100644 --- a/docs/img/smallfoliageclumps.jpg +++ b/dev-docs/img/smallfoliageclumps.jpg diff --git a/docs/img/smoothedgrown_1.png b/dev-docs/img/smoothedgrown_1.png Binary files differindex 16e563f96..16e563f96 100644 --- a/docs/img/smoothedgrown_1.png +++ b/dev-docs/img/smoothedgrown_1.png diff --git a/docs/img/smoothedgrown_2.png b/dev-docs/img/smoothedgrown_2.png Binary files differindex 2d97cfb4e..2d97cfb4e 100644 --- a/docs/img/smoothedgrown_2.png +++ b/dev-docs/img/smoothedgrown_2.png diff --git a/docs/img/smoothedgrown_3.png b/dev-docs/img/smoothedgrown_3.png Binary files differindex 2d4d13f49..2d4d13f49 100644 --- a/docs/img/smoothedgrown_3.png +++ b/dev-docs/img/smoothedgrown_3.png diff --git a/docs/img/smoothedgrown_4.png b/dev-docs/img/smoothedgrown_4.png Binary files differindex d52a34bfe..d52a34bfe 100644 --- a/docs/img/smoothedgrown_4.png +++ b/dev-docs/img/smoothedgrown_4.png diff --git a/docs/img/smoothedgrown_5.png b/dev-docs/img/smoothedgrown_5.png Binary files differindex ae14d9847..ae14d9847 100644 --- a/docs/img/smoothedgrown_5.png +++ b/dev-docs/img/smoothedgrown_5.png diff --git a/docs/img/smoothedgrown_6.png b/dev-docs/img/smoothedgrown_6.png Binary files differindex 0a7f17595..0a7f17595 100644 --- a/docs/img/smoothedgrown_6.png +++ b/dev-docs/img/smoothedgrown_6.png diff --git a/docs/img/smoothedgrown_7.png b/dev-docs/img/smoothedgrown_7.png Binary files differindex 4351d6881..4351d6881 100644 --- a/docs/img/smoothedgrown_7.png +++ b/dev-docs/img/smoothedgrown_7.png diff --git a/docs/img/temperaturehumiditydecisionhills.jpg b/dev-docs/img/temperaturehumiditydecisionhills.jpg Binary files differindex c755df158..c755df158 100644 --- a/docs/img/temperaturehumiditydecisionhills.jpg +++ b/dev-docs/img/temperaturehumiditydecisionhills.jpg diff --git a/docs/img/temperaturehumiditydecisionsimple.jpg b/dev-docs/img/temperaturehumiditydecisionsimple.jpg Binary files differindex cbb1271b5..cbb1271b5 100644 --- a/docs/img/temperaturehumiditydecisionsimple.jpg +++ b/dev-docs/img/temperaturehumiditydecisionsimple.jpg diff --git a/docs/img/terraincomposition.jpg b/dev-docs/img/terraincomposition.jpg Binary files differindex 3d03e101d..3d03e101d 100644 --- a/docs/img/terraincomposition.jpg +++ b/dev-docs/img/terraincomposition.jpg diff --git a/docs/img/terrainheight.jpg b/dev-docs/img/terrainheight.jpg Binary files differindex bcbafcfaf..bcbafcfaf 100644 --- a/docs/img/terrainheight.jpg +++ b/dev-docs/img/terrainheight.jpg diff --git a/docs/img/twolevelbiomes.png b/dev-docs/img/twolevelbiomes.png Binary files differindex a3104733f..a3104733f 100644 --- a/docs/img/twolevelbiomes.png +++ b/dev-docs/img/twolevelbiomes.png diff --git a/docs/img/twolevellargeareas.jpg b/dev-docs/img/twolevellargeareas.jpg Binary files differindex 9d5d5ac8a..9d5d5ac8a 100644 --- a/docs/img/twolevellargeareas.jpg +++ b/dev-docs/img/twolevellargeareas.jpg diff --git a/docs/img/twolevelsmallareas.jpg b/dev-docs/img/twolevelsmallareas.jpg Binary files differindex 14afbc42a..14afbc42a 100644 --- a/docs/img/twolevelsmallareas.jpg +++ b/dev-docs/img/twolevelsmallareas.jpg diff --git a/docs/img/twolevelsmallgrid.jpg b/dev-docs/img/twolevelsmallgrid.jpg Binary files differindex 6c75e0b28..6c75e0b28 100644 --- a/docs/img/twolevelsmallgrid.jpg +++ b/dev-docs/img/twolevelsmallgrid.jpg diff --git a/docs/img/vanilla_springs_huge.png b/dev-docs/img/vanilla_springs_huge.png Binary files differindex 694389c85..694389c85 100644 --- a/docs/img/vanilla_springs_huge.png +++ b/dev-docs/img/vanilla_springs_huge.png diff --git a/docs/img/voronoi.png b/dev-docs/img/voronoi.png Binary files differindex e61e183ef..e61e183ef 100644 --- a/docs/img/voronoi.png +++ b/dev-docs/img/voronoi.png diff --git a/docs/img/voronoijitterbiomes.png b/dev-docs/img/voronoijitterbiomes.png Binary files differindex 42f0b7e40..42f0b7e40 100644 --- a/docs/img/voronoijitterbiomes.png +++ b/dev-docs/img/voronoijitterbiomes.png diff --git a/docs/img/zoomedgrown_1.png b/dev-docs/img/zoomedgrown_1.png Binary files differindex c73326b0e..c73326b0e 100644 --- a/docs/img/zoomedgrown_1.png +++ b/dev-docs/img/zoomedgrown_1.png diff --git a/docs/img/zoomedgrown_2.png b/dev-docs/img/zoomedgrown_2.png Binary files differindex 45fa6427f..45fa6427f 100644 --- a/docs/img/zoomedgrown_2.png +++ b/dev-docs/img/zoomedgrown_2.png diff --git a/docs/img/zoomedgrown_3.png b/dev-docs/img/zoomedgrown_3.png Binary files differindex 3c9d89759..3c9d89759 100644 --- a/docs/img/zoomedgrown_3.png +++ b/dev-docs/img/zoomedgrown_3.png diff --git a/docs/img/zoomedgrown_4.png b/dev-docs/img/zoomedgrown_4.png Binary files differindex 221a5fc76..221a5fc76 100644 --- a/docs/img/zoomedgrown_4.png +++ b/dev-docs/img/zoomedgrown_4.png diff --git a/docs/img/zoomedgrown_5.png b/dev-docs/img/zoomedgrown_5.png Binary files differindex 3881532ca..3881532ca 100644 --- a/docs/img/zoomedgrown_5.png +++ b/dev-docs/img/zoomedgrown_5.png diff --git a/docs/img/zoomedgrown_6.png b/dev-docs/img/zoomedgrown_6.png Binary files differindex cc03d2150..cc03d2150 100644 --- a/docs/img/zoomedgrown_6.png +++ b/dev-docs/img/zoomedgrown_6.png diff --git a/docs/img/zoomedgrown_7.png b/dev-docs/img/zoomedgrown_7.png Binary files differindex 7a9f43aac..7a9f43aac 100644 --- a/docs/img/zoomedgrown_7.png +++ b/dev-docs/img/zoomedgrown_7.png diff --git a/docs/js/ValueMap.js b/dev-docs/js/ValueMap.js index 31ddba27e..31ddba27e 100644 --- a/docs/js/ValueMap.js +++ b/dev-docs/js/ValueMap.js diff --git a/docs/js/grown.js b/dev-docs/js/grown.js index 1658ce21c..1658ce21c 100644 --- a/docs/js/grown.js +++ b/dev-docs/js/grown.js diff --git a/docs/style.css b/dev-docs/style.css index 74419d8da..74419d8da 100644 --- a/docs/style.css +++ b/dev-docs/style.css diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp index bb59fca7c..3ae1fd990 100644 --- a/src/Bindings/DeprecatedBindings.cpp +++ b/src/Bindings/DeprecatedBindings.cpp @@ -291,6 +291,114 @@ tolua_lerror: +static int tolua_cBlockInfo_GetPlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamStaticSelf("cBlockInfo") || + !L.CheckParamNumber(2) + ) + { + return 0; + } + + L.Push(""); + LOGWARNING("cBlockInfo:GetPlaceSound() is deprecated"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_get_cBlockInfo_m_PlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cBlockInfo")) + { + return 0; + } + + L.Push(""); + LOGWARNING("cBlockInfo.m_PlaceSound is deprecated"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_set_cBlockInfo_m_PlaceSound(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if (!L.CheckParamSelf("cBlockInfo")) + { + return 0; + } + + LOGWARNING("cBlockInfo.m_PlaceSound is deprecated"); + L.LogStackTrace(0); + return 0; +} + + + + + +static int tolua_get_cItem_m_Lore(lua_State * tolua_S) +{ + // Maintain legacy m_Lore variable as Lore table split by ` (grave-accent) + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cItem")) + { + return 0; + } + + const cItem * Self = nullptr; + L.GetStackValue(1, Self); + + AString LoreString = StringJoin(Self->m_LoreTable, "`"); + + L.Push(LoreString); + + LOGWARNING("cItem.m_Lore is deprecated, use cItem.m_LoreTable instead"); + L.LogStackTrace(0); + return 1; +} + + + + + +static int tolua_set_cItem_m_Lore(lua_State * tolua_S) +{ + // Maintain legacy m_Lore variable as Lore table split by ` (grave-accent) + cLuaState L(tolua_S); + if ( + !L.CheckParamSelf("cItem") || + !L.CheckParamString(2) + ) + { + return 0; + } + + cItem * Self = nullptr; + AString LoreString; + L.GetStackValues(1, Self, LoreString); + + Self->m_LoreTable = StringSplit(LoreString, "`"); + + LOGWARNING("cItem.m_Lore is deprecated, use cItem.m_LoreTable instead"); + L.LogStackTrace(0); + return 0; +} + + + + + /* method: Trace of class cTracer */ static int tolua_cTracer_Trace(lua_State * a_LuaState) { @@ -439,6 +547,15 @@ void DeprecatedBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "StringToMobType", tolua_AllToLua_StringToMobType00); + tolua_beginmodule(tolua_S, "cBlockInfo"); + tolua_function(tolua_S, "GetPlaceSound", tolua_cBlockInfo_GetPlaceSound); + tolua_variable(tolua_S, "m_PlaceSound", tolua_get_cBlockInfo_m_PlaceSound, tolua_set_cBlockInfo_m_PlaceSound); + tolua_endmodule(tolua_S); + + tolua_beginmodule(tolua_S, "cItem"); + tolua_variable(tolua_S, "m_Lore", tolua_get_cItem_m_Lore, tolua_set_cItem_m_Lore); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cTracer"); tolua_function(tolua_S, "Trace", tolua_cTracer_Trace); tolua_endmodule(tolua_S); diff --git a/src/Bindings/DiffAPIDesc.lua b/src/Bindings/DiffAPIDesc.lua index 8b8c340e2..54d379356 100644 --- a/src/Bindings/DiffAPIDesc.lua +++ b/src/Bindings/DiffAPIDesc.lua @@ -129,14 +129,17 @@ end -- a_FunctionDoc is a single documentation item for a function, as loaded from ToLua++'s parser local function functionDescMatchesDocs(a_FunctionDesc, a_FunctionDoc) -- Check the number of parameters: - local numParams + local numParams = 0 local numOptionalParams = 0 if (not(a_FunctionDesc.Params) or (a_FunctionDesc.Params == "")) then numParams = 0 else - _, numParams = string.gsub(a_FunctionDesc.Params, ",", "") - numParams = numParams + 1 - _, numOptionalParams = string.gsub(a_FunctionDesc.Params, "%b[]", "") + for _, Param in pairs(a_FunctionDesc.Params) do + numParams = numParams + 1 + if Param.IsOptional then + numOptionalParams = numOptionalParams + 1 + end + end end local numDocParams = #(a_FunctionDoc.Params) if ((numDocParams > numParams) or (numDocParams < numParams - numOptionalParams)) then diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index e30d0ed5f..185759acc 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -875,6 +875,17 @@ void cLuaState::Push(const char * a_Value) +void cLuaState::Push(const cItem & a_Item) +{ + ASSERT(IsValid()); + auto c = new cItem(a_Item); + tolua_pushusertype_and_takeownership(m_LuaState, c, "cItem"); +} + + + + + void cLuaState::Push(const cNil & a_Nil) { ASSERT(IsValid()); @@ -1140,6 +1151,37 @@ bool cLuaState::GetStackValue(int a_StackPos, AStringMap & a_Value) +bool cLuaState::GetStackValue(int a_StackPos, AStringVector & a_Value) +{ + // Retrieve all values in an array of string table: + if (!lua_istable(m_LuaState, a_StackPos)) + { + return false; + } + cStackTable tbl(*this, a_StackPos); + bool isValid = true; + tbl.ForEachArrayElement([&](cLuaState & a_LuaState, int a_Index) + { + AString tempStr; + if (a_LuaState.GetStackValue(-1, tempStr)) + { + a_Value.push_back(std::move(tempStr)); + } + else + { + isValid = false; + return true; + } + return false; + } + ); + return isValid; +} + + + + + bool cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) { a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 3d5b1e645..ffcddcfe8 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -614,6 +614,7 @@ public: void Push(const AStringMap & a_Dictionary); void Push(const AStringVector & a_Vector); void Push(const char * a_Value); + void Push(const cItem & a_Item); void Push(const cNil & a_Nil); void Push(const cRef & a_Ref); void Push(const Vector3d & a_Vector); @@ -639,6 +640,7 @@ public: // Enum values are checked for their allowed values and fail if the value is not assigned. bool GetStackValue(int a_StackPos, AString & a_Value); bool GetStackValue(int a_StackPos, AStringMap & a_Value); + bool GetStackValue(int a_StackPos, AStringVector & a_Value); bool GetStackValue(int a_StackPos, bool & a_Value); bool GetStackValue(int a_StackPos, cCallback & a_Callback); bool GetStackValue(int a_StackPos, cCallbackPtr & a_Callback); diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index fd714390e..2802c69db 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -9,7 +9,7 @@ #include "PluginLua.h" #include "Root.h" #include "lua/src/lauxlib.h" // Needed for LUA_REFNIL - +#include "ClientHandle.h" @@ -86,6 +86,19 @@ cLuaWindow::~cLuaWindow() +void cLuaWindow::SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked) +{ + // Only one Lua state can be a cLuaWindow object callback: + ASSERT(a_OnClicked->IsSameLuaState(*m_LuaState)); + + // Store the new reference, releasing the old one if appropriate: + m_OnClicked = std::move(a_OnClicked); +} + + + + + void cLuaWindow::SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing) { // Only one Lua state can be a cLuaWindow object callback: @@ -206,3 +219,24 @@ void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) + +void cLuaWindow::Clicked(cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + if (m_OnClicked != nullptr) + { + // Plugin can stop a click + if (m_OnClicked->Call(this, &a_Player, a_SlotNum, a_ClickAction, a_ClickedItem)) + { + // Tell the client the actual state of the window + a_Player.GetClientHandle()->SendInventorySlot(-1, -1, a_Player.GetDraggingItem()); + BroadcastWholeWindow(); + return; + } + } + + cWindow::Clicked(a_Player, a_WindowID, a_SlotNum, a_ClickAction, a_ClickedItem); +} + + + + diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h index fb21c1c4e..8f3349d00 100644 --- a/src/Bindings/LuaWindow.h +++ b/src/Bindings/LuaWindow.h @@ -49,6 +49,10 @@ public: // tolua_end + /** Sets the Lua callback to call when the player clicks on the window. + The window can stop the click from propogating. */ + void SetOnClicked(cLuaState::cCallbackPtr && a_OnClicked); + /** Sets the Lua callback function to call when the window is about to close */ void SetOnClosing(cLuaState::cCallbackPtr && a_OnClosing); @@ -63,6 +67,9 @@ protected: /** The canon Lua state that has opened the window and owns the m_LuaRef */ cLuaState * m_LuaState; + /** The Lua callback to call when the player clicked on a slot */ + cLuaState::cCallbackPtr m_OnClicked; + /** The Lua callback to call when the window is closing for any player */ cLuaState::cCallbackPtr m_OnClosing; @@ -80,6 +87,11 @@ protected: // cWindow overrides: virtual void OpenedByPlayer(cPlayer & a_Player) override; + virtual void Clicked( + cPlayer & a_Player, int a_WindowID, + short a_SlotNum, eClickAction a_ClickAction, + const cItem & a_ClickedItem + ) override; virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override; virtual void Destroy(void) override; virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index e4410dd14..6fe133e1e 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -11,11 +11,6 @@ #include "PluginLua.h" #include "PluginManager.h" #include "LuaWindow.h" -#include "../Root.h" -#include "../World.h" -#include "../Entities/Player.h" -#include "../WebAdmin.h" -#include "../ClientHandle.h" #include "../BlockArea.h" #include "../BlockEntities/BeaconEntity.h" #include "../BlockEntities/BrewingstandEntity.h" @@ -28,14 +23,20 @@ #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" +#include "../BoundingBox.h" +#include "../BuildInfo.h" +#include "../ClientHandle.h" +#include "../CommandOutput.h" +#include "../CompositeChat.h" +#include "../Entities/Player.h" #include "../Generating/ChunkDesc.h" +#include "../HTTP/UrlParser.h" +#include "../Item.h" #include "../LineBlockTracer.h" -#include "../CompositeChat.h" +#include "../Root.h" #include "../StringCompression.h" -#include "../CommandOutput.h" -#include "../BuildInfo.h" -#include "../HTTP/UrlParser.h" -#include "../BoundingBox.h" +#include "../WebAdmin.h" +#include "../World.h" @@ -2557,6 +2558,57 @@ static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L) +static int tolua_get_cItem_m_LoreTable(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if (!L.CheckParamSelf("const cItem")) + { + return 0; + } + + // Get the params: + const cItem * Self = nullptr; + L.GetStackValue(1, Self); + + // Push the result: + L.Push(Self->m_LoreTable); + return 1; +} + + + + + +static int tolua_set_cItem_m_LoreTable(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamSelf("cItem") || + !L.CheckParamTable(2) + ) + { + return 0; + } + + // Get the params: + cItem * Self = nullptr; + L.GetStackValue(1, Self); + + // Set the value: + Self->m_LoreTable.clear(); + if (!L.GetStackValue(2, Self->m_LoreTable)) + { + return L.ApiParamError("cItem.m_LoreTable: Could not read value as an array of strings"); + } + return 0; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -3798,6 +3850,10 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cItem"); + tolua_variable(tolua_S, "m_LoreTable", tolua_get_cItem_m_LoreTable, tolua_set_cItem_m_LoreTable); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cItemGrid"); tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords); tolua_endmodule(tolua_S); @@ -3816,6 +3872,7 @@ void cManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "new", tolua_cLuaWindow_new); tolua_function(tolua_S, "new_local", tolua_cLuaWindow_new_local); tolua_function(tolua_S, ".call", tolua_cLuaWindow_new_local); + tolua_function(tolua_S, "SetOnClicked", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClicked>); tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>); tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>); tolua_endmodule(tolua_S); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 3276fde67..22e8f15e2 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -80,6 +80,7 @@ public: virtual bool OnPlayerJoined (cPlayer & a_Player) = 0; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) = 0; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; + virtual bool OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) = 0; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) = 0; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index e3aa63aa1..5af336a95 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -659,6 +659,15 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi +bool cPluginLua::OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) +{ + return CallSimpleHooks(cPluginManager::HOOK_PLAYER_OPENING_WINDOW, &a_Player, &a_Window); +} + + + + + bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { return CallSimpleHooks(cPluginManager::HOOK_PLAYER_PLACED_BLOCK, @@ -1056,6 +1065,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_PLAYER_JOINED: return "OnPlayerJoined"; case cPluginManager::HOOK_PLAYER_LEFT_CLICK: return "OnPlayerLeftClick"; case cPluginManager::HOOK_PLAYER_MOVING: return "OnPlayerMoving"; + case cPluginManager::HOOK_PLAYER_OPENING_WINDOW: return "OnPlayerOpeningWindow"; case cPluginManager::HOOK_PLAYER_PLACED_BLOCK: return "OnPlayerPlacedBlock"; case cPluginManager::HOOK_PLAYER_PLACING_BLOCK: return "OnPlayerPlacingBlock"; case cPluginManager::HOOK_PLAYER_RIGHT_CLICK: return "OnPlayerRightClick"; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index ff5e8d726..4de5751e7 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -101,6 +101,7 @@ public: virtual bool OnPlayerJoined (cPlayer & a_Player) override; virtual bool OnPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) override; virtual bool OnPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) override; + virtual bool OnPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) override; virtual bool OnPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override; virtual bool OnPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange) override; virtual bool OnPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 066ccf9d7..1d977fcde 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -999,6 +999,25 @@ bool cPluginManager::CallHookPlayerMoving(cPlayer & a_Player, const Vector3d & a +bool cPluginManager::CallHookPlayerOpeningWindow(cPlayer & a_Player, cWindow & a_Window) +{ + FIND_HOOK(HOOK_PLAYER_OPENING_WINDOW); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnPlayerOpeningWindow(a_Player, a_Window)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { FIND_HOOK(HOOK_PLAYER_PLACED_BLOCK); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index f38ac8fa1..f3fc3551a 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -24,6 +24,7 @@ class cPickup; class cPlayer; class cPlugin; class cProjectileEntity; +class cWindow; class cWorld; class cSettingsRepositoryInterface; class cDeadlockDetect; @@ -111,6 +112,7 @@ public: HOOK_PLAYER_JOINED, HOOK_PLAYER_LEFT_CLICK, HOOK_PLAYER_MOVING, + HOOK_PLAYER_OPENING_WINDOW, HOOK_PLAYER_PLACED_BLOCK, HOOK_PLAYER_PLACING_BLOCK, HOOK_PLAYER_RIGHT_CLICK, @@ -257,6 +259,7 @@ public: bool CallHookPlayerJoined (cPlayer & a_Player); bool CallHookPlayerLeftClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); bool CallHookPlayerMoving (cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition); + bool CallHookPlayerOpeningWindow (cPlayer & a_Player, cWindow & a_Window); bool CallHookPlayerPlacedBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange); bool CallHookPlayerPlacingBlock (cPlayer & a_Player, const sSetBlock & a_BlockChange); bool CallHookPlayerRightClick (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 74c4d867f..667a231a4 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -1954,8 +1954,8 @@ void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTY cCuboid cBlockArea::GetBounds(void) const { return cCuboid( - m_Origin.x, m_Origin.y, m_Origin.z, - m_Origin.x + m_Size.x - 1, m_Origin.y + m_Size.y - 1, m_Origin.z + m_Size.z - 1 + m_Origin, + m_Origin + m_Size - Vector3i(1, 1, 1) ); } diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp index 24de9e25c..a772290dd 100644 --- a/src/BlockEntities/BeaconEntity.cpp +++ b/src/BlockEntities/BeaconEntity.cpp @@ -19,7 +19,10 @@ cBeaconEntity::cBeaconEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int m_SecondaryEffect(cEntityEffect::effNoEffect) { ASSERT(a_BlockType == E_BLOCK_BEACON); - UpdateBeacon(); + if (m_World != nullptr) + { + UpdateBeacon(); + } } diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp index 54f6e0dfa..a8f5b7242 100644 --- a/src/BlockEntities/ChestEntity.cpp +++ b/src/BlockEntities/ChestEntity.cpp @@ -7,7 +7,6 @@ #include "../UI/ChestWindow.h" #include "../ClientHandle.h" #include "../Mobs/Ocelot.h" -#include "../BoundingBox.h" @@ -219,32 +218,13 @@ void cChestEntity::DestroyWindow() -class cFindSittingCat : - public cEntityCallback -{ - virtual bool Item(cEntity * a_Entity) override - { - return ( - (a_Entity->GetEntityType() == cEntity::etMonster) && - (static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) && - (static_cast<cOcelot *>(a_Entity)->IsSitting()) - ); - } -}; - - - - - bool cChestEntity::IsBlocked() { - cFindSittingCat FindSittingCat; return ( - (GetPosY() >= cChunkDef::Height - 1) || - !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + (GetPosY() < cChunkDef::Height - 1) && ( - (GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()) == E_BLOCK_AIR) && - !GetWorld()->ForEachEntityInBox(cBoundingBox(Vector3d(GetPosX(), GetPosY() + 1, GetPosZ()), 1, 1), FindSittingCat) + !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + !cOcelot::IsCatSittingOnBlock(GetWorld(), Vector3d(GetPos())) ) ); } diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp index 9030a0172..e475d7022 100644 --- a/src/BlockEntities/EnderChestEntity.cpp +++ b/src/BlockEntities/EnderChestEntity.cpp @@ -7,6 +7,7 @@ #include "../Entities/Player.h" #include "../UI/EnderChestWindow.h" #include "../ClientHandle.h" +#include "../Mobs/Ocelot.h" @@ -48,8 +49,13 @@ void cEnderChestEntity::SendTo(cClientHandle & a_Client) bool cEnderChestEntity::UsedBy(cPlayer * a_Player) { - // TODO: cats are an obstruction - if ((GetPosY() < cChunkDef::Height - 1) && !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ()))) + if ( + (GetPosY() < cChunkDef::Height - 1) && + ( + !cBlockInfo::IsTransparent(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())) || + !cOcelot::IsCatSittingOnBlock(GetWorld(), Vector3d(GetPos())) + ) + ) { // Obstruction, don't open return false; diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index 9cc6f20c6..5246ae6ca 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -178,7 +178,7 @@ void cMobSpawnerEntity::SpawnEntity(void) double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX; double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ; - cMonster * Monster = cMonster::NewMonsterFromType(m_MobType); + auto Monster = cMonster::NewMonsterFromType(m_MobType); if (Monster == nullptr) { continue; @@ -186,7 +186,7 @@ void cMobSpawnerEntity::SpawnEntity(void) Monster->SetPosition(PosX, RelY, PosZ); Monster->SetYaw(Random.RandReal(360.0f)); - if (Chunk->GetWorld()->SpawnMobFinalize(Monster) != cEntity::INVALID_ID) + if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID) { EntitiesSpawned = true; Chunk->BroadcastSoundParticleEffect( diff --git a/src/BlockInServerPluginInterface.h b/src/BlockInServerPluginInterface.h index c6578fe72..b3a71577f 100644 --- a/src/BlockInServerPluginInterface.h +++ b/src/BlockInServerPluginInterface.h @@ -10,11 +10,10 @@ #pragma once #include "Blocks/BlockPluginInterface.h" -#include "World.h" #include "Bindings/PluginManager.h" - +class cWorld; class cBlockInServerPluginInterface : diff --git a/src/BlockInfo.h b/src/BlockInfo.h index 569b537c1..1ba818cb3 100644 --- a/src/BlockInfo.h +++ b/src/BlockInfo.h @@ -55,9 +55,6 @@ public: /** Block height */ float m_BlockHeight; - /** Sound when placing this block */ - AString m_PlaceSound; - /** Block's hardness. The greater the value the longer the player needs to break the block. */ float m_Hardness; @@ -85,7 +82,6 @@ public: inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; } inline static bool CanBeTerraformed (BLOCKTYPE a_Type) { return Get(a_Type).m_CanBeTerraformed; } inline static float GetBlockHeight (BLOCKTYPE a_Type) { return Get(a_Type).m_BlockHeight; } - inline static AString GetPlaceSound (BLOCKTYPE a_Type) { return Get(a_Type).m_PlaceSound; } inline static float GetHardness (BLOCKTYPE a_Type) { return Get(a_Type).m_Hardness; } // tolua_end @@ -105,7 +101,6 @@ public: , m_FullyOccupiesVoxel(false) , m_CanBeTerraformed(false) , m_BlockHeight(1.0) - , m_PlaceSound() , m_Hardness(0.0f) , m_Handler() {} diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 634c7dd3a..f2cbfde18 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -6,9 +6,9 @@ #include "BlockEntity.h" #include "MetaRotator.h" #include "ChunkInterface.h" -#include "../Entities/Entity.h" +class cEntity; class cPlayer; class cWorldInterface; diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 041a579f7..808c271b3 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -34,7 +34,7 @@ public: Meta |= 0x08; a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta, false); - a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_WorldInterface.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", x, y, z, 0.5f, 0.6f); // Queue a button reset (unpress) @@ -45,7 +45,7 @@ public: { // Block hasn't change in the meantime; set its meta a_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07, false); - a_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_World.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_World.BroadcastSoundEffect("block.stone_button.click_off", x, y, z, 0.5f, 0.5f); } } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 1eae70c42..4c2209383 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -650,7 +650,7 @@ void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterf // Wake up the simulators for this block: int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); } } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 56a1169e9..7d6a1bc8b 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -23,7 +23,7 @@ public: NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + a_WorldInterface.WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", static_cast<double>(a_BlockX), static_cast<double>(a_BlockY), static_cast<double>(a_BlockZ), 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); return true; } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 21dba0bed..eae9f7fd5 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -159,7 +159,7 @@ public: // Wake up the simulators for this block: int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; - a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, &a_Chunk); + a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk); } } diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h index d471df6f1..1300ffe8c 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -1,15 +1,17 @@ #pragma once -#include "BroadcastInterface.h" + #include "../Mobs/MonsterTypes.h" -class cItems; typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +class cBroadcastInterface; +class cItems; +class cPlayer; + -class cPlayer; class cWorldInterface @@ -72,6 +74,6 @@ public: virtual int GetHeight(int a_BlockX, int a_BlockZ) = 0; /** Wakes up the simulators for the specified block */ - virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) = 0; + virtual void WakeUpSimulators(Vector3i a_Block) = 0; }; diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index 5a594a2a4..afb7e025b 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -19,7 +19,7 @@ cBoundingBox::cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a -cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) : +cBoundingBox::cBoundingBox(Vector3d a_Min, Vector3d a_Max) : m_Min(a_Min), m_Max(a_Max) { @@ -29,7 +29,7 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) : -cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height) : +cBoundingBox::cBoundingBox(Vector3d a_Pos, double a_Radius, double a_Height) : m_Min(a_Pos.x - a_Radius, a_Pos.y, a_Pos.z - a_Radius), m_Max(a_Pos.x + a_Radius, a_Pos.y + a_Height, a_Pos.z + a_Radius) { @@ -39,7 +39,7 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Hei -cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_CubeLength) : +cBoundingBox::cBoundingBox(Vector3d a_Pos, double a_CubeLength) : m_Min(a_Pos.x - a_CubeLength / 2, a_Pos.y - a_CubeLength / 2, a_Pos.z - a_CubeLength / 2), m_Max(a_Pos.x + a_CubeLength / 2, a_Pos.y + a_CubeLength / 2, a_Pos.z + a_CubeLength / 2) { @@ -84,7 +84,7 @@ void cBoundingBox::Move(double a_OffX, double a_OffY, double a_OffZ) -void cBoundingBox::Move(const Vector3d & a_Off) +void cBoundingBox::Move(Vector3d a_Off) { m_Min.x += a_Off.x; m_Min.y += a_Off.y; @@ -141,7 +141,7 @@ cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other) -bool cBoundingBox::IsInside(const Vector3d & a_Point) +bool cBoundingBox::IsInside(Vector3d a_Point) { return IsInside(m_Min, m_Max, a_Point); } @@ -169,7 +169,7 @@ bool cBoundingBox::IsInside(cBoundingBox & a_Other) -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max) { // If both coords are inside this, then the entire a_Other is inside return (IsInside(a_Min) && IsInside(a_Max)); @@ -179,7 +179,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max) -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max, Vector3d a_Point) { return ( ((a_Point.x >= a_Min.x) && (a_Point.x <= a_Max.x)) && @@ -192,7 +192,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, cons -bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z) +bool cBoundingBox::IsInside(Vector3d a_Min, Vector3d a_Max, double a_X, double a_Y, double a_Z) { return ( ((a_X >= a_Min.x) && (a_X <= a_Max.x)) && @@ -205,7 +205,7 @@ bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, doub -bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face) const +bool cBoundingBox::CalcLineIntersection(Vector3d a_Line1, Vector3d a_Line2, double & a_LineCoeff, eBlockFace & a_Face) const { return CalcLineIntersection(m_Min, m_Max, a_Line1, a_Line2, a_LineCoeff, a_Face); } @@ -214,7 +214,7 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d -bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face) +bool cBoundingBox::CalcLineIntersection(Vector3d a_Min, Vector3d a_Max, Vector3d a_Line1, Vector3d a_Line2, double & a_LineCoeff, eBlockFace & a_Face) { if (IsInside(a_Min, a_Max, a_Line1)) { diff --git a/src/BoundingBox.h b/src/BoundingBox.h index 48b9a3d82..809b7fe7c 100644 --- a/src/BoundingBox.h +++ b/src/BoundingBox.h @@ -24,9 +24,9 @@ class cBoundingBox { public: cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ); - cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max); - cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height); - cBoundingBox(const Vector3d & a_Pos, double a_CubeLength); + cBoundingBox(Vector3d a_Min, Vector3d a_Max); + cBoundingBox(Vector3d a_Pos, double a_Radius, double a_Height); + cBoundingBox(Vector3d a_Pos, double a_CubeLength); cBoundingBox(const cBoundingBox & a_Orig); cBoundingBox & operator=(const cBoundingBox & a_Other); @@ -35,7 +35,7 @@ public: void Move(double a_OffX, double a_OffY, double a_OffZ); /** Moves the entire boundingbox by the specified offset */ - void Move(const Vector3d & a_Off); + void Move(Vector3d a_Off); /** Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction) */ void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ); @@ -47,7 +47,7 @@ public: cBoundingBox Union(const cBoundingBox & a_Other); /** Returns true if the point is inside the bounding box */ - bool IsInside(const Vector3d & a_Point); + bool IsInside(Vector3d a_Point); /** Returns true if the point is inside the bounding box */ bool IsInside(double a_X, double a_Y, double a_Z); @@ -56,13 +56,13 @@ public: bool IsInside(cBoundingBox & a_Other); /** Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box */ - bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max); + bool IsInside(Vector3d a_Min, Vector3d a_Max); /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ - static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point); + static bool IsInside(Vector3d a_Min, Vector3d a_Max, Vector3d a_Point); /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ - static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z); + static bool IsInside(Vector3d a_Min, Vector3d a_Max, double a_X, double a_Y, double a_Z); // tolua_end @@ -70,13 +70,13 @@ public: Also calculates the distance along the line in which the intersection occurs, and the face hit (BLOCK_FACE_ constants) Only forward collisions (a_LineCoeff >= 0) are returned. Exported to Lua manually, because ToLua++ would generate needless input params (a_LineCoeff, a_Face). */ - bool CalcLineIntersection(const Vector3d & a_LinePoint1, const Vector3d & a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face) const; + bool CalcLineIntersection(Vector3d a_LinePoint1, Vector3d a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face) const; /** Returns true if the specified bounding box is intersected by the line specified by its two points Also calculates the distance along the line in which the intersection occurs, and the face hit (BLOCK_FACE_ constants) Only forward collisions (a_LineCoeff >= 0) are returned. Exported to Lua manually, because ToLua++ would generate needless input params (a_LineCoeff, a_Face). */ - static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_LinePoint1, const Vector3d & a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face); + static bool CalcLineIntersection(Vector3d a_Min, Vector3d a_Max, Vector3d a_LinePoint1, Vector3d a_LinePoint2, double & a_LineCoeff, eBlockFace & a_Face); /** Calculates the intersection of the two bounding boxes; returns true if nonempty. Exported manually, because ToLua++ would generate needless input params (a_Intersection). */ @@ -92,8 +92,8 @@ public: double GetMaxY(void) const { return m_Max.y; } double GetMaxZ(void) const { return m_Max.z; } - const Vector3d & GetMin(void) const { return m_Min; } - const Vector3d & GetMax(void) const { return m_Max; } + Vector3d GetMin(void) const { return m_Min; } + Vector3d GetMax(void) const { return m_Max; } // tolua_end diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 3b9739907..4c85c9c80 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -136,13 +136,12 @@ cChunk::~cChunk() // Remove and destroy all entities that are not players: cEntityList Entities; std::swap(Entities, m_Entities); // Need another list because cEntity destructors check if they've been removed from chunk - for (auto Entity : Entities) + for (auto & Entity : Entities) { if (!Entity->IsPlayer()) { // Scheduling a normal destruction is neither possible (Since this chunk will be gone till the schedule occurs) nor necessary. Entity->DestroyNoScheduling(false); // No point in broadcasting in an unloading chunk. Chunks unload when no one is nearby. - delete Entity; } } @@ -300,9 +299,9 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) a_Callback.ChunkData(m_ChunkData); - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { - a_Callback.Entity(Entity); + a_Callback.Entity(Entity.get()); } for (auto & KeyPair : m_BlockEntities) @@ -453,7 +452,10 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock } // for y // Erase all affected block entities: - cCuboid affectedArea(OffX, a_MinBlockY, OffZ, OffX + SizeX - 1, a_MinBlockY + SizeY - 1, OffZ + SizeZ - 1); + cCuboid affectedArea( + {OffX, a_MinBlockY, OffZ}, + {OffX + SizeX - 1, a_MinBlockY + SizeY - 1, OffZ + SizeZ - 1} + ); for (auto itr = m_BlockEntities.begin(); itr != m_BlockEntities.end();) { if (affectedArea.IsInside(itr->second->GetPos())) @@ -531,7 +533,7 @@ void cChunk::CollectMobCensus(cMobCensus & toFill) } Vector3d currentPosition; - for (auto entity : m_Entities) + for (auto & entity : m_Entities) { // LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); if (entity->IsMob()) @@ -634,7 +636,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner) continue; } - cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); + auto newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); if (newMob == nullptr) { continue; @@ -658,7 +660,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) // If we are not valid, tick players and bailout if (!IsValid()) { - for (auto Entity : m_Entities) + for (const auto & Entity : m_Entities) { if (Entity->IsPlayer()) { @@ -683,7 +685,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) m_IsDirty = KeyPair.second->Tick(a_Dt, *this) | m_IsDirty; } - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + for (auto itr = m_Entities.begin(); itr != m_Entities.end();) { // Do not tick mobs that are detached from the world. They're either scheduled for teleportation or for removal. if (!(*itr)->IsTicking()) @@ -708,20 +710,22 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) continue; } - if ((((*itr)->GetChunkX() != m_PosX) || - ((*itr)->GetChunkZ() != m_PosZ)) + if ( + ((*itr)->GetChunkX() != m_PosX) || + ((*itr)->GetChunkZ() != m_PosZ) ) { - // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities - // The entity moved out of the chunk, move it to the neighbor - - (*itr)->SetParentChunk(nullptr); - MoveEntityToNewChunk(*itr); // Mark as dirty if it was a server-generated entity: if (!(*itr)->IsPlayer()) { MarkDirty(); } + + // This block is very similar to RemoveEntity, except it uses an iterator to avoid scanning the whole m_Entities + // The entity moved out of the chunk, move it to the neighbor + (*itr)->SetParentChunk(nullptr); + MoveEntityToNewChunk(std::move(*itr)); + itr = m_Entities.erase(itr); } else @@ -750,7 +754,7 @@ void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) -void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) +void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) { cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == nullptr) @@ -764,28 +768,29 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity) } ASSERT(Neighbor != this); // Moving into the same chunk? wtf? - Neighbor->AddEntity(a_Entity); + auto & Entity = *a_Entity; + Neighbor->AddEntity(std::move(a_Entity)); class cMover : public cClientDiffCallback { virtual void Removed(cClientHandle * a_Client) override { - a_Client->SendDestroyEntity(*m_Entity); + a_Client->SendDestroyEntity(m_Entity); } virtual void Added(cClientHandle * a_Client) override { - m_Entity->SpawnOn(*a_Client); + m_Entity.SpawnOn(*a_Client); } - cEntity * m_Entity; + cEntity & m_Entity; public: - cMover(cEntity * a_CallbackEntity) : + cMover(cEntity & a_CallbackEntity) : m_Entity(a_CallbackEntity) {} - } Mover(a_Entity); + } Mover(Entity); m_ChunkMap->CompareChunkClients(this, Neighbor, Mover); } @@ -1489,7 +1494,7 @@ void cChunk::WakeUpSimulators(void) // The redstone sim takes multiple blocks, use the inbuilt checker if (RedstoneSimulator->IsAllowedBlock(Block)) { - RedstoneSimulator->AddBlock(BlockX, y, BlockZ, this); + RedstoneSimulator->AddBlock({BlockX, y, BlockZ}, this); continue; } @@ -1497,12 +1502,12 @@ void cChunk::WakeUpSimulators(void) { case E_BLOCK_WATER: { - WaterSimulator->AddBlock(BlockX, y, BlockZ, this); + WaterSimulator->AddBlock({BlockX, y, BlockZ}, this); break; } case E_BLOCK_LAVA: { - LavaSimulator->AddBlock(BlockX, y, BlockZ, this); + LavaSimulator->AddBlock({BlockX, y, BlockZ}, this); break; } default: @@ -1770,16 +1775,20 @@ void cChunk::AddBlockEntityClean(cBlockEntity * a_BlockEntity) cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) { - // Check that the query coords are within chunk bounds: - ASSERT(a_BlockX >= m_PosX * cChunkDef::Width); - ASSERT(a_BlockX < m_PosX * cChunkDef::Width + cChunkDef::Width); - ASSERT(a_BlockZ >= m_PosZ * cChunkDef::Width); - ASSERT(a_BlockZ < m_PosZ * cChunkDef::Width + cChunkDef::Width); - int RelX = a_BlockX - m_PosX * cChunkDef::Width; int RelZ = a_BlockZ - m_PosZ * cChunkDef::Width; - auto itr = m_BlockEntities.find(MakeIndex(RelX, a_BlockY, RelZ)); + if ( + !IsValidWidth (RelX) || + !IsValidHeight(a_BlockY) || + !IsValidWidth (RelZ) + ) + { + // Coordinates are outside outside the world, no block entities here + return nullptr; + } + + auto itr = m_BlockEntities.find(MakeIndexNoCheck(RelX, a_BlockY, RelZ)); return (itr == m_BlockEntities.end()) ? nullptr : itr->second; } @@ -1866,15 +1875,15 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) double PosY = a_Player.GetPosY(); double PosZ = a_Player.GetPosZ(); - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + for (auto & Entity : m_Entities) { - if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile())) + if ((!Entity->IsPickup()) && (!Entity->IsProjectile())) { continue; // Only pickups and projectiles can be picked up } - float DiffX = static_cast<float>((*itr)->GetPosX() - PosX); - float DiffY = static_cast<float>((*itr)->GetPosY() - PosY); - float DiffZ = static_cast<float>((*itr)->GetPosZ() - PosZ); + float DiffX = static_cast<float>(Entity->GetPosX() - PosX); + float DiffY = static_cast<float>(Entity->GetPosY() - PosY); + float DiffZ = static_cast<float>(Entity->GetPosZ() - PosZ); float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ; if (SqrDist < 1.5f * 1.5f) // 1.5 block { @@ -1884,13 +1893,13 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player) ); */ MarkDirty(); - if ((*itr)->IsPickup()) + if (Entity->IsPickup()) { - (reinterpret_cast<cPickup *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cPickup *>(Entity.get())->CollectedBy(a_Player); } else { - (reinterpret_cast<cProjectileEntity *>(*itr))->CollectedBy(a_Player); + reinterpret_cast<cProjectileEntity *>(Entity.get())->CollectedBy(a_Player); } } else if (SqrDist < 5 * 5) @@ -1986,7 +1995,7 @@ void cChunk::RemoveClient(cClientHandle * a_Client) if (!a_Client->IsDestroyed()) { - for (auto Entity : m_Entities) + for (auto & Entity : m_Entities) { /* // DEBUG: @@ -2024,34 +2033,59 @@ bool cChunk::HasAnyClients(void) const -void cChunk::AddEntity(cEntity * a_Entity) +void cChunk::AddEntity(OwnedEntity a_Entity) { if (!a_Entity->IsPlayer()) { MarkDirty(); } + auto EntityPtr = a_Entity.get(); + ASSERT(std::find(m_Entities.begin(), m_Entities.end(), a_Entity) == m_Entities.end()); // Not there already + m_Entities.emplace_back(std::move(a_Entity)); - m_Entities.push_back(a_Entity); - ASSERT(a_Entity->GetParentChunk() == nullptr); - a_Entity->SetParentChunk(this); + ASSERT(EntityPtr->GetParentChunk() == nullptr); + EntityPtr->SetParentChunk(this); } -void cChunk::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunk::RemoveEntity(cEntity & a_Entity) { - ASSERT(a_Entity->GetParentChunk() == this); - a_Entity->SetParentChunk(nullptr); - m_Entities.remove(a_Entity); + ASSERT(a_Entity.GetParentChunk() == this); + ASSERT(!a_Entity.IsTicking()); + a_Entity.SetParentChunk(nullptr); + // Mark as dirty if it was a server-generated entity: - if (!a_Entity->IsPlayer()) + if (!a_Entity.IsPlayer()) { MarkDirty(); } + + OwnedEntity Removed; + m_Entities.erase( + std::remove_if( + m_Entities.begin(), + m_Entities.end(), + [&a_Entity, &Removed](decltype(m_Entities)::value_type & a_Value) + { + if (a_Value.get() == &a_Entity) + { + ASSERT(!Removed); + Removed = std::move(a_Value); + return true; + } + + return false; + } + ), + m_Entities.end() + ); + + return Removed; } @@ -2060,13 +2094,13 @@ void cChunk::RemoveEntity(cEntity * a_Entity) bool cChunk::HasEntity(UInt32 a_EntityID) { - for (cEntityList::const_iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if ((*itr)->GetUniqueID() == a_EntityID) + if (Entity->GetUniqueID() == a_EntityID) { return true; } - } // for itr - m_Entities[] + } return false; } @@ -2077,14 +2111,14 @@ bool cChunk::HasEntity(UInt32 a_EntityID) bool cChunk::ForEachEntity(cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) { continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2099,7 +2133,7 @@ bool cChunk::ForEachEntity(cEntityCallback & a_Callback) bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) + for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2) { ++itr2; if (!(*itr)->IsTicking()) @@ -2112,7 +2146,7 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_ // The entity is not in the specified box continue; } - if (a_Callback.Item(*itr)) + if (a_Callback.Item(itr->get())) { return false; } @@ -2136,11 +2170,11 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, b bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult) { // The entity list is locked by the parent chunkmap's CS - for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr) + for (const auto & Entity : m_Entities) { - if (((*itr)->GetUniqueID() == a_EntityID) && ((*itr)->IsTicking())) + if ((Entity->GetUniqueID() == a_EntityID) && (Entity->IsTicking())) { - a_CallbackResult = a_Callback(*itr); + a_CallbackResult = a_Callback(Entity.get()); return true; } } // for itr - m_Entitites[] diff --git a/src/Chunk.h b/src/Chunk.h index 87f2cd568..7e399052d 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -61,6 +61,7 @@ class cChunk : public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef { public: + /** Represents the presence state of the chunk */ enum ePresence { @@ -75,7 +76,7 @@ public: cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP, // Neighbor chunks cAllocationPool<cChunkData::sChunkSection> & a_Pool ); - cChunk(cChunk & other); + cChunk(cChunk & other) = delete; ~cChunk(); /** Returns true iff the chunk block data is valid (loaded / generated) */ @@ -248,8 +249,12 @@ public: /** Returns true if theres any client in the chunk; false otherwise */ bool HasAnyClients(void) const; - void AddEntity(cEntity * a_Entity); - void RemoveEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); + + /** Releases ownership of the given entity if it was found in this chunk. + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); + bool HasEntity(UInt32 a_EntityID); /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ @@ -525,7 +530,7 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers std::vector<cClientHandle *> m_LoadedByClient; - cEntityList m_Entities; + std::vector<OwnedEntity> m_Entities; cBlockEntities m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ @@ -602,7 +607,7 @@ private: bool GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType); /** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */ - void MoveEntityToNewChunk(cEntity * a_Entity); + void MoveEntityToNewChunk(OwnedEntity a_Entity); }; typedef cChunk * cChunkPtr; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 11a03a26e..f4a0867b5 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -27,8 +27,10 @@ class cBlockEntity; class cEntity; class cClientHandle; class cBlockEntity; +class cChunkCoords; -typedef std::list<cEntity *> cEntityList; +typedef std::unique_ptr<cEntity> OwnedEntity; +typedef std::vector<OwnedEntity> cEntityList; typedef std::map<int, cBlockEntity *> cBlockEntities; @@ -50,6 +52,25 @@ typedef unsigned char HEIGHTTYPE; + +class cChunkCoords +{ +public: + int m_ChunkX; + int m_ChunkZ; + + cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} + + bool operator == (const cChunkCoords & a_Other) const + { + return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); + } +} ; + + + + + /** Constants used throughout the code, useful typedefs and utility functions */ class cChunkDef { @@ -107,9 +128,9 @@ public: } /** Converts relative block coordinates into absolute coordinates with a known chunk location */ - inline static Vector3i RelativeToAbsolute(const Vector3i & a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) + inline static Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition, int a_ChunkX, int a_ChunkZ) { - return Vector3i(a_RelBlockPosition.x + a_ChunkX * Width, a_RelBlockPosition.y, a_RelBlockPosition.z + a_ChunkZ * Width); + return {a_RelBlockPosition.x + a_ChunkX * Width, a_RelBlockPosition.y, a_RelBlockPosition.z + a_ChunkZ * Width}; } /** Validates a height-coordinate. Returns false if height-coordiante is out of height bounds */ @@ -127,16 +148,26 @@ public: /** Converts absolute block coords to chunk coords: */ inline static void BlockToChunk(int a_X, int a_Z, int & a_ChunkX, int & a_ChunkZ) { - a_ChunkX = a_X / Width; - if ((a_X < 0) && (a_X % Width != 0)) + // This version is deprecated in favor of the vector version + // If you're developing new code, use the other version. + auto ChunkCoords = BlockToChunk({a_X, 0, a_Z}); + a_ChunkX = ChunkCoords.m_ChunkX; + a_ChunkZ = ChunkCoords.m_ChunkZ; + } + + /** The Y coordinate of a_Pos is ignored */ + inline static cChunkCoords BlockToChunk(Vector3i a_Pos) + { + cChunkCoords Chunk(a_Pos.x / Width, a_Pos.z / Width); + if ((a_Pos.x < 0) && (a_Pos.x % Width != 0)) { - a_ChunkX--; + Chunk.m_ChunkX--; } - a_ChunkZ = a_Z / cChunkDef::Width; - if ((a_Z < 0) && (a_Z % Width != 0)) + if ((a_Pos.z < 0) && (a_Pos.z % Width != 0)) { - a_ChunkZ--; + Chunk.m_ChunkZ--; } + return Chunk; } @@ -407,24 +438,6 @@ struct sSetBlock typedef std::list<sSetBlock> sSetBlockList; typedef std::vector<sSetBlock> sSetBlockVector; - - - - -class cChunkCoords -{ -public: - int m_ChunkX; - int m_ChunkZ; - - cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {} - - bool operator == (const cChunkCoords & a_Other) const - { - return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ)); - } -} ; - typedef std::list<cChunkCoords> cChunkCoordsList; typedef std::vector<cChunkCoords> cChunkCoordsVector; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index b1a7d6ec5..fcd990ad6 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -114,11 +114,11 @@ cChunkPtr cChunkMap::GetChunk(int a_ChunkX, int a_ChunkZ) -cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) +cChunkPtr cChunkMap::GetChunkNoGen(cChunkCoords a_Chunk) { ASSERT(m_CSChunks.IsLockedByCurrentThread()); // m_CSChunks should already be locked by the operation that called us - auto Chunk = ConstructChunk(a_ChunkX, a_ChunkZ); + auto Chunk = ConstructChunk(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); if (Chunk == nullptr) { return nullptr; @@ -126,7 +126,7 @@ cChunkPtr cChunkMap::GetChunkNoGen(int a_ChunkX, int a_ChunkZ) if (!Chunk->IsValid() && !Chunk->IsQueued()) { Chunk->SetPresence(cChunk::cpQueued); - m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ); + m_World->GetStorage().QueueLoadChunk(a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ); } return Chunk; @@ -739,17 +739,15 @@ bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> -void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) +void cChunkMap::WakeUpSimulators(Vector3i a_Block) { cCSLock Lock(m_CSChunks); - int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); - cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(cChunkDef::BlockToChunk(a_Block)); if ((Chunk == nullptr) || !Chunk->IsValid()) { return; } - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk); + m_World->GetSimulatorManager()->WakeUp(a_Block, Chunk); } @@ -1139,7 +1137,7 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B if ((Chunk != nullptr) && Chunk->IsValid()) { Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients); - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk); + m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, Chunk); } BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); } @@ -1360,7 +1358,7 @@ bool cChunkMap::DigBlock(int a_BlockX, int a_BlockY, int a_BlockZ) } DestChunk->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, 0); - m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, DestChunk); + m_World->GetSimulatorManager()->WakeUp({a_BlockX, a_BlockY, a_BlockZ}, DestChunk); } return true; @@ -1497,38 +1495,38 @@ void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) -void cChunkMap::AddEntity(cEntity * a_Entity) +void cChunkMap::AddEntity(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } -void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) +void cChunkMap::AddEntityIfNotPresent(OwnedEntity a_Entity) { cCSLock Lock(m_CSChunks); cChunkPtr Chunk = GetChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); if (Chunk == nullptr) // This will assert inside GetChunk in Debug builds { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", - static_cast<void *>(a_Entity), a_Entity->GetClass(), a_Entity->GetUniqueID() + static_cast<void *>(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() ); return; } if (!Chunk->HasEntity(a_Entity->GetUniqueID())) { - Chunk->AddEntity(a_Entity); + Chunk->AddEntity(std::move(a_Entity)); } } @@ -1553,17 +1551,18 @@ bool cChunkMap::HasEntity(UInt32 a_UniqueID) -void cChunkMap::RemoveEntity(cEntity * a_Entity) +OwnedEntity cChunkMap::RemoveEntity(cEntity & a_Entity) { cCSLock Lock(m_CSChunks); - cChunkPtr Chunk = a_Entity->GetParentChunk(); + cChunkPtr Chunk = a_Entity.GetParentChunk(); - // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) if (Chunk == nullptr) { - return; + return nullptr; } - Chunk->RemoveEntity(a_Entity); + + // Remove the entity no matter whether the chunk itself is valid or not (#1190) + return Chunk->RemoveEntity(a_Entity); } @@ -1821,8 +1820,8 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): m_World->GetSimulatorManager()->WakeUpArea(cCuboid( - bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1, - bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1 + {bx - ExplosionSizeInt - 1, MinY, bz - ExplosionSizeInt - 1}, + {bx + ExplosionSizeInt + 1, MaxY, bz + ExplosionSizeInt + 1} )); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 330c6532d..e902be60c 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -110,7 +110,14 @@ public: bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback); /** Wakes up simulators for the specified block */ - void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); + void WakeUpSimulators(Vector3i a_Block); + + // DEPRECATED, use the vector-parametered version instead. + void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) + { + LOGWARNING("cChunkMap::WakeUpSimulators(int, int, int) is deprecated, use cChunkMap::WakeUpSimulators(Vector3i) instead."); + WakeUpSimulators(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + } void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); void MarkChunkSaving (int a_ChunkX, int a_ChunkZ); @@ -207,17 +214,18 @@ public: void RemoveClientFromChunks(cClientHandle * a_Client); /** Adds the entity to its appropriate chunk, takes ownership of the entity pointer */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Adds the entity to its appropriate chunk, if the entity is not already added. Takes ownership of the entity pointer */ - void AddEntityIfNotPresent(cEntity * a_Entity); + void AddEntityIfNotPresent(OwnedEntity a_Entity); /** Returns true if the entity with specified ID is present in the chunks */ bool HasEntity(UInt32 a_EntityID); - /** Removes the entity from its appropriate chunk */ - void RemoveEntity(cEntity * a_Entity); + /** Removes the entity from its appropriate chunk + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible @@ -484,7 +492,13 @@ private: cChunkPtr GetChunk(int a_ChunkX, int a_ChunkZ); /** Constructs a chunk and queues the chunk for loading if not valid, returning it; doesn't generate */ - cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ); + cChunkPtr GetChunkNoGen(cChunkCoords a_Chunk); + + // Deprecated in favor of the vector version + cChunkPtr GetChunkNoGen(int a_ChunkX, int a_ChunkZ) + { + return GetChunkNoGen(cChunkCoords(a_ChunkX, a_ChunkZ)); + } /** Constructs a chunk, returning it. Doesn't load, doesn't generate */ cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkZ); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 54cfa5310..a8279a738 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -133,7 +133,7 @@ cClientHandle::~cClientHandle() } m_Player->DestroyNoScheduling(true); } - delete m_Player; + m_PlayerPtr.reset(); m_Player = nullptr; } @@ -157,8 +157,12 @@ void cClientHandle::Destroy(void) cCSLock Lock(m_CSOutgoingData); m_Link.reset(); } + + // Temporary (#3115-will-fix): variable to keep track of whether the client authenticated and had the opportunity to have ownership transferred to the world + bool WasAddedToWorld = false; { cCSLock Lock(m_CSState); + WasAddedToWorld = (m_State >= csAuthenticated); if (m_State >= csDestroying) { // Already called @@ -186,7 +190,23 @@ void cClientHandle::Destroy(void) { player->StopEveryoneFromTargetingMe(); player->SetIsTicking(false); - world->RemovePlayer(player, true); + + if (WasAddedToWorld) + { + // If ownership was transferred, our own smart pointer should be unset + ASSERT(!m_PlayerPtr); + + m_PlayerPtr = world->RemovePlayer(*player, true); + + // And RemovePlayer should have returned a valid smart pointer + ASSERT(m_PlayerPtr); + } + else + { + // If ownership was not transferred, our own smart pointer should be valid and RemovePlayer's should not + ASSERT(m_PlayerPtr); + ASSERT(!world->IsPlayerReferencedInWorldOrChunk(*player)); + } } player->RemoveClientHandle(); } @@ -359,7 +379,8 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID, m_Protocol->SendLoginSuccess(); // Spawn player (only serversided, so data is loaded) - m_Player = new cPlayer(m_Self, GetUsername()); + m_PlayerPtr = cpp14::make_unique<cPlayer>(m_Self, GetUsername()); + m_Player = m_PlayerPtr.get(); /* LOGD("Created a new cPlayer object at %p for client %s @ %s (%p)", static_cast<void *>(m_Player), @@ -2203,7 +2224,7 @@ void cClientHandle::ServerTick(float a_Dt) // Add the player to the world (start ticking from there): m_State = csDownloadingWorld; - m_Player->Initialize(*(m_Player->GetWorld())); + m_Player->Initialize(std::move(m_PlayerPtr), *(m_Player->GetWorld())); return; } } // lock(m_CSState) diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 9b7e3dd58..9e1d1a9b5 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -12,7 +12,6 @@ #include "OSSupport/Network.h" #include "Defines.h" #include "Scoreboard.h" -#include "Map.h" #include "UI/SlotArea.h" #include "json/json.h" #include "ChunkSender.h" @@ -34,6 +33,7 @@ class cWindow; class cFallingBlock; class cCompositeChat; class cStatManager; +class cMap; class cClientHandle; typedef std::shared_ptr<cClientHandle> cClientHandlePtr; @@ -416,6 +416,9 @@ private: cPlayer * m_Player; + // Temporary (#3115-will-fix): maintain temporary ownership of created cPlayer objects while they are in limbo + std::unique_ptr<cPlayer> m_PlayerPtr; + /** This is an optimization which saves you an iteration of m_SentChunks if you just want to know whether or not the player is standing at a sent chunk. If this is equal to the coordinates of the chunk the player is currrently standing at, then this must be a sent chunk diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp index 1aa1e92e1..d87a6ef5e 100644 --- a/src/Cuboid.cpp +++ b/src/Cuboid.cpp @@ -7,30 +7,9 @@ -/** Returns true if the two specified intervals have a non-empty union */ -static bool DoIntervalsIntersect(int a_Min1, int a_Max1, int a_Min2, int a_Max2) -{ - return ( - ((a_Min1 >= a_Min2) && (a_Min1 <= a_Max2)) || // Start of first interval is within the second interval - ((a_Max1 >= a_Min2) && (a_Max1 <= a_Max2)) || // End of first interval is within the second interval - ((a_Min2 >= a_Min1) && (a_Min2 <= a_Max1)) // Start of second interval is within the first interval - ); -} - - - - - //////////////////////////////////////////////////////////////////////////////// // cCuboid: -cCuboid & cCuboid::operator =(cCuboid a_Other) -{ - std::swap(p1, a_Other.p1); - std::swap(p2, a_Other.p2); - return *this; -} - @@ -95,23 +74,6 @@ int cCuboid::GetVolume(void) const -bool cCuboid::DoesIntersect(const cCuboid & a_Other) const -{ - ASSERT(IsSorted()); - ASSERT(a_Other.IsSorted()); - - // In order for cuboids to intersect, each of their coord intervals need to intersect - return ( - DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) && - DoIntervalsIntersect(p1.y, p2.y, a_Other.p1.y, a_Other.p2.y) && - DoIntervalsIntersect(p1.z, p2.z, a_Other.p1.z, a_Other.p2.z) - ); -} - - - - - bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const { ASSERT(IsSorted()); @@ -229,7 +191,7 @@ bool cCuboid::IsSorted(void) const -void cCuboid::Engulf(const Vector3i & a_Point) +void cCuboid::Engulf(Vector3i a_Point) { if (a_Point.x < p1.x) { diff --git a/src/Cuboid.h b/src/Cuboid.h index 3ade5bc20..b39d3ad4a 100644 --- a/src/Cuboid.h +++ b/src/Cuboid.h @@ -13,16 +13,14 @@ public: Vector3i p1, p2; cCuboid(void) {} - cCuboid(const cCuboid & a_Cuboid) : p1(a_Cuboid.p1), p2(a_Cuboid.p2) {} cCuboid(const Vector3i & a_p1, const Vector3i & a_p2) : p1(a_p1), p2(a_p2) {} cCuboid(int a_X1, int a_Y1, int a_Z1) : p1(a_X1, a_Y1, a_Z1), p2(a_X1, a_Y1, a_Z1) {} - cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) {} - // tolua_end - - cCuboid & operator =(cCuboid a_Other); - - // tolua_begin + // DEPRECATED, use cCuboid(Vector3i, Vector3i) instead + cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) + { + LOGWARNING("cCuboid(int, int, int, int, int, int) constructor is deprecated, use cCuboid(Vector3i, Vector3i) constructor instead."); + } void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2); void Assign(const cCuboid & a_SrcCuboid); @@ -40,9 +38,20 @@ public: /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. Assumes both cuboids are sorted. */ - bool DoesIntersect(const cCuboid & a_Other) const; + inline bool DoesIntersect(const cCuboid & a_Other) const + { + ASSERT(IsSorted()); + ASSERT(a_Other.IsSorted()); + + // In order for cuboids to intersect, each of their coord intervals need to intersect + return ( + DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) && + DoIntervalsIntersect(p1.y, p2.y, a_Other.p1.y, a_Other.p2.y) && + DoIntervalsIntersect(p1.z, p2.z, a_Other.p1.z, a_Other.p2.z) + ); + } - bool IsInside(const Vector3i & v) const + bool IsInside(Vector3i v) const { return ( (v.x >= p1.x) && (v.x <= p2.x) && @@ -60,7 +69,7 @@ public: ); } - bool IsInside( const Vector3d & v) const + bool IsInside(Vector3d v) const { return ( (v.x >= p1.x) && (v.x <= p2.x) && @@ -94,7 +103,18 @@ public: bool IsSorted(void) const; /** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */ - void Engulf(const Vector3i & a_Point); + void Engulf(Vector3i a_Point); + +private: + + /** Returns true if the two specified intervals have a non-empty union */ + inline static bool DoIntervalsIntersect(int a_Min1, int a_Max1, int a_Min2, int a_Max2) + { + ASSERT(a_Min1 <= a_Max1); + ASSERT(a_Min2 <= a_Max2); + return ((a_Min1 <= a_Max2) && (a_Max1 >= a_Min2)); + } + } ; // tolua_end diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index e8430090b..6259098d8 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -119,23 +119,9 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) Damage += ExtraDamage; } - // int KnockbackAmount = 1; unsigned int PunchLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPunch); - if (PunchLevel > 0) - { - Vector3d LookVector = GetLookVector(); - Vector3f FinalSpeed = Vector3f(0, 0, 0); - switch (PunchLevel) - { - case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); break; - case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); break; - default: break; - } - a_EntityHit.SetSpeed(FinalSpeed); - } - - // a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); // TODO fix knockback. - a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, 0); // Until knockback is fixed. + double KnockbackAmount = 11 + 10 * PunchLevel; + a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, KnockbackAmount); if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming()) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index b596bc93d..a38a6552d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -135,9 +135,9 @@ const char * cEntity::GetParentClass(void) const -bool cEntity::Initialize(cWorld & a_World) +bool cEntity::Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld) { - if (cPluginManager::Get()->CallHookSpawningEntity(a_World, *this)) + if (cPluginManager::Get()->CallHookSpawningEntity(a_EntityWorld, *this)) { return false; } @@ -151,13 +151,13 @@ bool cEntity::Initialize(cWorld & a_World) ASSERT(m_World == nullptr); ASSERT(GetParentChunk() == nullptr); - a_World.AddEntity(this); + a_EntityWorld.AddEntity(std::move(a_Self)); ASSERT(m_World != nullptr); - cPluginManager::Get()->CallHookSpawnedEntity(a_World, *this); + cPluginManager::Get()->CallHookSpawnedEntity(a_EntityWorld, *this); // Spawn the entity on the clients: - a_World.BroadcastSpawnEntity(*this); + a_EntityWorld.BroadcastSpawnEntity(*this); return true; } @@ -230,8 +230,10 @@ void cEntity::Destroy(bool a_ShouldBroadcast) this->GetUniqueID(), this->GetClass(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - delete this; + + // Make sure that RemoveEntity returned a valid smart pointer + // Also, not storing the returned pointer means automatic destruction + VERIFY(ParentChunk->RemoveEntity(*this)); }); Destroyed(); } @@ -343,7 +345,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R Vector3d Heading(0, 0, 0); if (a_Attacker != nullptr) { - Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 16 : 11); + Heading = a_Attacker->GetLookVector(); } TDI.Knockback = Heading * a_KnockbackAmount; @@ -532,21 +534,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) // Add knockback: if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != nullptr)) { - int KnockbackLevel = static_cast<int>(a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback)); // More common enchantment - if (KnockbackLevel < 1) - { - // We support punch on swords and vice versa! :) - KnockbackLevel = static_cast<int>(a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch)); - } - - Vector3d AdditionalSpeed(0, 0, 0); - switch (KnockbackLevel) - { - case 1: AdditionalSpeed.Set(5, 0.3, 5); break; - case 2: AdditionalSpeed.Set(8, 0.3, 8); break; - default: break; - } - AddSpeed(a_TDI.Knockback + AdditionalSpeed); + AddSpeed(a_TDI.Knockback); } m_World->BroadcastEntityStatus(*this, esGenericHurt); @@ -761,9 +749,19 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama double cEntity::GetKnockbackAmountAgainst(const cEntity & a_Receiver) { // Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit + double Knockback = 11; - // TODO: Enchantments - return 1; + // If we're sprinting, bump up the knockback + if (IsSprinting()) + { + Knockback = 16; + } + + // Check for knockback enchantments (punch only applies to shot arrows) + unsigned int KnockbackLevel = GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); + Knockback += 10 * KnockbackLevel; + + return Knockback; } @@ -1585,8 +1583,7 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddEntity(this); + a_World->AddEntity(ParentChunk->RemoveEntity(*this)); cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld); }); return true; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8991b9fad..8f433b816 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -157,7 +157,7 @@ public: /** Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed). Adds the entity to the world. */ - virtual bool Initialize(cWorld & a_World); + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_EntityWorld); // tolua_begin @@ -670,8 +670,6 @@ private: int m_InvulnerableTicks; } ; // tolua_export -typedef std::list<cEntity *> cEntityList; - diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 3bbe334fb..a1b518cbc 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -149,12 +149,12 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : -bool cPlayer::Initialize(cWorld & a_World) +bool cPlayer::Initialize(OwnedEntity a_Self, cWorld & a_World) { UNUSED(a_World); ASSERT(GetWorld() != nullptr); ASSERT(GetParentChunk() == nullptr); - GetWorld()->AddPlayer(this); + GetWorld()->AddPlayer(std::unique_ptr<cPlayer>(static_cast<cPlayer *>(a_Self.release()))); cPluginManager::Get()->CallHookSpawnedEntity(*GetWorld(), *this); @@ -1321,10 +1321,16 @@ cTeam * cPlayer::UpdateTeam(void) void cPlayer::OpenWindow(cWindow & a_Window) { + if (cRoot::Get()->GetPluginManager()->CallHookPlayerOpeningWindow(*this, a_Window)) + { + return; + } + if (&a_Window != m_CurrentWindow) { CloseWindow(false); } + a_Window.OpenedByPlayer(*this); m_CurrentWindow = &a_Window; a_Window.SendWholeWindow(*GetClientHandle()); @@ -2003,7 +2009,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d GetWorld()->BroadcastDestroyEntity(*this); // Remove player from world - GetWorld()->RemovePlayer(this, false); + // Make sure that RemovePlayer didn't return a valid smart pointer, due to the second parameter being false + // We remain valid and not destructed after this call + VERIFY(!GetWorld()->RemovePlayer(*this, false)); // Set position to the new position SetPosition(a_NewPosition); @@ -2045,8 +2053,10 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), ParentChunk->GetPosX(), ParentChunk->GetPosZ() ); - ParentChunk->RemoveEntity(this); - a_World->AddPlayer(this, &a_OldWorld); // New world will take over and announce client at its next tick + + // New world will take over and announce client at its next tick + auto PlayerPtr = static_cast<cPlayer *>(ParentChunk->RemoveEntity(*this).release()); + a_World->AddPlayer(std::unique_ptr<cPlayer>(PlayerPtr), &a_OldWorld); }); return true; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c00dbc7f1..8c21c25d6 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -41,7 +41,7 @@ public: cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName); - virtual bool Initialize(cWorld & a_World) override; + virtual bool Initialize(OwnedEntity a_Self, cWorld & a_World) override; virtual ~cPlayer() override; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 64522acef..d1e101964 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -260,7 +260,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve -cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) +std::unique_ptr<cProjectileEntity> cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed) { Vector3d Speed; if (a_Speed != nullptr) @@ -270,15 +270,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); - case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); - case pkSplashPotion: return new cSplashPotionEntity (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); - case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return cpp14::make_unique<cArrowEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return cpp14::make_unique<cThrownEggEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return cpp14::make_unique<cThrownEnderPearlEntity>(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return cpp14::make_unique<cThrownSnowballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkGhastFireball: return cpp14::make_unique<cGhastFireballEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFireCharge: return cpp14::make_unique<cFireChargeEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkExpBottle: return cpp14::make_unique<cExpBottleEntity> (a_Creator, a_X, a_Y, a_Z, Speed); + case pkSplashPotion: return cpp14::make_unique<cSplashPotionEntity> (a_Creator, a_X, a_Y, a_Z, Speed, *a_Item); + case pkWitherSkull: return cpp14::make_unique<cWitherSkullEntity> (a_Creator, a_X, a_Y, a_Z, Speed); case pkFirework: { ASSERT(a_Item != nullptr); @@ -287,7 +287,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, return nullptr; } - return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item); + return cpp14::make_unique<cFireworkEntity>(a_Creator, a_X, a_Y, a_Z, *a_Item); } case pkFishingFloat: break; } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index b354c7cfc..da8c650f5 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -46,7 +46,7 @@ public: cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); - static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); + static std::unique_ptr<cProjectileEntity> Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = nullptr); /** Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given */ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace); diff --git a/src/Entities/SplashPotionEntity.h b/src/Entities/SplashPotionEntity.h index 85aa5046f..baa5da725 100644 --- a/src/Entities/SplashPotionEntity.h +++ b/src/Entities/SplashPotionEntity.h @@ -12,10 +12,12 @@ #include "ProjectileEntity.h" #include "EntityEffect.h" #include "../World.h" -#include "Entity.h" +class cEntity; + + // tolua_begin diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 22a0113e5..451451fd3 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -7,6 +7,7 @@ #include "ChunkDesc.h" #include "../Noise/Noise.h" #include "../BlockEntities/BlockEntity.h" +#include "../Entities/Entity.h" diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index 4c97430a2..709fccb70 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -231,7 +231,7 @@ private: cChunkDef::BiomeMap m_BiomeMap; cBlockArea m_BlockArea; cChunkDef::HeightMap m_HeightMap; - cEntityList m_Entities; // Individual entities are NOT owned by this object! + cEntityList m_Entities; cBlockEntities m_BlockEntities; // Individual block entities are NOT owned by this object! bool m_bUseDefaultBiomes; diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index d1201797c..fe5ce82be 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1489,11 +1489,11 @@ bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX double AnimalY = a_RelY; double AnimalZ = static_cast<double>(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + a_RelZ + 0.5); - cMonster * NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); + auto NewMob = cMonster::NewMonsterFromType(AnimalToSpawn); NewMob->SetHealth(NewMob->GetMaxHealth()); NewMob->SetPosition(AnimalX, AnimalY, AnimalZ); - a_ChunkDesc.GetEntities().push_back(NewMob); LOGD("Spawning %s #%i at {%.02f, %.02f, %.02f}", NewMob->GetClass(), NewMob->GetUniqueID(), AnimalX, AnimalY, AnimalZ); + a_ChunkDesc.GetEntities().emplace_back(std::move(NewMob)); return true; } diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index de2f5f95d..818b8254c 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -18,8 +18,8 @@ uses a prefabricate in a cBlockArea for drawing itself. cPrefab::cPrefab(const cPrefab::sDef & a_Def) : m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ), m_HitBox( - a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ, - a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ + {a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ}, + {a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ} ), m_AllowedRotations(a_Def.m_AllowedRotations), m_MergeStrategy(a_Def.m_MergeStrategy), diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index bf1fee2e8..5473965d6 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -128,7 +128,10 @@ public: m_Noise(a_Seed), m_MaxSize(a_MaxSize), m_Density(a_Density), - m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize), + m_Borders( + {a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize}, + {a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize} + ), m_Prefabs(a_Prefabs), m_HeightGen(a_HeightGen) { diff --git a/src/Item.cpp b/src/Item.cpp index 3d9efb3b3..995ff59dc 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -158,7 +158,12 @@ void cItem::GetJson(Json::Value & a_OutValue) const } if (!IsLoreEmpty()) { - a_OutValue["Lore"] = m_Lore; + auto & LoreArray = (a_OutValue["Lore"] = Json::Value(Json::arrayValue)); + + for (const auto & Line : m_LoreTable) + { + LoreArray.append(Line); + } } if (m_ItemColor.IsValid()) @@ -196,7 +201,11 @@ void cItem::FromJson(const Json::Value & a_Value) m_Enchantments.Clear(); m_Enchantments.AddFromString(a_Value.get("ench", "").asString()); m_CustomName = a_Value.get("Name", "").asString(); - m_Lore = a_Value.get("Lore", "").asString(); + auto Lore = a_Value.get("Lore", Json::arrayValue); + for (auto & Line : Lore) + { + m_LoreTable.push_back(Line.asString()); + } int red = a_Value.get("Color_Red", -1).asInt(); int green = a_Value.get("Color_Green", -1).asInt(); diff --git a/src/Item.h b/src/Item.h index 18a1e69c0..493061d93 100644 --- a/src/Item.h +++ b/src/Item.h @@ -41,7 +41,6 @@ public: m_ItemCount(0), m_ItemDamage(0), m_CustomName(""), - m_Lore(""), m_RepairCost(0), m_FireworkItem(), m_ItemColor() @@ -56,14 +55,14 @@ public: short a_ItemDamage = 0, const AString & a_Enchantments = "", const AString & a_CustomName = "", - const AString & a_Lore = "" + const AStringVector & a_LoreTable = {} ) : m_ItemType (a_ItemType), m_ItemCount (a_ItemCount), m_ItemDamage (a_ItemDamage), m_Enchantments(a_Enchantments), m_CustomName (a_CustomName), - m_Lore (a_Lore), + m_LoreTable (a_LoreTable), m_RepairCost (0), m_FireworkItem(), m_ItemColor() @@ -106,7 +105,7 @@ public: m_ItemDamage = 0; m_Enchantments.Clear(); m_CustomName = ""; - m_Lore = ""; + m_LoreTable.clear(); m_RepairCost = 0; m_FireworkItem.EmptyData(); m_ItemColor.Clear(); @@ -137,7 +136,7 @@ public: (m_ItemDamage == a_Item.m_ItemDamage) && (m_Enchantments == a_Item.m_Enchantments) && (m_CustomName == a_Item.m_CustomName) && - (m_Lore == a_Item.m_Lore) && + (m_LoreTable == a_Item.m_LoreTable) && m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem) ); } @@ -151,12 +150,12 @@ public: bool IsBothNameAndLoreEmpty(void) const { - return (m_CustomName.empty() && m_Lore.empty()); + return (m_CustomName.empty() && m_LoreTable.empty()); } bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); } - bool IsLoreEmpty(void) const { return (m_Lore.empty()); } + bool IsLoreEmpty(void) const { return (m_LoreTable.empty()); } /** Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items */ cItem CopyOne(void) const; @@ -221,7 +220,12 @@ public: short m_ItemDamage; cEnchantments m_Enchantments; AString m_CustomName; - AString m_Lore; + + // tolua_end + + AStringVector m_LoreTable; // Exported in ManualBindings.cpp + + // tolua_begin int m_RepairCost; cFireworkItem m_FireworkItem; diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index bdfed8944..f39a35a88 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -95,11 +95,8 @@ public: } // Spawn block at water level - cBoat * Boat = new cBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())); - if (!Boat->Initialize(*a_World)) + if (a_World->SpawnBoat(x + 0.5, y + 0.5, z + 0.5, cBoat::ItemToMaterial(a_Player->GetEquippedItem())) == cEntity::INVALID_ID) { - delete Boat; - Boat = nullptr; return false; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index a2f646efc..7cbd1dc70 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -69,17 +69,12 @@ public: } // Create the arrow entity: - cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); - if (Arrow == nullptr) + auto Arrow = cpp14::make_unique<cArrowEntity>(*a_Player, Force * 2); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *a_Player->GetWorld())) { return; } - if (!Arrow->Initialize(*a_Player->GetWorld())) - { - delete Arrow; - Arrow = nullptr; - return; - } a_Player->GetWorld()->BroadcastSoundEffect( "entity.arrow.shoot", a_Player->GetPosX(), diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index a32368304..012f13a6c 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -251,14 +251,13 @@ public: } else { - cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); - if (!Floater->Initialize(*a_World)) + auto Floater = cpp14::make_unique<cFloater>(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100))); + auto FloaterPtr = Floater.get(); + if (!FloaterPtr->Initialize(std::move(Floater), *a_World)) { - delete Floater; - Floater = nullptr; return false; } - a_Player->SetIsFishing(true, Floater->GetUniqueID()); + a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID()); } return true; } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 48cf782d8..faee5d008 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -3,7 +3,6 @@ #include "../Defines.h" #include "../Item.h" -#include "../Blocks/BlockPluginInterface.h" @@ -12,6 +11,7 @@ // fwd: class cWorld; class cPlayer; +class cBlockPluginInterface; diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 77a5bf47c..dd3e1f5a8 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -38,11 +38,10 @@ public: if (Block == E_BLOCK_AIR) { - cItemFrame * ItemFrame = new cItemFrame(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!ItemFrame->Initialize(*a_World)) + auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto ItemFramePtr = ItemFrame.get(); + if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World)) { - delete ItemFrame; - ItemFrame = nullptr; return false; } diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 623342d41..05f375f06 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -59,24 +59,9 @@ public: double x = static_cast<double>(a_BlockX) + 0.5; double y = static_cast<double>(a_BlockY) + 0.5; double z = static_cast<double>(a_BlockZ) + 0.5; - cMinecart * Minecart = nullptr; - switch (m_ItemType) - { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (x, y, z); break; - default: - { - ASSERT(!"Unhandled minecart item"); - return false; - } - } // switch (m_ItemType) - if (!Minecart->Initialize(*a_World)) + + if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID) { - delete Minecart; - Minecart = nullptr; return false; } diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index 3432583ca..8e5a1b5d2 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -70,11 +70,10 @@ public: { "BurningSkull" } }; - cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); - if (!Painting->Initialize(*a_World)) + auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, a_BlockX, a_BlockY, a_BlockZ); + auto PaintingPtr = Painting.get(); + if (!PaintingPtr->Initialize(std::move(Painting), *a_World)) { - delete Painting; - Painting = nullptr; return false; } diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index e3f5298e4..1e0db5175 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -342,13 +342,12 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int & a_MaxPackSize) { - cMonster * toReturn = nullptr; if (m_NewPack) { m_MobType = ChooseMobType(a_Biome); if (m_MobType == mtInvalidType) { - return toReturn; + return nullptr; } if (m_MobType == mtWolf) { @@ -366,14 +365,16 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) { - cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); + auto newMob = cMonster::NewMonsterFromType(m_MobType); + auto NewMobPtr = newMob.get(); if (newMob) { - m_Spawned.insert(newMob); + m_Spawned.insert(std::move(newMob)); } - toReturn = newMob; + return NewMobPtr; } - return toReturn; + + return nullptr; } diff --git a/src/MobSpawner.h b/src/MobSpawner.h index 941a04a17..14c721ae3 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -7,12 +7,6 @@ -// fwd: -class cChunk; - - - - /** This class is used to determine which monster can be spawned in which place it is essentially static (eg. Squids spawn in water, Zombies spawn in dark places) @@ -43,7 +37,7 @@ public : // return true if there is at least one allowed type bool CanSpawnAnything(void); - typedef const std::set<cMonster *> tSpawnedContainer; + typedef const std::set<std::unique_ptr<cMonster>> tSpawnedContainer; tSpawnedContainer & getSpawned(void); /** Returns true if specified type of mob can spawn on specified block */ @@ -61,7 +55,7 @@ protected : std::set<eMonsterType> m_AllowedTypes; bool m_NewPack; eMonsterType m_MobType; - std::set<cMonster *> m_Spawned; + std::set<std::unique_ptr<cMonster>> m_Spawned; } ; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index 8cdac12d1..a48bfa886 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -39,19 +39,17 @@ bool cBlaze::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cFireChargeEntity * FireCharge = new cFireChargeEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (FireCharge == nullptr) - { - return false; - } - if (!FireCharge->Initialize(*m_World)) + + auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto FireChargePtr = FireCharge.get(); + if (!FireChargePtr->Initialize(std::move(FireCharge), *m_World)) { - delete FireCharge; - FireCharge = nullptr; return false; } + ResetAttackCooldown(); // ToDo: Shoot 3 fireballs instead of 1. + return true; } return false; diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index 6f5a93d93..2488e63b1 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -39,17 +39,14 @@ bool cGhast::Attack(std::chrono::milliseconds a_Dt) // Setting this higher gives us more wiggle room for attackrate Vector3d Speed = GetLookVector() * 20; Speed.y = Speed.y + 1; - cGhastFireballEntity * GhastBall = new cGhastFireballEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (GhastBall == nullptr) - { - return false; - } - if (!GhastBall->Initialize(*m_World)) + + auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto GhastBallPtr = GhastBall.get(); + if (!GhastBallPtr->Initialize(std::move(GhastBall), *m_World)) { - delete GhastBall; - GhastBall = nullptr; return false; } + ResetAttackCooldown(); return true; } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index ecda6e724..8077e41d6 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -5,6 +5,7 @@ #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" +#include "../Items/ItemHandler.h" #include "../World.h" #include "../EffectID.h" #include "../Entities/Player.h" @@ -996,7 +997,7 @@ void cMonster::UnsafeUnsetTarget() -cPawn * cMonster::GetTarget () +cPawn * cMonster::GetTarget() { return m_Target; } @@ -1005,29 +1006,25 @@ cPawn * cMonster::GetTarget () -cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) +std::unique_ptr<cMonster> cMonster::NewMonsterFromType(eMonsterType a_MobType) { auto & Random = GetRandomProvider(); - cMonster * toReturn = nullptr; // Create the mob entity switch (a_MobType) { case mtMagmaCube: { - toReturn = new cMagmaCube(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cMagmaCube>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSlime: { - toReturn = new cSlime(1 << Random.RandInt(2)); // Size 1, 2 or 4 - break; + return cpp14::make_unique<cSlime>(1 << Random.RandInt(2)); // Size 1, 2 or 4 } case mtSkeleton: { // TODO: Actual detection of spawning in Nether - toReturn = new cSkeleton(false); - break; + return cpp14::make_unique<cSkeleton>(false); } case mtVillager: { @@ -1038,8 +1035,7 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) VillagerType = 0; } - toReturn = new cVillager(static_cast<cVillager::eVillagerType>(VillagerType)); - break; + return cpp14::make_unique<cVillager>(static_cast<cVillager::eVillagerType>(VillagerType)); } case mtHorse: { @@ -1055,42 +1051,41 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) HorseType = 0; } - toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes); - break; + return cpp14::make_unique<cHorse>(HorseType, HorseColor, HorseStyle, HorseTameTimes); } - case mtBat: toReturn = new cBat(); break; - case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCaveSpider(); break; - case mtChicken: toReturn = new cChicken(); break; - case mtCow: toReturn = new cCow(); break; - case mtCreeper: toReturn = new cCreeper(); break; - case mtEnderDragon: toReturn = new cEnderDragon(); break; - case mtEnderman: toReturn = new cEnderman(); break; - case mtGhast: toReturn = new cGhast(); break; - case mtGiant: toReturn = new cGiant(); break; - case mtGuardian: toReturn = new cGuardian(); break; - case mtIronGolem: toReturn = new cIronGolem(); break; - case mtMooshroom: toReturn = new cMooshroom(); break; - case mtOcelot: toReturn = new cOcelot(); break; - case mtPig: toReturn = new cPig(); break; - case mtRabbit: toReturn = new cRabbit(); break; - case mtSheep: toReturn = new cSheep(); break; - case mtSilverfish: toReturn = new cSilverfish(); break; - case mtSnowGolem: toReturn = new cSnowGolem(); break; - case mtSpider: toReturn = new cSpider(); break; - case mtSquid: toReturn = new cSquid(); break; - case mtWitch: toReturn = new cWitch(); break; - case mtWither: toReturn = new cWither(); break; - case mtWolf: toReturn = new cWolf(); break; - case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter - case mtZombiePigman: toReturn = new cZombiePigman(); break; + case mtBat: return cpp14::make_unique<cBat>(); + case mtBlaze: return cpp14::make_unique<cBlaze>(); + case mtCaveSpider: return cpp14::make_unique<cCaveSpider>(); + case mtChicken: return cpp14::make_unique<cChicken>(); + case mtCow: return cpp14::make_unique<cCow>(); + case mtCreeper: return cpp14::make_unique < cCreeper>(); + case mtEnderDragon: return cpp14::make_unique<cEnderDragon>(); + case mtEnderman: return cpp14::make_unique<cEnderman>(); + case mtGhast: return cpp14::make_unique<cGhast>(); + case mtGiant: return cpp14::make_unique<cGiant>(); + case mtGuardian: return cpp14::make_unique<cGuardian>(); + case mtIronGolem: return cpp14::make_unique<cIronGolem>(); + case mtMooshroom: return cpp14::make_unique<cMooshroom>(); + case mtOcelot: return cpp14::make_unique<cOcelot>(); + case mtPig: return cpp14::make_unique<cPig>(); + case mtRabbit: return cpp14::make_unique<cRabbit>(); + case mtSheep: return cpp14::make_unique<cSheep>(); + case mtSilverfish: return cpp14::make_unique<cSilverfish>(); + case mtSnowGolem: return cpp14::make_unique<cSnowGolem>(); + case mtSpider: return cpp14::make_unique<cSpider>(); + case mtSquid: return cpp14::make_unique<cSquid>(); + case mtWitch: return cpp14::make_unique<cWitch>(); + case mtWither: return cpp14::make_unique<cWither>(); + case mtWolf: return cpp14::make_unique<cWolf>(); + case mtZombie: return cpp14::make_unique<cZombie>(false); // TODO: Infected zombie parameter + case mtZombiePigman: return cpp14::make_unique<cZombiePigman>(); default: { ASSERT(!"Unhandled mob type whilst trying to spawn mob!"); + return nullptr; } } - return toReturn; } @@ -1099,7 +1094,13 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth) { - auto Count = GetRandomProvider().RandInt<char>(static_cast<char>(a_Min), static_cast<char>(a_Max)); + auto Count = GetRandomProvider().RandInt<unsigned int>(a_Min, a_Max); + auto MaxStackSize = static_cast<unsigned char>(ItemHandler(a_Item)->GetMaxStackSize()); + while (Count > MaxStackSize) + { + a_Drops.emplace_back(a_Item, MaxStackSize, a_ItemHealth); + Count -= MaxStackSize; + } if (Count > 0) { a_Drops.emplace_back(a_Item, Count, a_ItemHealth); diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index b79399a0f..268db6168 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -2,11 +2,11 @@ #pragma once #include "../Entities/Pawn.h" -#include "../Item.h" #include "MonsterTypes.h" #include "PathFinder.h" +class cItem; class cClientHandle; @@ -168,13 +168,13 @@ public: void UnsafeUnsetTarget(); /** Returns the current target. */ - cPawn * GetTarget (); + cPawn * GetTarget(); /** Creates a new object of the specified mob. a_MobType is the type of the mob to be created Asserts and returns null if mob type is not specified */ - static cMonster * NewMonsterFromType(eMonsterType a_MobType); + static std::unique_ptr<cMonster> NewMonsterFromType(eMonsterType a_MobType); /** Returns if this mob last target was a player to avoid destruction on player quit */ bool WasLastTargetAPlayer() const { return m_WasLastTargetAPlayer; } @@ -203,7 +203,11 @@ protected: bool ReachedFinalDestination(void) { return ((m_FinalDestination - GetPosition()).SqrLength() < WAYPOINT_RADIUS * WAYPOINT_RADIUS); } /** Returns whether or not the target is close enough for attack. */ - bool TargetIsInRange(void) { ASSERT(m_Target != nullptr); return ((m_Target->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); } + bool TargetIsInRange(void) + { + ASSERT(GetTarget() != nullptr); + return ((GetTarget()->GetPosition() - GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange)); + } /** Returns whether the monster needs to jump to reach a given height. */ inline bool DoesPosYRequireJump(double a_PosY) @@ -272,7 +276,9 @@ protected: void AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel); private: - /** A pointer to the entity this mobile is aiming to reach */ + /** A pointer to the entity this mobile is aiming to reach. + The validity of this pointer SHALL be guaranteed by the pointee; + it MUST be reset when the pointee changes worlds or is destroyed. */ cPawn * m_Target; } ; // tolua_export diff --git a/src/Mobs/Ocelot.cpp b/src/Mobs/Ocelot.cpp index 47776670c..e5004a1d1 100644 --- a/src/Mobs/Ocelot.cpp +++ b/src/Mobs/Ocelot.cpp @@ -6,6 +6,7 @@ #include "../Entities/Player.h" #include "../Items/ItemHandler.h" #include "Broadcaster.h" +#include "../BoundingBox.h" @@ -203,3 +204,30 @@ void cOcelot::SpawnOn(cClientHandle & a_ClientHandle) + +class cFindSittingCat : + public cEntityCallback +{ + virtual bool Item(cEntity * a_Entity) override + { + return ( + (a_Entity->GetEntityType() == cEntity::etMonster) && + (static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) && + (static_cast<cOcelot *>(a_Entity)->IsSitting()) + ); + } +}; + + + + + +bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition) +{ + cFindSittingCat FindSittingCat; + return a_World->ForEachEntityInBox(cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), FindSittingCat); +} + + + + diff --git a/src/Mobs/Ocelot.h b/src/Mobs/Ocelot.h index 5729851fe..59b4f25af 100644 --- a/src/Mobs/Ocelot.h +++ b/src/Mobs/Ocelot.h @@ -54,6 +54,9 @@ public: } void SetCatType (eCatType a_CatType) { m_CatType = a_CatType; } + /** Returns true if there's a cat sitting above the given position */ + static bool IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition); + protected: bool m_IsSitting; diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 0d6d5e428..e48991a06 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -57,19 +57,15 @@ bool cSkeleton::Attack(std::chrono::milliseconds a_Dt) Vector3d Inaccuracy = Vector3d(Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25), Random.RandReal<double>(-0.25, 0.25)); Vector3d Speed = (GetTarget()->GetPosition() + Inaccuracy - GetPosition()) * 5; Speed.y += Random.RandInt(-1, 1); - cArrowEntity * Arrow = new cArrowEntity(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); - if (Arrow == nullptr) - { - return false; - } - if (!Arrow->Initialize(*m_World)) + + auto Arrow = cpp14::make_unique<cArrowEntity>(this, GetPosX(), GetPosY() + 1, GetPosZ(), Speed); + auto ArrowPtr = Arrow.get(); + if (!ArrowPtr->Initialize(std::move(Arrow), *m_World)) { - delete Arrow; - Arrow = nullptr; return false; } - ResetAttackCooldown(); + ResetAttackCooldown(); return true; } return false; diff --git a/src/Mobs/Slime.cpp b/src/Mobs/Slime.cpp index 3f832ae87..291a3a57f 100644 --- a/src/Mobs/Slime.cpp +++ b/src/Mobs/Slime.cpp @@ -78,10 +78,10 @@ void cSlime::KilledBy(TakeDamageInfo & a_TDI) double AddX = (i % 2 - 0.5) * m_Size / 4.0; double AddZ = (i / 2 - 0.5) * m_Size / 4.0; - cSlime * NewSlime = new cSlime(m_Size / 2); + auto NewSlime = cpp14::make_unique<cSlime>(m_Size / 2); NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ); NewSlime->SetYaw(Random.RandReal(360.0f)); - m_World->SpawnMobFinalize(NewSlime); + m_World->SpawnMobFinalize(std::move(NewSlime)); } } super::KilledBy(a_TDI); diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index fad51c05f..dd85d7d2b 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -15,6 +15,7 @@ cWither::cWither(void) : m_WitherInvulnerableTicks(220) { SetMaxHealth(300); + SetHealth(GetMaxHealth() / 3); } @@ -30,18 +31,6 @@ bool cWither::IsArmored(void) const -bool cWither::Initialize(cWorld & a_World) -{ - // Set health before BroadcastSpawnEntity() - SetHealth(GetMaxHealth() / 3); - - return super::Initialize(a_World); -} - - - - - bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.DamageType == dtDrowning) diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index b430588c9..5f6ec607c 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -25,7 +25,6 @@ public: bool IsArmored(void) const; // cEntity overrides - virtual bool Initialize(cWorld & a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 70e761469..e05fedbf8 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -2,9 +2,9 @@ #pragma once #include "PassiveAggressiveMonster.h" -#include "../Entities/Entity.h" +class cEntity; diff --git a/src/Protocol/Packetizer.h b/src/Protocol/Packetizer.h index efed9c7a9..26b3a7ec7 100644 --- a/src/Protocol/Packetizer.h +++ b/src/Protocol/Packetizer.h @@ -11,7 +11,10 @@ #pragma once #include "Protocol.h" -#include "../ByteBuffer.h" + + + +class cByteBuffer; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 93f25310b..18ede0640 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -12,7 +12,6 @@ #include "../Defines.h" #include "../Scoreboard.h" -#include "../Map.h" #include "../ByteBuffer.h" #include "../EffectID.h" @@ -20,6 +19,7 @@ +class cMap; class cExpOrb; class cPlayer; class cEntity; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 43facde72..a65fb931e 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) case PROTO_VERSION_1_11_0: return "1.11"; case PROTO_VERSION_1_11_1: return "1.11.1"; case PROTO_VERSION_1_12: return "1.12"; + case PROTO_VERSION_1_12_1: return "1.12.1"; } ASSERT(!"Unknown protocol version"); return Printf("Unknown protocol (%d)", a_ProtocolVersion); @@ -1107,6 +1108,11 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema m_Protocol = new cProtocol_1_12(m_Client, ServerAddress, ServerPort, NextState); return true; } + case PROTO_VERSION_1_12_1: + { + m_Protocol = new cProtocol_1_12_1(m_Client, ServerAddress, ServerPort, NextState); + return true; + } default: { LOGD("Client \"%s\" uses an unsupported protocol (lengthed, version %u (0x%x))", diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 32dcca940..4c338a5b8 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,9 +18,9 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12" -#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335" -#define MCS_LATEST_PROTOCOL_VERSION 335 +#define MCS_CLIENT_VERSIONS "1.8.x, 1.9.x, 1.10.x, 1.11.x, 1.12.x" +#define MCS_PROTOCOL_VERSIONS "47, 107, 108, 109, 110, 210, 315, 316, 335, 338" +#define MCS_LATEST_PROTOCOL_VERSION 338 @@ -43,6 +43,7 @@ public: PROTO_VERSION_1_11_0 = 315, PROTO_VERSION_1_11_1 = 316, PROTO_VERSION_1_12 = 335, + PROTO_VERSION_1_12_1 = 338, } ; cProtocolRecognizer(cClientHandle * a_Client); diff --git a/src/Protocol/Protocol_1_12.cpp b/src/Protocol/Protocol_1_12.cpp index 278c063cc..b9eb1801d 100644 --- a/src/Protocol/Protocol_1_12.cpp +++ b/src/Protocol/Protocol_1_12.cpp @@ -1164,7 +1164,7 @@ void cProtocol_1_12::SendExperience(void) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x3f); // Experience Packet + cPacketizer Pkt(*this, 0x3f); // Set Experience Packet cPlayer * Player = m_Client->GetPlayer(); Pkt.WriteBEFloat(Player->GetXpPercentage()); Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel())); @@ -1211,7 +1211,7 @@ void cProtocol_1_12::SendScoreboardObjective(const AString & a_Name, const AStri void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x42); // Set passangers packet + cPacketizer Pkt(*this, 0x42); // Set Passengers packet Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); Pkt.WriteVarInt32(1); // 1 passenger Pkt.WriteVarInt32(a_Entity.GetUniqueID()); @@ -1224,7 +1224,7 @@ void cProtocol_1_12::SendAttachEntity(const cEntity & a_Entity, const cEntity & void cProtocol_1_12::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) { ASSERT(m_State == 3); // In game mode? - cPacketizer Pkt(*this, 0x42); // Set passangers packet + cPacketizer Pkt(*this, 0x42); // Set Passengers packet Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); Pkt.WriteVarInt32(0); // No passangers } @@ -1600,3 +1600,756 @@ bool cProtocol_1_12::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketTyp m_Client->PacketUnknown(a_PacketType); return false; } + + + + + +cProtocol_1_12_1::cProtocol_1_12_1(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : + super(a_Client, a_ServerAddress, a_ServerPort, a_State) +{ +} + + + + + +void cProtocol_1_12_1::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) +{ + cServer * Server = cRoot::Get()->GetServer(); + AString ServerDescription = Server->GetDescription(); + auto NumPlayers = static_cast<signed>(Server->GetNumPlayers()); + auto MaxPlayers = static_cast<signed>(Server->GetMaxPlayers()); + AString Favicon = Server->GetFaviconData(); + cRoot::Get()->GetPluginManager()->CallHookServerPing(*m_Client, ServerDescription, NumPlayers, MaxPlayers, Favicon); + + // Version: + Json::Value Version; + Version["name"] = "Cuberite 1.12.1"; + Version["protocol"] = cProtocolRecognizer::PROTO_VERSION_1_12_1; + + // Players: + Json::Value Players; + Players["online"] = NumPlayers; + Players["max"] = MaxPlayers; + // TODO: Add "sample" + + // Description: + Json::Value Description; + Description["text"] = ServerDescription.c_str(); + + // Create the response: + Json::Value ResponseValue; + ResponseValue["version"] = Version; + ResponseValue["players"] = Players; + ResponseValue["description"] = Description; + if (!Favicon.empty()) + { + ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str()); + } + + // Serialize the response into a packet: + Json::FastWriter Writer; + cPacketizer Pkt(*this, 0x00); // Response packet + Pkt.WriteString(Writer.write(ResponseValue)); +} + + + + + +void cProtocol_1_12_1::SendRespawn(eDimension a_Dimension) +{ + cPacketizer Pkt(*this, 0x35); // Respawn packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEInt32(static_cast<Int32>(a_Dimension)); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(static_cast<Byte>(Player->GetEffectiveGameMode())); + Pkt.WriteString("default"); +} + + + + + +void cProtocol_1_12_1::SendPlayerListAddPlayer(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(0); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteString(a_Player.GetPlayerListName()); + + const Json::Value & Properties = a_Player.GetClientHandle()->GetProperties(); + Pkt.WriteVarInt32(Properties.size()); + for (auto & Node : Properties) + { + Pkt.WriteString(Node.get("name", "").asString()); + Pkt.WriteString(Node.get("value", "").asString()); + AString Signature = Node.get("signature", "").asString(); + if (Signature.empty()) + { + Pkt.WriteBool(false); + } + else + { + Pkt.WriteBool(true); + Pkt.WriteString(Signature); + } + } + + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode())); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetClientHandle()->GetPing())); + Pkt.WriteBool(false); +} + + + + + +void cProtocol_1_12_1::SendPlayerListRemovePlayer(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(4); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdateGameMode(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Player.GetGameMode())); +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdatePing(const cPlayer & a_Player) +{ + ASSERT(m_State == 3); // In game mode? + + auto ClientHandle = a_Player.GetClientHandlePtr(); + if (ClientHandle != nullptr) + { + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(2); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + Pkt.WriteVarInt32(static_cast<UInt32>(ClientHandle->GetPing())); + } +} + + + + + +void cProtocol_1_12_1::SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2e); // Player List Item packet + Pkt.WriteVarInt32(3); + Pkt.WriteVarInt32(1); + Pkt.WriteUUID(a_Player.GetUUID()); + + if (a_CustomName.empty()) + { + Pkt.WriteBool(false); + } + else + { + Pkt.WriteBool(true); + Pkt.WriteString(Printf("{\"text\":\"%s\"}", a_CustomName.c_str())); + } +} + + + + + +void cProtocol_1_12_1::SendPlayerAbilities(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2c); // Player Abilities packet + Byte Flags = 0; + cPlayer * Player = m_Client->GetPlayer(); + if (Player->IsGameModeCreative()) + { + Flags |= 0x01; + Flags |= 0x08; // Godmode, used for creative + } + if (Player->IsFlying()) + { + Flags |= 0x02; + } + if (Player->CanFly()) + { + Flags |= 0x04; + } + Pkt.WriteBEUInt8(Flags); + Pkt.WriteBEFloat(static_cast<float>(0.05 * Player->GetFlyingMaxSpeed())); + Pkt.WriteBEFloat(static_cast<float>(0.1 * Player->GetNormalMaxSpeed())); +} + + + + + +void cProtocol_1_12_1::SendPlayerMoveLook(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x2f); // Player Position And Look packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEDouble(Player->GetPosX()); + Pkt.WriteBEDouble(Player->GetPosY()); + Pkt.WriteBEDouble(Player->GetPosZ()); + Pkt.WriteBEFloat(static_cast<float>(Player->GetYaw())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetPitch())); + Pkt.WriteBEUInt8(0); + Pkt.WriteVarInt32(++m_OutstandingTeleportId); + + // This teleport ID hasn't been confirmed yet + m_IsTeleportIdConfirmed = false; +} + + + + + +void cProtocol_1_12_1::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x30); // Use bed + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WritePosition64(a_BlockX, a_BlockY, a_BlockZ); +} + + + + + +void cProtocol_1_12_1::SendDestroyEntity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x32); // Destroy Entities packet + Pkt.WriteVarInt32(1); + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x33); // Remove entity effect packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID)); +} + + + + + +void cProtocol_1_12_1::SendEntityHeadLook(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x36); // Entity Head Look packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); +} + + + + + +void cProtocol_1_12_1::SendCameraSetTo(const cEntity & a_Entity) +{ + cPacketizer Pkt(*this, 0x39); // Camera packet (Attach the camera of a player at another entity in spectator mode) + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3b); // Display Scoreboard packet + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Display)); + Pkt.WriteString(a_Objective); +} + + + + + +void cProtocol_1_12_1::SendEntityMetadata(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3c); // Entity Metadata packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityMetadata(Pkt, a_Entity); + Pkt.WriteBEUInt8(0xff); // The termination byte +} + + + + + +void cProtocol_1_12_1::SendEntityVelocity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3e); // Entity Velocity packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + // 400 = 8000 / 20 ... Conversion from our speed in m / s to 8000 m / tick + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedX() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedY() * 400)); + Pkt.WriteBEInt16(static_cast<Int16>(a_Entity.GetSpeedZ() * 400)); +} + + + + + +void cProtocol_1_12_1::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3f); // Entity Equipment packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + // Needs to be adjusted due to the insertion of offhand at slot 1 + if (a_SlotNum > 0) + { + a_SlotNum++; + } + Pkt.WriteVarInt32(static_cast<UInt32>(a_SlotNum)); + WriteItem(Pkt, a_Item); +} + + + + + +void cProtocol_1_12_1::SendExperience(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x40); // Set Experience packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEFloat(Player->GetXpPercentage()); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetXpLevel())); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetCurrentXp())); +} + + + + + +void cProtocol_1_12_1::SendHealth(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x41); // Update Health packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteBEFloat(static_cast<float>(Player->GetHealth())); + Pkt.WriteVarInt32(static_cast<UInt32>(Player->GetFoodLevel())); + Pkt.WriteBEFloat(static_cast<float>(Player->GetFoodSaturationLevel())); +} + + + + + +void cProtocol_1_12_1::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x42); // Scoreboard Objective packet + Pkt.WriteString(a_Name); + Pkt.WriteBEUInt8(a_Mode); + if ((a_Mode == 0) || (a_Mode == 2)) + { + Pkt.WriteString(a_DisplayName); + Pkt.WriteString("integer"); + } +} + + + + + +void cProtocol_1_12_1::SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) +{ + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x43); // Set Passengers packet + Pkt.WriteVarInt32(a_Vehicle.GetUniqueID()); + Pkt.WriteVarInt32(1); // 1 passenger + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); +} + + + + + +void cProtocol_1_12_1::SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) +{ + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x43); // Set Passengers packet + Pkt.WriteVarInt32(a_PreviousVehicle.GetUniqueID()); + Pkt.WriteVarInt32(0); // No passangers +} + + + + + +void cProtocol_1_12_1::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x45); // Update Score packet + Pkt.WriteString(a_Player); + Pkt.WriteBEUInt8(a_Mode); + Pkt.WriteString(a_Objective); + + if (a_Mode != 1) + { + Pkt.WriteVarInt32(static_cast<UInt32>(a_Score)); + } +} + + + + + +void cProtocol_1_12_1::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +{ + // Send the Join Game packet: + { + cServer * Server = cRoot::Get()->GetServer(); + cPacketizer Pkt(*this, 0x23); // Join Game packet + Pkt.WriteBEUInt32(a_Player.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Player.GetEffectiveGameMode()) | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteBEInt32(static_cast<Int32>(a_World.GetDimension())); + Pkt.WriteBEUInt8(2); // TODO: Difficulty (set to Normal) + Pkt.WriteBEUInt8(static_cast<UInt8>(Clamp<size_t>(Server->GetMaxPlayers(), 0, 255))); + Pkt.WriteString("default"); // Level type - wtf? + Pkt.WriteBool(false); // Reduced Debug Info - wtf? + } + + // Send the spawn position: + { + cPacketizer Pkt(*this, 0x46); // Spawn Position packet + Pkt.WritePosition64(FloorC(a_World.GetSpawnX()), FloorC(a_World.GetSpawnY()), FloorC(a_World.GetSpawnZ())); + } + + // Send the server difficulty: + { + cPacketizer Pkt(*this, 0x0d); // Server difficulty packet + Pkt.WriteBEInt8(1); + } + + // Send player abilities: + SendPlayerAbilities(); +} + + + + + +void cProtocol_1_12_1::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) +{ + ASSERT(m_State == 3); // In game mode? + if (!a_DoDaylightCycle) + { + // When writing a "-" before the number the client ignores it but it will stop the client-side time expiration. + a_TimeOfDay = std::min(-a_TimeOfDay, -1LL); + } + + cPacketizer Pkt(*this, 0x47); // Time update packet + Pkt.WriteBEInt64(a_WorldAge); + Pkt.WriteBEInt64(a_TimeOfDay); +} + + + + + +void cProtocol_1_12_1::SendSetRawTitle(const AString & a_Title) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(0); // Set title + + Pkt.WriteString(a_Title); +} + + + + + +void cProtocol_1_12_1::SendSetRawSubTitle(const AString & a_SubTitle) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(1); // Set subtitle + + Pkt.WriteString(a_SubTitle); +} + + + + + +void cProtocol_1_12_1::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(3); // Set title display times + Pkt.WriteBEInt32(a_FadeInTicks); + Pkt.WriteBEInt32(a_DisplayTicks); + Pkt.WriteBEInt32(a_FadeOutTicks); +} + + + + + +void cProtocol_1_12_1::SendHideTitle(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(4); // Hide title +} + + + + + +void cProtocol_1_12_1::SendResetTitle(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x48); // Title packet + Pkt.WriteVarInt32(5); // Reset title +} + + + + + +void cProtocol_1_12_1::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4b); // Collect Item packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteVarInt32(a_Player.GetUniqueID()); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Count)); +} + + + + + +void cProtocol_1_12_1::SendTeleportEntity(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4c); // Entity teleport packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEDouble(a_Entity.GetPosX()); + Pkt.WriteBEDouble(a_Entity.GetPosY()); + Pkt.WriteBEDouble(a_Entity.GetPosZ()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); + Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteBool(a_Entity.IsOnGround()); +} + + + + + +void cProtocol_1_12_1::SendEntityProperties(const cEntity & a_Entity) +{ + ASSERT(m_State == 3); // In game mode? + + + cPacketizer Pkt(*this, 0x4e); // Entity Properties packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + WriteEntityProperties(Pkt, a_Entity); +} + + + + + +void cProtocol_1_12_1::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4f); // Entity Effect packet + Pkt.WriteVarInt32(a_Entity.GetUniqueID()); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_EffectID)); + Pkt.WriteBEUInt8(static_cast<UInt8>(a_Amplifier)); + Pkt.WriteVarInt32(static_cast<UInt32>(a_Duration)); + Pkt.WriteBool(false); // Hide particles +} + + + + + +void cProtocol_1_12_1::SendPlayerMaxSpeed(void) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x4e); // Entity Properties + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteVarInt32(Player->GetUniqueID()); + Pkt.WriteBEInt32(1); // Count + Pkt.WriteString("generic.movementSpeed"); + // The default game speed is 0.1, multiply that value by the relative speed: + Pkt.WriteBEDouble(0.1 * Player->GetNormalMaxSpeed()); + if (Player->IsSprinting()) + { + Pkt.WriteVarInt32(1); // Modifier count + Pkt.WriteBEUInt64(0x662a6b8dda3e4c1c); + Pkt.WriteBEUInt64(0x881396ea6097278d); // UUID of the modifier + Pkt.WriteBEDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); + Pkt.WriteBEUInt8(2); + } + else + { + Pkt.WriteVarInt32(0); // Modifier count + } +} + + + + + +bool cProtocol_1_12_1::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) +{ + switch (m_State) + { + case 1: + { + // Status + switch (a_PacketType) + { + case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true; + case 0x01: HandlePacketStatusPing(a_ByteBuffer); return true; + } + break; + } + + case 2: + { + // Login + switch (a_PacketType) + { + case 0x00: HandlePacketLoginStart(a_ByteBuffer); return true; + case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true; + } + break; + } + + case 3: + { + // Game + switch (a_PacketType) + { + case 0x00: HandleConfirmTeleport(a_ByteBuffer); return true; + case 0x01: HandlePacketTabComplete(a_ByteBuffer); return true; + case 0x02: HandlePacketChatMessage(a_ByteBuffer); return true; + case 0x03: HandlePacketClientStatus(a_ByteBuffer); return true; + case 0x04: HandlePacketClientSettings(a_ByteBuffer); return true; + case 0x05: break; // Confirm transaction - not used in Cuberite + case 0x06: HandlePacketEnchantItem(a_ByteBuffer); return true; + case 0x07: HandlePacketWindowClick(a_ByteBuffer); return true; + case 0x08: HandlePacketWindowClose(a_ByteBuffer); return true; + case 0x09: HandlePacketPluginMessage(a_ByteBuffer); return true; + case 0x0a: HandlePacketUseEntity(a_ByteBuffer); return true; + case 0x0b: HandlePacketKeepAlive(a_ByteBuffer); return true; + case 0x0c: HandlePacketPlayer(a_ByteBuffer); return true; + case 0x0d: HandlePacketPlayerPos(a_ByteBuffer); return true; + case 0x0e: HandlePacketPlayerPosLook(a_ByteBuffer); return true; + case 0x0f: HandlePacketPlayerLook(a_ByteBuffer); return true; + case 0x10: HandlePacketVehicleMove(a_ByteBuffer); return true; + case 0x11: HandlePacketBoatSteer(a_ByteBuffer); return true; + case 0x12: break; // Craft Recipe Request - not yet implemented + case 0x13: HandlePacketPlayerAbilities(a_ByteBuffer); return true; + case 0x14: HandlePacketBlockDig(a_ByteBuffer); return true; + case 0x15: HandlePacketEntityAction(a_ByteBuffer); return true; + case 0x16: HandlePacketSteerVehicle(a_ByteBuffer); return true; + case 0x17: HandlePacketCraftingBookData(a_ByteBuffer); return true; + case 0x18: break; // Resource pack status - not yet implemented + case 0x19: HandlePacketAdvancementTab(a_ByteBuffer); return true; + case 0x1a: HandlePacketSlotSelect(a_ByteBuffer); return true; + case 0x1b: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; + case 0x1c: HandlePacketUpdateSign(a_ByteBuffer); return true; + case 0x1d: HandlePacketAnimation(a_ByteBuffer); return true; + case 0x1e: HandlePacketSpectate(a_ByteBuffer); return true; + case 0x1f: HandlePacketBlockPlace(a_ByteBuffer); return true; + case 0x20: HandlePacketUseItem(a_ByteBuffer); return true; + } + break; + } + default: + { + // Received a packet in an unknown state, report: + LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State); + + // Cannot kick the client - we don't know this state and thus the packet number for the kick packet + + // Switch to a state when all further packets are silently ignored: + m_State = 255; + return false; + } + case 255: + { + // This is the state used for "not processing packets anymore" when we receive a bad packet from a client. + // Do not output anything (the caller will do that for us), just return failure + return false; + } + } // switch (m_State) + + // Unknown packet type, report to the ClientHandle: + m_Client->PacketUnknown(a_PacketType); + return false; +} + + + + diff --git a/src/Protocol/Protocol_1_12.h b/src/Protocol/Protocol_1_12.h index 4d90e2183..53ff05aa6 100644 --- a/src/Protocol/Protocol_1_12.h +++ b/src/Protocol/Protocol_1_12.h @@ -5,6 +5,8 @@ Declares the 1.12 protocol classes: - cProtocol_1_12 - release 1.12 protocol (#335) + - cProtocol_1_12_1 + - release 1.12.1 protocol (#338) (others may be added later in the future for the 1.12 release series) */ @@ -69,3 +71,60 @@ protected: virtual void WriteEntityMetadata(cPacketizer & a_Pkt, const cEntity & a_Entity) override; virtual void WriteMobMetadata(cPacketizer & a_Pkt, const cMonster & a_Mob) override; }; + + + + + +class cProtocol_1_12_1 : + public cProtocol_1_12 +{ + typedef cProtocol_1_12 super; + +public: + cProtocol_1_12_1(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); + + virtual void SendRespawn(eDimension a_Dimension) override; + virtual void SendPlayerListAddPlayer(const cPlayer & a_Player) override; + virtual void SendPlayerListRemovePlayer(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdateGameMode(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdatePing(const cPlayer & a_Player) override; + virtual void SendPlayerListUpdateDisplayName(const cPlayer & a_Player, const AString & a_CustomName) override; + virtual void SendPlayerAbilities(void) override; + virtual void SendPlayerMoveLook(void) override; + virtual void SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void SendDestroyEntity(const cEntity & a_Entity) override; + virtual void SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) override; + virtual void SendEntityHeadLook(const cEntity & a_Entity) override; + virtual void SendCameraSetTo(const cEntity & a_Entity) override; + virtual void SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override; + virtual void SendEntityMetadata(const cEntity & a_Entity) override; + virtual void SendEntityVelocity(const cEntity & a_Entity) override; + virtual void SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override; + virtual void SendExperience(void) override; + virtual void SendHealth(void) override; + virtual void SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; + virtual void SendAttachEntity(const cEntity & a_Entity, const cEntity & a_Vehicle) override; + virtual void SendDetachEntity(const cEntity & a_Entity, const cEntity & a_PreviousVehicle) override; + virtual void SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override; + virtual void SendLogin(const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override; + virtual void SendHideTitle(void) override; + virtual void SendResetTitle(void) override; + virtual void SendSetRawSubTitle(const AString & a_SubTitle) override; + virtual void SendSetRawTitle(const AString & a_Title) override; + virtual void SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override; + virtual void SendCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, int a_Count) override; + virtual void SendTeleportEntity(const cEntity & a_Entity) override; + virtual void SendEntityProperties(const cEntity & a_Entity) override; + virtual void SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) override; + virtual void SendPlayerMaxSpeed(void) override; + +protected: + virtual bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) override; + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override; +}; + + + + diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index f578e0e65..873ed2902 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -2883,14 +2883,10 @@ void cProtocol_1_8_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metada } else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag { - AString Lore; - for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings { - AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent / backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;) + a_Item.m_LoreTable.push_back(NBT.GetString(loretag)); } - - a_Item.m_Lore = Lore; } else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) { @@ -3079,15 +3075,9 @@ void cProtocol_1_8_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { Writer.BeginList("Lore", TAG_String); - AStringVector Decls = StringSplit(a_Item.m_Lore, "`"); - for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + for (const auto & Line : a_Item.m_LoreTable) { - if (itr->empty()) - { - // The decl is empty (two `s), ignore - continue; - } - Writer.AddString("", itr->c_str()); + Writer.AddString("", Line); } Writer.EndList(); diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp index 3e0171b24..56f41ec51 100644 --- a/src/Protocol/Protocol_1_9.cpp +++ b/src/Protocol/Protocol_1_9.cpp @@ -2999,14 +2999,11 @@ void cProtocol_1_9_0::ParseItemMetadata(cItem & a_Item, const AString & a_Metada } else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag { - AString Lore; - + a_Item.m_LoreTable.clear(); for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings { - AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent / backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;) + a_Item.m_LoreTable.push_back(NBT.GetString(loretag)); } - - a_Item.m_Lore = Lore; } else if ((NBT.GetType(displaytag) == TAG_Int) && (NBT.GetName(displaytag) == "color")) { @@ -3342,15 +3339,9 @@ void cProtocol_1_9_0::WriteItem(cPacketizer & a_Pkt, const cItem & a_Item) { Writer.BeginList("Lore", TAG_String); - AStringVector Decls = StringSplit(a_Item.m_Lore, "`"); - for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + for (const auto & Line : a_Item.m_LoreTable) { - if (itr->empty()) - { - // The decl is empty (two `s), ignore - continue; - } - Writer.AddString("", itr->c_str()); + Writer.AddString("", Line); } Writer.EndList(); diff --git a/src/SetChunkData.cpp b/src/SetChunkData.cpp index cb530b3b6..c218c361c 100644 --- a/src/SetChunkData.cpp +++ b/src/SetChunkData.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "SetChunkData.h" #include "BlockEntities/BlockEntity.h" +#include "Entities/Entity.h" diff --git a/src/SetChunkData.h b/src/SetChunkData.h index b0c59e40b..c608a8f61 100644 --- a/src/SetChunkData.h +++ b/src/SetChunkData.h @@ -115,11 +115,3 @@ protected: bool m_AreBiomesValid; bool m_ShouldMarkDirty; }; - -typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; -typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; - - - - - diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index d21e8dc6d..c3e262dec 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -78,9 +78,9 @@ cDelayedFluidSimulator::cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Flu -void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cDelayedFluidSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { - if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + if ((a_Block.y < 0) || (a_Block.y >= cChunkDef::Height)) { // Not inside the world (may happen when rclk with a full bucket - the client sends Y = -1) return; @@ -91,9 +91,9 @@ void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if (BlockType != m_FluidBlock) { return; @@ -104,7 +104,7 @@ void cDelayedFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cDelayedFluidSimulatorChunkData::cSlot & Slot = ChunkData->m_Slots[m_AddSlotNum]; // Add, if not already present: - if (!Slot.Add(RelX, a_BlockY, RelZ)) + if (!Slot.Add(RelX, a_Block.y, RelZ)) { return; } diff --git a/src/Simulator/DelayedFluidSimulator.h b/src/Simulator/DelayedFluidSimulator.h index 62efb717e..78619a608 100644 --- a/src/Simulator/DelayedFluidSimulator.h +++ b/src/Simulator/DelayedFluidSimulator.h @@ -54,7 +54,7 @@ public: cDelayedFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, int a_TickDelay); // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; virtual void Simulate(float a_Dt) override; virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; virtual cFluidSimulatorData * CreateChunkData(void) override { return new cDelayedFluidSimulatorChunkData(m_TickDelay); } diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 55dd7008b..45969bd0a 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -218,16 +218,16 @@ bool cFireSimulator::DoesBurnForever(BLOCKTYPE a_BlockType) -void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cFireSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if (!IsAllowedBlock(BlockType)) { return; @@ -237,15 +237,15 @@ void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * cFireSimulatorChunkData & ChunkData = a_Chunk->GetFireSimulatorData(); for (cCoordWithIntList::iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr) { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) + if ((itr->x == RelX) && (itr->y == a_Block.y) && (itr->z == RelZ)) { // Already present, skip adding return; } } // for itr - ChunkData[] - FLOG("FS: Adding block {%d, %d, %d}", a_BlockX, a_BlockY, a_BlockZ); - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ, 100)); + FLOG("FS: Adding block {%d, %d, %d}", a_Block.x, a_Block.y, a_Block.z); + ChunkData.push_back(cCoordWithInt(RelX, a_Block.y, RelZ, 100)); } diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h index 5c926e6ea..bbfeb045e 100644 --- a/src/Simulator/FireSimulator.h +++ b/src/Simulator/FireSimulator.h @@ -43,7 +43,7 @@ protected: int m_ReplaceFuelChance; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; /** Returns the time [msec] after which the specified fire block is stepped again; based on surrounding fuels */ int GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 8d712824f..d24b6aa9b 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -325,7 +325,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i // Spread: FLOG(" Spreading to {%d, %d, %d} with meta %d", BlockX, a_RelY, BlockZ, a_NewMeta); a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); - m_World.GetSimulatorManager()->WakeUp(BlockX, a_RelY, BlockZ, a_NearChunk); + m_World.GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, a_NearChunk); HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); } diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h index a869b3489..e00db39b5 100644 --- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h @@ -31,9 +31,9 @@ public: return IsRedstone(a_BlockType); } - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - m_Data.WakeUp({ a_BlockX, a_BlockY, a_BlockZ }); + m_Data.WakeUp(a_Block); } /** Returns if a block is a mechanism (something that accepts power and does something) diff --git a/src/Simulator/NoopFluidSimulator.h b/src/Simulator/NoopFluidSimulator.h index a237e960b..11bbf061d 100644 --- a/src/Simulator/NoopFluidSimulator.h +++ b/src/Simulator/NoopFluidSimulator.h @@ -27,11 +27,9 @@ public: } // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); + UNUSED(a_Block); UNUSED(a_Chunk); } virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} diff --git a/src/Simulator/NoopRedstoneSimulator.h b/src/Simulator/NoopRedstoneSimulator.h index a5d9e9448..d9e8e00f5 100644 --- a/src/Simulator/NoopRedstoneSimulator.h +++ b/src/Simulator/NoopRedstoneSimulator.h @@ -27,11 +27,9 @@ public: UNUSED(a_Chunk); } virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType) override { return false; } - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override { - UNUSED(a_BlockX); - UNUSED(a_BlockY); - UNUSED(a_BlockZ); + UNUSED(a_Block); UNUSED(a_Chunk); } diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index cee43db60..2f6b32398 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -33,7 +33,7 @@ public: virtual void Simulate(float a_Dt) = 0; virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0; virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0; - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) = 0; virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0; diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index 6b1219edb..01e699b49 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -60,11 +60,11 @@ void cSandSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, Pos.x, Pos.y, Pos.z, ItemTypeToString(BlockType).c_str(), ItemTypeToString(BlockBelow).c_str() ); */ - cFallingBlock * FallingBlock = new cFallingBlock(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); - if (!FallingBlock->Initialize(m_World)) + + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Pos, BlockType, a_Chunk->GetMeta(itr->x, itr->y, itr->z)); + auto FallingBlockPtr = FallingBlock.get(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), m_World)) { - delete FallingBlock; - FallingBlock = nullptr; continue; } a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); @@ -101,15 +101,15 @@ bool cSandSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType) -void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSandSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if ((a_Chunk == nullptr) || !a_Chunk->IsValid()) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ))) + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_Block.y, RelZ))) { return; } @@ -118,14 +118,14 @@ void cSandSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * cSandSimulatorChunkData & ChunkData = a_Chunk->GetSandSimulatorData(); for (cSandSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) + if ((itr->x == RelX) && (itr->y == a_Block.y) && (itr->z == RelZ)) { return; } } m_TotalBlocks += 1; - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ)); + ChunkData.push_back(cCoordWithInt(RelX, a_Block.y, RelZ)); } diff --git a/src/Simulator/SandSimulator.h b/src/Simulator/SandSimulator.h index cda26775e..cee0a85e6 100644 --- a/src/Simulator/SandSimulator.h +++ b/src/Simulator/SandSimulator.h @@ -59,7 +59,7 @@ protected: int m_TotalBlocks; // Total number of blocks currently in the queue for simulating - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; /** Performs the instant fall of the block - removes it from top, Finishes it at the bottom */ void DoInstantFall(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp index 7d3ce7851..9dbdd6a07 100644 --- a/src/Simulator/Simulator.cpp +++ b/src/Simulator/Simulator.cpp @@ -18,20 +18,20 @@ -void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSimulator::WakeUp(Vector3i a_Block, cChunk * a_Chunk) { - AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); - AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockZ)); - AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockZ)); - AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 1)); - AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 1)); - if (a_BlockY > 0) + AddBlock(a_Block, a_Chunk); + AddBlock(a_Block + Vector3i(-1, 0, 0), a_Chunk->GetNeighborChunk(a_Block.x - 1, a_Block.z)); + AddBlock(a_Block + Vector3i( 1, 0, 0), a_Chunk->GetNeighborChunk(a_Block.x + 1, a_Block.z)); + AddBlock(a_Block + Vector3i(0, 0, -1), a_Chunk->GetNeighborChunk(a_Block.x, a_Block.z - 1)); + AddBlock(a_Block + Vector3i(0, 0, 1), a_Chunk->GetNeighborChunk(a_Block.x, a_Block.z + 1)); + if (a_Block.y > 0) { - AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk); + AddBlock(a_Block + Vector3i(0, -1, 0), a_Chunk); } - if (a_BlockY < cChunkDef::Height - 1) + if (a_Block.y < cChunkDef::Height - 1) { - AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk); + AddBlock(a_Block + Vector3i(0, 1, 0), a_Chunk); } } @@ -47,12 +47,11 @@ void cSimulator::WakeUpArea(const cCuboid & a_Area) area.ClampY(0, cChunkDef::Height - 1); // Add all blocks, in a per-chunk manner: - int chunkStartX, chunkStartZ, chunkEndX, chunkEndZ; - cChunkDef::BlockToChunk(area.p1.x, area.p1.z, chunkStartX, chunkStartZ); - cChunkDef::BlockToChunk(area.p2.x, area.p2.z, chunkEndX, chunkEndZ); - for (int cz = chunkStartZ; cz <= chunkEndZ; ++cz) + cChunkCoords ChunkStart = cChunkDef::BlockToChunk(area.p1); + cChunkCoords ChunkEnd = cChunkDef::BlockToChunk(area.p2); + for (int cz = ChunkStart.m_ChunkZ; cz <= ChunkEnd.m_ChunkZ; ++cz) { - for (int cx = chunkStartX; cx <= chunkEndX; ++cx) + for (int cx = ChunkStart.m_ChunkX; cx <= ChunkEnd.m_ChunkX; ++cx) { m_World.DoWithChunk(cx, cz, [this, &area](cChunk & a_CBChunk) -> bool { @@ -73,7 +72,7 @@ void cSimulator::WakeUpArea(const cCuboid & a_Area) { for (int x = startX; x <= endX; ++x) { - AddBlock(x, y, z, &a_CBChunk); + AddBlock({x, y, z}, &a_CBChunk); } // for x } // for z } // for y diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h index ef0a3bf68..669680693 100644 --- a/src/Simulator/Simulator.h +++ b/src/Simulator/Simulator.h @@ -39,7 +39,7 @@ public: } /** Called when a block changes */ - void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + void WakeUp(Vector3i a_Block, cChunk * a_Chunk); /** Does the same processing as WakeUp, but for all blocks within the specified area. Has better performance than calling WakeUp for each block individually, due to neighbor-checking. @@ -55,7 +55,7 @@ protected: friend class cChunk; // Calls AddBlock() in its WakeUpSimulators() function, to speed things up /** Called to simulate a new block */ - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) = 0; cWorld & m_World; } ; diff --git a/src/Simulator/SimulatorManager.cpp b/src/Simulator/SimulatorManager.cpp index 78c02fc07..a2740f707 100644 --- a/src/Simulator/SimulatorManager.cpp +++ b/src/Simulator/SimulatorManager.cpp @@ -58,11 +58,11 @@ void cSimulatorManager::SimulateChunk(std::chrono::milliseconds a_Dt, int a_Chun -void cSimulatorManager::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cSimulatorManager::WakeUp(Vector3i a_Block, cChunk * a_Chunk) { for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr) { - itr->first->WakeUp(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); + itr->first->WakeUp(a_Block, a_Chunk); } } diff --git a/src/Simulator/SimulatorManager.h b/src/Simulator/SimulatorManager.h index daa949157..98a60b4ee 100644 --- a/src/Simulator/SimulatorManager.h +++ b/src/Simulator/SimulatorManager.h @@ -36,7 +36,7 @@ public: void SimulateChunk(std::chrono::milliseconds a_DT, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk); /* Called when a single block changes, wakes all simulators up for the block and its face-neighbors. */ - void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk); + void WakeUp(Vector3i a_Block, cChunk * a_Chunk); /** Does the same processing as WakeUp, but for all blocks within the specified area. Has better performance than calling WakeUp for each block individually, due to neighbor-checking. diff --git a/src/Simulator/VaporizeFluidSimulator.cpp b/src/Simulator/VaporizeFluidSimulator.cpp index 1d2db58fb..c023f88c9 100644 --- a/src/Simulator/VaporizeFluidSimulator.cpp +++ b/src/Simulator/VaporizeFluidSimulator.cpp @@ -20,26 +20,26 @@ cVaporizeFluidSimulator::cVaporizeFluidSimulator(cWorld & a_World, BLOCKTYPE a_F -void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cVaporizeFluidSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) { if (a_Chunk == nullptr) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ); + int RelX = a_Block.x - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_Block.z - a_Chunk->GetPosZ() * cChunkDef::Width; + BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_Block.y, RelZ); if ( (BlockType == m_FluidBlock) || (BlockType == m_StationaryFluidBlock) ) { - a_Chunk->SetBlock(RelX, a_BlockY, RelZ, E_BLOCK_AIR, 0); + a_Chunk->SetBlock(RelX, a_Block.y, RelZ, E_BLOCK_AIR, 0); a_Chunk->BroadcastSoundEffect( "block.fire.extinguish", - static_cast<double>(a_BlockX), - static_cast<double>(a_BlockY), - static_cast<double>(a_BlockZ), + static_cast<double>(a_Block.x), + static_cast<double>(a_Block.y), + static_cast<double>(a_Block.z), 1.0f, 0.6f ); diff --git a/src/Simulator/VaporizeFluidSimulator.h b/src/Simulator/VaporizeFluidSimulator.h index 8076972a8..7a7006309 100644 --- a/src/Simulator/VaporizeFluidSimulator.h +++ b/src/Simulator/VaporizeFluidSimulator.h @@ -25,7 +25,7 @@ public: cVaporizeFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid); // cSimulator overrides: - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; virtual void Simulate(float a_Dt) override; } ; diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 42d736a8c..b7e446d53 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -228,6 +228,42 @@ AStringVector StringSplitWithQuotes(const AString & str, const AString & delim) + +AString StringJoin(const AStringVector & a_Strings, const AString & a_Delimeter) +{ + if (a_Strings.empty()) + { + return {}; + } + + // Do a dry run to gather the size + const auto DelimSize = a_Delimeter.size(); + size_t ResultSize = a_Strings[0].size(); + std::for_each(a_Strings.begin() + 1, a_Strings.end(), + [&](const AString & a_String) + { + ResultSize += DelimSize; + ResultSize += a_String.size(); + } + ); + + // Now do the actual join + AString Result; + Result.reserve(ResultSize); + Result.append(a_Strings[0]); + std::for_each(a_Strings.begin() + 1, a_Strings.end(), + [&](const AString & a_String) + { + Result += a_Delimeter; + Result += a_String; + } + ); + return Result; +} + + + + AStringVector StringSplitAndTrim(const AString & str, const AString & delim) { AStringVector results; diff --git a/src/StringUtils.h b/src/StringUtils.h index b59dde41a..12227014d 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -47,6 +47,9 @@ Resolves issue #490 Return the splitted strings as a stringvector. */ extern AStringVector StringSplitWithQuotes(const AString & str, const AString & delim); +/** Join a list of strings with the given delimiter between entries. */ +AString StringJoin(const AStringVector & a_Strings, const AString & a_Delimiter); + /** Split the string at any of the listed delimiters and trim each value. Returns the splitted strings as a stringvector. */ extern AStringVector StringSplitAndTrim(const AString & str, const AString & delim); diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp index e889f9c44..7b3fe15af 100644 --- a/src/UI/ChestWindow.cpp +++ b/src/UI/ChestWindow.cpp @@ -76,12 +76,12 @@ cChestWindow::~cChestWindow() bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) { m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1); - m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPos()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1); - m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPos()); } cWindow::ClosedByPlayer(a_Player, a_CanRefuse); @@ -95,12 +95,12 @@ bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) void cChestWindow::OpenedByPlayer(cPlayer & a_Player) { m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1); - m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ()); + m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPos()); if (m_SecondaryChest != nullptr) { m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1); - m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ()); + m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPos()); } cWindow::OpenedByPlayer(a_Player); diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 5a94a26af..be21cdada 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -9,7 +9,8 @@ #pragma once #include "../Inventory.h" -#include "Window.h" + + diff --git a/src/UI/Window.h b/src/UI/Window.h index 5bb90a75e..d7a29dc47 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -113,7 +113,7 @@ public: void GetSlots(cPlayer & a_Player, cItems & a_Slots) const; /** Handles a click event from a player */ - void Clicked( + virtual void Clicked( cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem diff --git a/src/World.cpp b/src/World.cpp index f11aee878..738761aa6 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -999,9 +999,10 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La for (auto & Entity : m_EntitiesToAdd) { Entity->SetWorld(this); - m_ChunkMap->AddEntity(Entity); - ASSERT(!Entity->IsTicking()); - Entity->SetIsTicking(true); + auto EntityPtr = Entity.get(); + m_ChunkMap->AddEntity(std::move(Entity)); + ASSERT(!EntityPtr->IsTicking()); + EntityPtr->SetIsTicking(true); } m_EntitiesToAdd.clear(); } @@ -1114,7 +1115,7 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt) // do the spawn for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2) { - SpawnMobFinalize(*itr2); + SpawnMobFinalize(std::move(const_cast<std::unique_ptr<cMonster> &>(*itr2))); } } } // for i - AllFamilies[] @@ -1288,9 +1289,9 @@ void cWorld::UpdateSkyDarkness(void) -void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) +void cWorld::WakeUpSimulators(Vector3i a_Block) { - return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + return m_ChunkMap->WakeUpSimulators(a_Block); } @@ -1299,7 +1300,17 @@ void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) void cWorld::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ) { - m_SimulatorManager->WakeUpArea(cCuboid(a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ)); + LOGWARNING("cWorld::WakeUpSimulatorsInArea(int, int, int) is deprecated, use cWorld::WakeUpSimulatorsInArea(Vector3i) instead."); + WakeUpSimulatorsInArea(cCuboid({a_MinBlockX, a_MinBlockY, a_MinBlockZ}, {a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ})); +} + + + + + +void cWorld::WakeUpSimulatorsInArea(const cCuboid & a_Area) +{ + m_SimulatorManager->WakeUpArea(a_Area); } @@ -1550,7 +1561,7 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback -bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) +bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback) { struct cCallBackWrapper : cChunkCallback { @@ -2176,15 +2187,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double float SpeedY = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(50)); float SpeedZ = static_cast<float>(a_FlyAwaySpeed * Random.RandInt(-5, 5)); - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2201,15 +2209,12 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double continue; } - cPickup * Pickup = new cPickup( + auto Pickup = cpp14::make_unique<cPickup>( a_BlockX, a_BlockY, a_BlockZ, *itr, IsPlayerCreated, static_cast<float>(a_SpeedX), static_cast<float>(a_SpeedY), static_cast<float>(a_SpeedZ) ); - if (!Pickup->Initialize(*this)) - { - delete Pickup; - Pickup = nullptr; - } + auto PickupPtr = Pickup.get(); + PickupPtr->Initialize(std::move(Pickup), *this); } } @@ -2219,14 +2224,13 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, float a_SpeedX, float a_SpeedY, float a_SpeedZ, int a_LifetimeTicks, bool a_CanCombine) { - cPickup * Pickup = new cPickup(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); - if (!Pickup->Initialize(*this)) + auto Pickup = cpp14::make_unique<cPickup>(a_PosX, a_PosY, a_PosZ, a_Item, false, a_SpeedX, a_SpeedY, a_SpeedZ, a_LifetimeTicks, a_CanCombine); + auto PickupPtr = Pickup.get(); + if (!PickupPtr->Initialize(std::move(Pickup), *this)) { - delete Pickup; - Pickup = nullptr; return cEntity::INVALID_ID; } - return Pickup->GetUniqueID(); + return PickupPtr->GetUniqueID(); } @@ -2235,14 +2239,14 @@ UInt32 cWorld::SpawnItemPickup(double a_PosX, double a_PosY, double a_PosZ, cons UInt32 cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta) { - cFallingBlock * FallingBlock = new cFallingBlock(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); - if (!FallingBlock->Initialize(*this)) + auto FallingBlock = cpp14::make_unique<cFallingBlock>(Vector3i(a_X, a_Y, a_Z), BlockType, BlockMeta); + auto FallingBlockPtr = FallingBlock.get(); + auto ID = FallingBlock->GetUniqueID(); + if (!FallingBlockPtr->Initialize(std::move(FallingBlock), *this)) { - delete FallingBlock; - FallingBlock = nullptr; return cEntity::INVALID_ID; } - return FallingBlock->GetUniqueID(); + return ID; } @@ -2257,14 +2261,13 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa return cEntity::INVALID_ID; } - cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); - if (!ExpOrb->Initialize(*this)) + auto ExpOrb = cpp14::make_unique<cExpOrb>(a_X, a_Y, a_Z, a_Reward); + auto ExpOrbPtr = ExpOrb.get(); + if (!ExpOrbPtr->Initialize(std::move(ExpOrb), *this)) { - delete ExpOrb; - ExpOrb = nullptr; return cEntity::INVALID_ID; } - return ExpOrb->GetUniqueID(); + return ExpOrbPtr->GetUniqueID(); } @@ -2273,26 +2276,26 @@ UInt32 cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Rewa UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) { - cMinecart * Minecart; + std::unique_ptr<cMinecart> Minecart; switch (a_MinecartType) { - case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; - case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break; - case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break; - case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break; + case E_ITEM_MINECART: Minecart = cpp14::make_unique<cRideableMinecart>(a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; + case E_ITEM_CHEST_MINECART: Minecart = cpp14::make_unique<cMinecartWithChest>(a_X, a_Y, a_Z); break; + case E_ITEM_FURNACE_MINECART: Minecart = cpp14::make_unique<cMinecartWithFurnace>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_TNT: Minecart = cpp14::make_unique<cMinecartWithTNT>(a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_HOPPER: Minecart = cpp14::make_unique<cMinecartWithHopper>(a_X, a_Y, a_Z); break; default: { return cEntity::INVALID_ID; } } // switch (a_MinecartType) - if (!Minecart->Initialize(*this)) + + auto MinecartPtr = Minecart.get(); + if (!MinecartPtr->Initialize(std::move(Minecart), *this)) { - delete Minecart; - Minecart = nullptr; return cEntity::INVALID_ID; } - return Minecart->GetUniqueID(); + return MinecartPtr->GetUniqueID(); } @@ -2301,18 +2304,13 @@ UInt32 cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartT UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_Material) { - cBoat * Boat = new cBoat(a_X, a_Y, a_Z, a_Material); - if (Boat == nullptr) + auto Boat = cpp14::make_unique<cBoat>(a_X, a_Y, a_Z, a_Material); + auto BoatPtr = Boat.get(); + if (!BoatPtr->Initialize(std::move(Boat), *this)) { return cEntity::INVALID_ID; } - if (!Boat->Initialize(*this)) - { - delete Boat; - Boat = nullptr; - return cEntity::INVALID_ID; - } - return Boat->GetUniqueID(); + return BoatPtr->GetUniqueID(); } @@ -2320,20 +2318,20 @@ UInt32 cWorld::SpawnBoat(double a_X, double a_Y, double a_Z, cBoat::eMaterial a_ UInt32 cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff) { - cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks); - if (!TNT->Initialize(*this)) + auto TNT = cpp14::make_unique<cTNTEntity>(a_X, a_Y, a_Z, a_FuseTicks); + auto TNTPtr = TNT.get(); + if (!TNTPtr->Initialize(std::move(TNT), *this)) { - delete TNT; - TNT = nullptr; return cEntity::INVALID_ID; } + auto & Random = GetRandomProvider(); - TNT->SetSpeed( + TNTPtr->SetSpeed( a_InitialVelocityCoeff * Random.RandInt(-1, 1), a_InitialVelocityCoeff * 2, a_InitialVelocityCoeff * Random.RandInt(-1, 1) ); - return TNT->GetUniqueID(); + return TNTPtr->GetUniqueID(); } @@ -2902,7 +2900,7 @@ void cWorld::QueueSetChunkData(cSetChunkDataPtr a_SetChunkData) // Store a copy of the data in the queue: // TODO: If the queue is too large, wait for it to get processed. Not likely, though. cCSLock Lock(m_CSSetChunkDataQueue); - m_SetChunkDataQueue.push_back(std::move(a_SetChunkData)); + m_SetChunkDataQueue.emplace_back(std::move(a_SetChunkData)); } @@ -2917,15 +2915,10 @@ void cWorld::SetChunkData(cSetChunkData & a_SetChunkData) m_ChunkMap->SetChunkData(a_SetChunkData); // Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347): - cEntityList Entities; - std::swap(a_SetChunkData.GetEntities(), Entities); - for (cEntityList::iterator itr = Entities.begin(), end = Entities.end(); itr != end; ++itr) + for (auto & Entity : a_SetChunkData.GetEntities()) { - if (!(*itr)->Initialize(*this)) - { - delete *itr; - *itr = nullptr; - } + auto EntityPtr = Entity.get(); + EntityPtr->Initialize(std::move(Entity), *this); } // If a client is requesting this chunk, send it to them: @@ -3046,39 +3039,41 @@ void cWorld::CollectPickupsByPlayer(cPlayer & a_Player) -void cWorld::AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld) +void cWorld::AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld) { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.emplace_back(a_Player, a_OldWorld); + m_PlayersToAdd.emplace_back(std::move(a_Player), a_OldWorld); } -void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) +std::unique_ptr<cPlayer> cWorld::RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk) { + std::unique_ptr<cPlayer> PlayerPtr; + if (a_RemoveFromChunk) { // To prevent iterator invalidations when an entity goes through a portal and calls this function whilst being ticked by cChunk // we should not change cChunk's entity list if asked not to - m_ChunkMap->RemoveEntity(a_Player); + PlayerPtr = std::unique_ptr<cPlayer>(static_cast<cPlayer *>(m_ChunkMap->RemoveEntity(a_Player).release())); } { cCSLock Lock(m_CSPlayersToAdd); - m_PlayersToAdd.remove_if([&](const std::pair< cPlayer *, cWorld * > & value) -> bool + m_PlayersToAdd.remove_if([&](const decltype(m_PlayersToAdd)::value_type & value) -> bool { - return (value.first == a_Player); + return (value.first.get() == &a_Player); }); } { cCSLock Lock(m_CSPlayers); - LOGD("Removing player %s from world \"%s\"", a_Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.remove(a_Player); + LOGD("Removing player %s from world \"%s\"", a_Player.GetName().c_str(), m_WorldName.c_str()); + m_Players.remove(&a_Player); } // Remove the player's client from the list of clients to be ticked: - cClientHandle * Client = a_Player->GetClientHandle(); + cClientHandle * Client = a_Player.GetClientHandle(); if (Client != nullptr) { Client->RemoveFromWorld(); @@ -3086,12 +3081,66 @@ void cWorld::RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk) cCSLock Lock(m_CSClients); m_ClientsToRemove.push_back(Client); } + + return PlayerPtr; } +#ifdef _DEBUG +bool cWorld::IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player) +{ + if (m_ChunkMap->RemoveEntity(a_Player) != nullptr) + { + return true; + } + + { + cCSLock Lock(m_CSPlayersToAdd); + if (std::find_if( + m_PlayersToAdd.begin(), m_PlayersToAdd.end(), + [&a_Player](const cAwaitingPlayerList::value_type & Item) { return Item.first.get() == &a_Player; }) != m_PlayersToAdd.end() + ) + { + return true; + } + } + + { + cCSLock Lock(m_CSPlayers); + if (std::find(m_Players.begin(), m_Players.end(), &a_Player) != m_Players.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSEntitiesToAdd); + if (std::find(m_ClientsToAdd.begin(), m_ClientsToAdd.end(), a_Player.GetClientHandlePtr()) != m_ClientsToAdd.end()) + { + return true; + } + } + + { + cCSLock Lock(m_CSClients); + if (std::find(m_Clients.begin(), m_Clients.end(), a_Player.GetClientHandlePtr()) != m_Clients.end()) + { + return true; + } + } + + // Assume OK if in ClientsToRemove or PlayersToRemove + return false; +} +#endif + + + + + bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback) { // Calls the callback for each player in the list @@ -3204,7 +3253,7 @@ bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallb -cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight) +cPlayer * cWorld::FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight) { double ClosestDistance = a_SightLimit; cPlayer * ClosestPlayer = nullptr; @@ -3303,11 +3352,11 @@ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callbac // First check the entities-to-add: { cCSLock Lock(m_CSEntitiesToAdd); - for (auto & ent: m_EntitiesToAdd) + for (const auto & ent: m_EntitiesToAdd) { if (ent->GetUniqueID() == a_UniqueID) { - a_Callback(ent); + a_Callback(ent.get()); return true; } } // for ent - m_EntitiesToAdd[] @@ -3600,11 +3649,11 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas -void cWorld::AddEntity(cEntity * a_Entity) +void cWorld::AddEntity(OwnedEntity a_Entity) { a_Entity->SetWorld(this); cCSLock Lock(m_CSEntitiesToAdd); - m_EntitiesToAdd.push_back(a_Entity); + m_EntitiesToAdd.emplace_back(std::move(a_Entity)); } @@ -3739,9 +3788,7 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ) UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby) { - cMonster * Monster = nullptr; - - Monster = cMonster::NewMonsterFromType(a_MonsterType); + auto Monster = cMonster::NewMonsterFromType(a_MonsterType); if (Monster == nullptr) { return cEntity::INVALID_ID; @@ -3753,13 +3800,13 @@ UInt32 cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterTyp Monster->SetAge(-1); } - return SpawnMobFinalize(Monster); + return SpawnMobFinalize(std::move(Monster)); } -UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) +UInt32 cWorld::SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster) { ASSERT(a_Monster != nullptr); @@ -3769,22 +3816,20 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) // A plugin doesn't agree with the spawn. bail out. if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } + auto & Monster = *a_Monster; + // Initialize the monster into the current world. - if (!a_Monster->Initialize(*this)) + if (!Monster.Initialize(std::move(a_Monster), *this)) { - delete a_Monster; - a_Monster = nullptr; return cEntity::INVALID_ID; } - cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, Monster); - return a_Monster->GetUniqueID(); + return Monster.GetUniqueID(); } @@ -3793,18 +3838,19 @@ UInt32 cWorld::SpawnMobFinalize(cMonster * a_Monster) UInt32 cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed) { - cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); + auto Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); if (Projectile == nullptr) { return cEntity::INVALID_ID; } - if (!Projectile->Initialize(*this)) + + auto ProjectilePtr = Projectile.get(); + if (!ProjectilePtr->Initialize(std::move(Projectile), *this)) { - delete Projectile; - Projectile = nullptr; return cEntity::INVALID_ID; } - return Projectile->GetUniqueID(); + + return ProjectilePtr->GetUniqueID(); } @@ -4000,29 +4046,35 @@ void cWorld::AddQueuedPlayers(void) std::swap(PlayersToAdd, m_PlayersToAdd); } + // Temporary (#3115-will-fix): store pointers to player objects after ownership transferral + std::vector<std::pair<cPlayer *, cWorld *>> AddedPlayerPtrs; + AddedPlayerPtrs.reserve(PlayersToAdd.size()); + // Add all the players in the grabbed list: { cCSLock Lock(m_CSPlayers); for (auto & AwaitingPlayer : PlayersToAdd) { auto & Player = AwaitingPlayer.first; - ASSERT(std::find(m_Players.begin(), m_Players.end(), Player) == m_Players.end()); // Is it already in the list? HOW? + ASSERT(std::find(m_Players.begin(), m_Players.end(), Player.get()) == m_Players.end()); // Is it already in the list? HOW? LOGD("Adding player %s to world \"%s\".", Player->GetName().c_str(), m_WorldName.c_str()); - m_Players.push_back(Player); + m_Players.push_back(Player.get()); Player->SetWorld(this); // Add to chunkmap, if not already there (Spawn vs MoveToWorld): - m_ChunkMap->AddEntityIfNotPresent(Player); - ASSERT(!Player->IsTicking()); - Player->SetIsTicking(true); + auto PlayerPtr = Player.get(); + m_ChunkMap->AddEntityIfNotPresent(std::move(Player)); + ASSERT(!PlayerPtr->IsTicking()); + PlayerPtr->SetIsTicking(true); + AddedPlayerPtrs.emplace_back(PlayerPtr, AwaitingPlayer.second); } // for itr - PlayersToAdd[] } // Lock(m_CSPlayers) // Add all the players' clienthandles: { cCSLock Lock(m_CSClients); - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandlePtr Client = Player->GetClientHandlePtr(); @@ -4034,7 +4086,7 @@ void cWorld::AddQueuedPlayers(void) } // Lock(m_CSClients) // Stream chunks to all eligible clients: - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { auto & Player = AwaitingPlayer.first; cClientHandle * Client = Player->GetClientHandle(); @@ -4047,7 +4099,7 @@ void cWorld::AddQueuedPlayers(void) } // for itr - PlayersToAdd[] // Call EntityChangedWorld callback on all eligible clients - for (auto & AwaitingPlayer : PlayersToAdd) + for (auto & AwaitingPlayer : AddedPlayerPtrs) { if (AwaitingPlayer.second != nullptr) { @@ -4077,14 +4129,14 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc cChunkDef::BlockNibbles BlockMetas; a_ChunkDesc.CompressBlockMetas(BlockMetas); - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), a_ChunkDesc.GetBlockTypes(), BlockMetas, nullptr, nullptr, // We don't have lighting, chunk will be lighted when needed &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), std::move(a_ChunkDesc.GetEntities()), std::move(a_ChunkDesc.GetBlockEntities()), true - )); + ); SetChunkData->RemoveInvalidBlockEntities(); m_World->QueueSetChunkData(std::move(SetChunkData)); } diff --git a/src/World.h b/src/World.h index a53d3471c..8ff64046d 100644 --- a/src/World.h +++ b/src/World.h @@ -40,19 +40,19 @@ class cChunkGenerator; // The thread responsible for generating chunks class cBeaconEntity; class cBrewingstandEntity; class cChestEntity; +class cCuboid; class cDispenserEntity; class cFlowerPotEntity; class cFurnaceEntity; class cNoteEntity; class cMobHeadEntity; class cCompositeChat; -class cCuboid; class cSetChunkData; class cBroadcaster; class cDeadlockDetect; typedef std::list< cPlayer * > cPlayerList; -typedef std::list< std::pair< cPlayer *, cWorld * > > cAwaitingPlayerList; +typedef std::list< std::pair< std::unique_ptr<cPlayer>, cWorld * > > cAwaitingPlayerList; typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; @@ -258,13 +258,18 @@ public: Uses a queue to store the player object until the Tick thread processes the addition event. Also adds the player as an entity in the chunkmap, and the player's ClientHandle, if any, for ticking. If a_OldWorld is provided, a corresponding ENTITY_CHANGED_WORLD event is triggerred after the addition. */ - void AddPlayer(cPlayer * a_Player, cWorld * a_OldWorld = nullptr); + void AddPlayer(std::unique_ptr<cPlayer> a_Player, cWorld * a_OldWorld = nullptr); /** Removes the player from the world. Removes the player from the addition queue, too, if appropriate. If the player has a ClientHandle, the ClientHandle is removed from all chunks in the world and will not be ticked by this world anymore. - @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. */ - void RemovePlayer(cPlayer * a_Player, bool a_RemoveFromChunk); + @param a_RemoveFromChunk determines if the entity should be removed from its chunk as well. Should be false when ticking from cChunk. + @return An owning reference to the given player. */ + std::unique_ptr<cPlayer> RemovePlayer(cPlayer & a_Player, bool a_RemoveFromChunk); + +#ifdef _DEBUG + bool IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player); +#endif /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS << @@ -277,7 +282,7 @@ public: bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) - cPlayer * FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); + cPlayer * FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); /** Finds the player over his uuid and calls the callback */ bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << @@ -287,7 +292,7 @@ public: /** Adds the entity into its appropriate chunk; takes ownership of the entity ptr. The entity is added lazily - this function only puts it in a queue that is then processed by the Tick thread. */ - void AddEntity(cEntity * a_Entity); + void AddEntity(OwnedEntity a_Entity); /** Returns true if an entity with the specified UniqueID exists in the world. Note: Only loaded chunks are considered. */ @@ -412,11 +417,11 @@ public: // tolua_begin // Vector3i variants: - void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); } - BLOCKTYPE GetBlock (const Vector3i & a_Pos) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z); } - NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z); } - void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData); } - NIBBLETYPE GetBlockBlockLight(const Vector3i & a_Pos) { return GetBlockBlockLight( a_Pos.x, a_Pos.y, a_Pos.z); } + void FastSetBlock(Vector3i a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta); } + BLOCKTYPE GetBlock (Vector3i a_Pos) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z); } + NIBBLETYPE GetBlockMeta(Vector3i a_Pos) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z); } + void SetBlockMeta(Vector3i a_Pos, NIBBLETYPE a_MetaData) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData); } + NIBBLETYPE GetBlockBlockLight(Vector3i a_Pos) { return GetBlockBlockLight( a_Pos.x, a_Pos.y, a_Pos.z); } // tolua_end /** Writes the block area into the specified coords. @@ -484,9 +489,19 @@ public: double GetSpawnZ(void) const { return m_SpawnZ; } /** Wakes up the simulators for the specified block */ - virtual void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) override; + virtual void WakeUpSimulators(Vector3i a_Block) override; /** Wakes up the simulators for the specified area of blocks */ + void WakeUpSimulatorsInArea(const cCuboid & a_Area); + + // DEPRECATED, use vector-parametered version instead + void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) + { + LOGWARNING("cWorld::WakeUpSimulators(int, int, int) is deprecated, use cWorld::WakeUpSimulators(Vector3i) instead."); + WakeUpSimulators({a_BlockX, a_BlockY, a_BlockZ}); + } + + // DEPRECATED, use vector-parametered version instead void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); // tolua_end @@ -791,7 +806,9 @@ public: /** Spawns a mob of the specified type. Returns the mob's UniqueID if recognized and spawned, cEntity::INVALID_ID otherwise */ virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby = false) override; // tolua_export - UInt32 SpawnMobFinalize(cMonster * a_Monster); + /** Wraps cEntity::Initialize, doing Monster-specific things before spawning the monster. + Takes ownership of the given Monster reference. */ + UInt32 SpawnMobFinalize(std::unique_ptr<cMonster> a_Monster); /** Creates a projectile of the specified type. Returns the projectile's UniqueID if successful, cEntity::INVALID_ID otherwise Item parameter is currently used for Fireworks to correctly set entity metadata based on item metadata. */ diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index d474f59e1..480558fa3 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -107,7 +107,7 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) || (a_Item.m_RepairCost > 0) || (a_Item.m_CustomName != "") || - (a_Item.m_Lore != "") + (!a_Item.m_LoreTable.empty()) ) { m_Writer.BeginCompound("tag"); @@ -116,16 +116,23 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin m_Writer.AddInt("RepairCost", a_Item.m_RepairCost); } - if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != "")) + if ((a_Item.m_CustomName != "") || (!a_Item.m_LoreTable.empty())) { m_Writer.BeginCompound("display"); if (a_Item.m_CustomName != "") { m_Writer.AddString("Name", a_Item.m_CustomName); } - if (a_Item.m_Lore != "") + if (!a_Item.m_LoreTable.empty()) { - m_Writer.AddString("Lore", a_Item.m_Lore); + m_Writer.BeginList("Lore", TAG_String); + + for (const auto & Line : a_Item.m_LoreTable) + { + m_Writer.AddString("", Line); + } + + m_Writer.EndList(); } m_Writer.EndCompound(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 16688b712..77d1e46b8 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -458,7 +458,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT } // for y //*/ - cSetChunkDataPtr SetChunkData(new cSetChunkData( + auto SetChunkData = cpp14::make_unique<cSetChunkData>( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : nullptr, @@ -466,7 +466,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT nullptr, Biomes, std::move(Entities), std::move(BlockEntities), false - )); + ); m_World->QueueSetChunkData(std::move(SetChunkData)); return true; } @@ -804,7 +804,17 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ int Lore = a_NBT.FindChildByName(DisplayTag, "Lore"); if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String)) { - a_Item.m_Lore = a_NBT.GetString(Lore); + // Legacy string lore + a_Item.m_LoreTable = StringSplit(a_NBT.GetString(Lore), "`"); + } + else if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_List)) + { + // Lore table + a_Item.m_LoreTable.clear(); + for (int loretag = a_NBT.GetFirstChild(Lore); loretag >= 0; loretag = a_NBT.GetNextSibling(loretag)) // Loop through array of strings + { + a_Item.m_LoreTable.push_back(a_NBT.GetString(loretag)); + } } } @@ -1655,7 +1665,7 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N { Boat->SetMaterial(cBoat::StringToMaterial(a_NBT.GetString(TypeIdx))); } - a_Entities.push_back(Boat.release()); + a_Entities.emplace_back(std::move(Boat)); } @@ -1669,7 +1679,7 @@ void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(EnderCrystal.release()); + a_Entities.emplace_back(std::move(EnderCrystal)); } @@ -1694,7 +1704,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN { return; } - a_Entities.push_back(FallingBlock.release()); + a_Entities.emplace_back(std::move(FallingBlock)); } @@ -1708,7 +1718,7 @@ void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT { return; } - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1740,7 +1750,7 @@ void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT Minecart->SetSlot(a_NBT.GetByte(Slot), Item); } } // for itr - ItemDefs[] - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1757,7 +1767,7 @@ void cWSSAnvil::LoadMinecartFFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Load the Push and Fuel tags - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1774,7 +1784,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with TNT carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1791,7 +1801,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT // TODO: Everything to do with hopper carts - a_Entities.push_back(Minecart.release()); + a_Entities.emplace_back(std::move(Minecart)); } @@ -1825,7 +1835,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a Pickup->SetAge(a_NBT.GetShort(Age)); } - a_Entities.push_back(Pickup.release()); + a_Entities.emplace_back(std::move(Pickup)); } @@ -1847,7 +1857,7 @@ void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB TNT->SetFuseTicks(static_cast<int>(a_NBT.GetByte(FuseTicks))); } - a_Entities.push_back(TNT.release()); + a_Entities.emplace_back(std::move(TNT)); } @@ -1876,7 +1886,7 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a ExpOrb->SetReward(a_NBT.GetShort(Reward)); } - a_Entities.push_back(ExpOrb.release()); + a_Entities.emplace_back(std::move(ExpOrb)); } @@ -1941,7 +1951,7 @@ void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT ItemFrame->SetItemRotation(static_cast<Byte>(a_NBT.GetByte(Rotation))); } - a_Entities.push_back(ItemFrame.release()); + a_Entities.emplace_back(std::move(ItemFrame)); } @@ -1964,7 +1974,7 @@ void cWSSAnvil::LoadPaintingFromNBT(cEntityList & a_Entities, const cParsedNBT & } LoadHangingFromNBT(*Painting.get(), a_NBT, a_TagIdx); - a_Entities.push_back(Painting.release()); + a_Entities.emplace_back(std::move(Painting)); } @@ -2035,7 +2045,7 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ } // Store the new arrow in the entities list: - a_Entities.push_back(Arrow.release()); + a_Entities.emplace_back(std::move(Arrow)); } @@ -2058,7 +2068,7 @@ void cWSSAnvil::LoadSplashPotionFromNBT(cEntityList & a_Entities, const cParsedN SplashPotion->SetPotionColor(a_NBT.FindChildByName(a_TagIdx, "PotionName")); // Store the new splash potion in the entities list: - a_Entities.push_back(SplashPotion.release()); + a_Entities.emplace_back(std::move(SplashPotion)); } @@ -2074,7 +2084,7 @@ void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new snowball in the entities list: - a_Entities.push_back(Snowball.release()); + a_Entities.emplace_back(std::move(Snowball)); } @@ -2090,7 +2100,7 @@ void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB } // Store the new egg in the entities list: - a_Entities.push_back(Egg.release()); + a_Entities.emplace_back(std::move(Egg)); } @@ -2106,7 +2116,7 @@ void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & } // Store the new fireball in the entities list: - a_Entities.push_back(Fireball.release()); + a_Entities.emplace_back(std::move(Fireball)); } @@ -2122,7 +2132,7 @@ void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT } // Store the new FireCharge in the entities list: - a_Entities.push_back(FireCharge.release()); + a_Entities.emplace_back(std::move(FireCharge)); } @@ -2138,7 +2148,7 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar } // Store the new enderpearl in the entities list: - a_Entities.push_back(Enderpearl.release()); + a_Entities.emplace_back(std::move(Enderpearl)); } @@ -2158,7 +2168,7 @@ void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2178,7 +2188,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2198,7 +2208,7 @@ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2218,7 +2228,7 @@ void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2238,7 +2248,7 @@ void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2258,7 +2268,7 @@ void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2278,7 +2288,7 @@ void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNB return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2298,7 +2308,7 @@ void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2318,7 +2328,7 @@ void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2338,7 +2348,7 @@ void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2358,7 +2368,7 @@ void cWSSAnvil::LoadGuardianFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2404,7 +2414,7 @@ void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2424,7 +2434,7 @@ void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2453,7 +2463,7 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2473,7 +2483,7 @@ void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2527,7 +2537,7 @@ void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2560,7 +2570,7 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2604,7 +2614,7 @@ void cWSSAnvil::LoadRabbitFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2650,7 +2660,7 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2670,7 +2680,7 @@ void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2698,7 +2708,7 @@ void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2727,7 +2737,7 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2747,7 +2757,7 @@ void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2767,7 +2777,7 @@ void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2787,7 +2797,7 @@ void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2829,7 +2839,7 @@ void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2849,7 +2859,7 @@ void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ return; } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2875,7 +2885,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetWitherInvulnerableTicks(static_cast<unsigned int>(a_NBT.GetInt(CurrLine))); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2951,7 +2961,7 @@ void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -2992,7 +3002,7 @@ void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } @@ -3025,7 +3035,7 @@ void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT Monster->SetAge(Age); } - a_Entities.push_back(Monster.release()); + a_Entities.emplace_back(std::move(Monster)); } diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 37ccdda4c..454e6f73d 100755 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -10,7 +10,6 @@ #include "WorldStorage.h" #include "FastNBT.h" -#include "../Mobs/Monster.h" @@ -18,7 +17,7 @@ // fwd: ItemGrid.h class cItemGrid; - +class cMonster; class cProjectileEntity; class cHangingEntity; |