From c2d91726a740958cbdc304b4ad77a4de3a555eff Mon Sep 17 00:00:00 2001 From: OLEGSHA Date: Wed, 13 Jan 2021 14:36:18 +0300 Subject: [PATCH] Formatted source, added/updated copyright headers - Also added formatting settings for Eclipse IDE --- buildPackages.sh | 18 + docs/building/EclipseGuide.md | 14 +- .../opensimplex2/areagen/OpenSimplex2S.java | 17 +- .../java/ru/windcorp/jputil/ArrayUtil.java | 1260 ++++----- .../java/ru/windcorp/jputil/CSVWriter.java | 71 +- .../ru/windcorp/jputil/PrimitiveUtil.java | 54 +- .../java/ru/windcorp/jputil/SyncStreams.java | 2480 +++++++++-------- .../ru/windcorp/jputil/SyntaxException.java | 89 +- .../jputil/chars/CharArrayIterator.java | 260 +- .../windcorp/jputil/chars/CharConsumer.java | 85 +- .../windcorp/jputil/chars/CharConsumers.java | 139 +- .../windcorp/jputil/chars/CharPredicate.java | 169 +- .../windcorp/jputil/chars/CharSupplier.java | 71 +- .../jputil/chars/EscapeException.java | 89 +- .../ru/windcorp/jputil/chars/Escaper.java | 988 +++---- .../jputil/chars/FancyCharacterIterator.java | 94 +- .../jputil/chars/IndentedStringBuilder.java | 273 +- .../ru/windcorp/jputil/chars/StringUtil.java | 1972 ++++++------- .../chars/UncheckedEscapeException.java | 75 +- .../ru/windcorp/jputil/chars/WordReader.java | 282 +- .../chars/reader/AbstractCharReader.java | 212 +- .../jputil/chars/reader/ArrayCharReader.java | 119 +- .../chars/reader/BufferedCharReader.java | 250 +- .../jputil/chars/reader/CharReader.java | 554 ++-- .../jputil/chars/reader/CharReaders.java | 225 +- .../jputil/chars/reader/ReaderCharReader.java | 141 +- .../jputil/chars/reader/StringCharReader.java | 133 +- .../jputil/functions/FloatSupplier.java | 34 +- .../jputil/functions/ThrowingBiConsumer.java | 148 +- .../jputil/functions/ThrowingConsumer.java | 134 +- .../jputil/functions/ThrowingFunction.java | 154 +- .../jputil/functions/ThrowingRunnable.java | 129 +- .../jputil/functions/ThrowingSupplier.java | 102 +- .../jputil/iterators/ArrayIterator.java | 95 +- .../jputil/iterators/FunctionIterator.java | 122 +- .../jputil/iterators/PeekingIterator.java | 122 +- .../jputil/iterators/RangeIterator.java | 137 +- .../windcorp/jputil/iterators/Reiterator.java | 142 +- .../selectors/AbstractSelectorOperator.java | 79 +- .../selectors/NamedParameterizedSelector.java | 115 +- .../jputil/selectors/NamedSelector.java | 101 +- .../jputil/selectors/OperatorAnd.java | 73 +- .../jputil/selectors/OperatorExclude.java | 73 +- .../jputil/selectors/OperatorNot.java | 69 +- .../windcorp/jputil/selectors/OperatorOr.java | 73 +- .../jputil/selectors/OperatorXor.java | 73 +- .../jputil/selectors/PredicateWrapper.java | 73 +- .../windcorp/jputil/selectors/Selector.java | 57 +- .../jputil/selectors/SelectorOperator.java | 59 +- .../jputil/selectors/SelectorSystem.java | 351 ++- .../ru/windcorp/progressia/Progressia.java | 45 +- .../progressia/ProgressiaLauncher.java | 101 +- .../java/ru/windcorp/progressia/Proxy.java | 49 +- .../ru/windcorp/progressia/client/Client.java | 138 +- .../progressia/client/ClientProxy.java | 124 +- .../progressia/client/ClientState.java | 111 +- .../client/ProgressiaClientMain.java | 57 +- .../progressia/client/audio/AudioFormat.java | 20 +- .../progressia/client/audio/AudioManager.java | 50 +- .../progressia/client/audio/AudioSystem.java | 28 +- .../progressia/client/audio/Music.java | 122 +- .../progressia/client/audio/SoundEffect.java | 132 +- .../client/audio/backend/AudioReader.java | 43 +- .../client/audio/backend/Listener.java | 37 +- .../client/audio/backend/SoundType.java | 26 +- .../client/audio/backend/Speaker.java | 254 +- .../comms/DefaultClientCommsListener.java | 110 +- .../client/comms/ServerCommsChannel.java | 32 +- .../client/comms/controls/ControlTrigger.java | 40 +- .../controls/ControlTriggerInputBased.java | 46 +- .../comms/controls/ControlTriggerLambda.java | 115 +- .../controls/ControlTriggerRegistry.java | 45 +- .../comms/controls/ControlTriggers.java | 266 +- .../comms/controls/InputBasedControls.java | 84 +- .../client/comms/localhost/LocalClient.java | 100 +- .../localhost/LocalServerCommsChannel.java | 102 +- .../progressia/client/graphics/Colors.java | 123 +- .../progressia/client/graphics/GUI.java | 263 +- .../progressia/client/graphics/Layer.java | 163 +- .../client/graphics/backend/FaceCulling.java | 31 +- .../graphics/backend/GraphicsBackend.java | 258 +- .../graphics/backend/GraphicsInterface.java | 150 +- .../client/graphics/backend/InputHandler.java | 365 +-- .../client/graphics/backend/InputTracker.java | 147 +- .../graphics/backend/LWJGLInitializer.java | 220 +- .../graphics/backend/OpenGLObjectTracker.java | 193 +- .../graphics/backend/RenderTaskQueue.java | 110 +- .../client/graphics/backend/RenderThread.java | 159 +- .../client/graphics/backend/Usage.java | 77 +- .../graphics/backend/VertexBufferObject.java | 399 +-- .../backend/shaders/CombinedShader.java | 188 +- .../graphics/backend/shaders/Program.java | 129 +- .../graphics/backend/shaders/Shader.java | 211 +- .../backend/shaders/attributes/Attribute.java | 99 +- .../attributes/AttributeVertexArray.java | 268 +- .../backend/shaders/uniforms/Uniform.java | 179 +- .../shaders/uniforms/Uniform1Float.java | 87 +- .../backend/shaders/uniforms/Uniform1Int.java | 87 +- .../shaders/uniforms/Uniform2Float.java | 97 +- .../backend/shaders/uniforms/Uniform2Int.java | 97 +- .../shaders/uniforms/Uniform2Matrix.java | 79 +- .../shaders/uniforms/Uniform3Float.java | 97 +- .../backend/shaders/uniforms/Uniform3Int.java | 97 +- .../shaders/uniforms/Uniform3Matrix.java | 93 +- .../shaders/uniforms/Uniform4Float.java | 97 +- .../backend/shaders/uniforms/Uniform4Int.java | 97 +- .../shaders/uniforms/Uniform4Matrix.java | 93 +- .../graphics/flat/AssembledFlatLayer.java | 126 +- .../flat/AssembledFlatRenderHelper.java | 71 +- .../flat/DefaultFlatRenderHelper.java | 137 +- .../client/graphics/flat/FlatGraphics.java | 47 +- .../graphics/flat/FlatRenderHelper.java | 89 +- .../graphics/flat/FlatRenderProgram.java | 212 +- .../progressia/client/graphics/flat/Mask.java | 188 +- .../client/graphics/flat/MaskStack.java | 93 +- .../client/graphics/flat/RenderTarget.java | 609 ++-- .../client/graphics/flat/TransformedMask.java | 301 +- .../progressia/client/graphics/font/Font.java | 323 ++- .../client/graphics/font/GNUUnifont.java | 29 +- .../graphics/font/GNUUnifontLoader.java | 72 +- .../client/graphics/font/SpriteTypeface.java | 404 +-- .../client/graphics/font/Typeface.java | 223 +- .../client/graphics/font/Typefaces.java | 48 +- .../client/graphics/gui/Component.java | 1326 ++++----- .../client/graphics/gui/DynamicLabel.java | 18 + .../client/graphics/gui/GUILayer.java | 121 +- .../progressia/client/graphics/gui/Label.java | 201 +- .../client/graphics/gui/Layout.java | 57 +- .../progressia/client/graphics/gui/Panel.java | 38 +- .../graphics/gui/event/ChildAddedEvent.java | 57 +- .../client/graphics/gui/event/ChildEvent.java | 71 +- .../graphics/gui/event/ChildRemovedEvent.java | 57 +- .../graphics/gui/event/ComponentEvent.java | 69 +- .../client/graphics/gui/event/FocusEvent.java | 71 +- .../graphics/gui/event/HierarchyEvent.java | 57 +- .../client/graphics/gui/event/HoverEvent.java | 79 +- .../gui/event/ParentChangedEvent.java | 83 +- .../graphics/gui/layout/LayoutAlign.java | 41 +- .../gui/layout/LayoutBorderHorizontal.java | 70 +- .../gui/layout/LayoutBorderVertical.java | 72 +- .../graphics/gui/layout/LayoutGrid.java | 87 +- .../graphics/gui/layout/LayoutHorizontal.java | 33 +- .../graphics/gui/layout/LayoutVertical.java | 31 +- .../client/graphics/input/CursorEvent.java | 89 +- .../graphics/input/CursorMoveEvent.java | 233 +- .../graphics/input/FrameResizeEvent.java | 171 +- .../client/graphics/input/InputEvent.java | 77 +- .../client/graphics/input/KeyEvent.java | 213 +- .../client/graphics/input/KeyMatcher.java | 192 +- .../client/graphics/input/Keys.java | 294 +- .../client/graphics/input/WheelEvent.java | 59 +- .../graphics/input/WheelScrollEvent.java | 151 +- .../client/graphics/input/bus/Input.java | 123 +- .../client/graphics/input/bus/InputBus.java | 176 +- .../graphics/input/bus/InputListener.java | 55 +- .../graphics/model/BlockFaceVectors.java | 240 +- .../client/graphics/model/DynamicModel.java | 250 +- .../client/graphics/model/EmptyModel.java | 89 +- .../client/graphics/model/Face.java | 508 ++-- .../client/graphics/model/FaceGroup.java | 40 +- .../client/graphics/model/Faces.java | 215 +- .../client/graphics/model/LambdaModel.java | 272 +- .../client/graphics/model/Model.java | 95 +- .../client/graphics/model/Renderable.java | 49 +- .../client/graphics/model/Shape.java | 502 ++-- .../graphics/model/ShapeRenderHelper.java | 171 +- .../graphics/model/ShapeRenderProgram.java | 734 ++--- .../client/graphics/model/Shapes.java | 561 ++-- .../client/graphics/model/StaticModel.java | 174 +- .../client/graphics/texture/Atlases.java | 25 +- .../graphics/texture/ComplexTexture.java | 163 +- .../graphics/texture/SimpleTexture.java | 67 +- .../graphics/texture/SimpleTextures.java | 28 +- .../client/graphics/texture/Sprite.java | 137 +- .../client/graphics/texture/Texture.java | 49 +- .../client/graphics/texture/TextureData.java | 213 +- .../graphics/texture/TextureDataEditor.java | 214 +- .../graphics/texture/TextureLoader.java | 88 +- .../graphics/texture/TexturePrimitive.java | 222 +- .../graphics/texture/TextureSettings.java | 65 +- .../client/graphics/texture/TextureUtil.java | 125 +- .../client/graphics/world/Camera.java | 613 ++-- .../client/graphics/world/EntityAnchor.java | 154 +- .../client/graphics/world/LayerWorld.java | 435 +-- .../client/graphics/world/LocalPlayer.java | 48 +- .../client/graphics/world/Selection.java | 46 +- .../graphics/world/WorldRenderHelper.java | 124 +- .../graphics/world/WorldRenderProgram.java | 630 +++-- .../client/localization/LocaleListener.java | 20 +- .../client/localization/Localizer.java | 24 +- .../client/localization/MutableString.java | 29 +- .../localization/MutableStringConcat.java | 22 +- .../localization/MutableStringFormatter.java | 18 + .../localization/MutableStringFunc.java | 18 + .../localization/MutableStringLocalized.java | 18 + .../localization/MutableStringParented.java | 20 +- .../client/localization/Parser.java | 29 +- .../progressia/client/world/ChunkRender.java | 619 ++-- .../client/world/ChunkUpdateListener.java | 22 +- .../progressia/client/world/WorldRender.java | 456 ++- .../client/world/block/BlockRender.java | 91 +- .../client/world/block/BlockRenderNone.java | 79 +- .../world/block/BlockRenderOpaqueCube.java | 136 +- .../world/block/BlockRenderRegistry.java | 103 +- .../world/block/BlockRenderTexturedCube.java | 145 +- .../block/BlockRenderTransparentCube.java | 136 +- .../world/cro/ChunkRenderOptimizer.java | 88 +- .../world/cro/ChunkRenderOptimizerCube.java | 554 ++-- .../cro/ChunkRenderOptimizerSupplier.java | 89 +- .../world/cro/ChunkRenderOptimizers.java | 103 +- .../client/world/entity/EntityRender.java | 46 +- .../world/entity/EntityRenderRegistry.java | 89 +- .../client/world/entity/EntityRenderable.java | 86 +- .../client/world/entity/HumanoidModel.java | 256 +- .../client/world/entity/NPedModel.java | 190 +- .../client/world/entity/QuadripedModel.java | 174 +- .../client/world/tile/TileRender.java | 86 +- .../client/world/tile/TileRenderGrass.java | 138 +- .../world/tile/TileRenderOpaqueSurface.java | 18 + .../client/world/tile/TileRenderRegistry.java | 102 +- .../client/world/tile/TileRenderStack.java | 28 +- .../client/world/tile/TileRenderSurface.java | 117 +- .../tile/TileRenderTransparentSurface.java | 18 + .../ru/windcorp/progressia/common/Units.java | 244 +- .../progressia/common/collision/AABB.java | 89 +- .../progressia/common/collision/AABBoid.java | 25 +- .../common/collision/Collideable.java | 37 +- .../common/collision/CollisionModel.java | 21 +- .../collision/CollisionPathComputer.java | 66 +- .../collision/CompoundCollisionModel.java | 24 +- .../collision/TransformedCollisionModel.java | 30 +- .../common/collision/TranslatedAABB.java | 48 +- .../progressia/common/collision/Wall.java | 23 +- .../collision/WorldCollisionHelper.java | 59 +- .../collision/colliders/AABBoidCollider.java | 191 +- .../AnythingWithCompoundCollider.java | 56 +- .../common/collision/colliders/Collider.java | 356 +-- .../progressia/common/comms/CommsChannel.java | 248 +- .../common/comms/CommsListener.java | 44 +- .../common/comms/controls/ControlData.java | 40 +- .../comms/controls/ControlDataRegistry.java | 44 +- .../common/comms/controls/PacketControl.java | 84 +- .../common/comms/packets/Packet.java | 57 +- .../common/hacks/GuavaEventBusHijacker.java | 57 +- .../progressia/common/resource/Resource.java | 167 +- .../common/resource/ResourceManager.java | 66 +- .../state/AbstractStatefulObjectLayout.java | 190 +- .../common/state/HashMapStateStorage.java | 58 +- .../progressia/common/state/IOContext.java | 36 +- .../state/InspectingStatefulObjectLayout.java | 214 +- .../common/state/IntStateField.java | 144 +- .../common/state/OptimizedStateStorage.java | 60 +- .../state/OptimizedStatefulObjectLayout.java | 155 +- .../common/state/PrimitiveCounters.java | 61 +- .../progressia/common/state/StateChanger.java | 32 +- .../progressia/common/state/StateField.java | 120 +- .../common/state/StateFieldBuilder.java | 65 +- .../progressia/common/state/StateStorage.java | 36 +- .../common/state/StatefulObject.java | 465 ++-- .../common/state/StatefulObjectLayout.java | 117 +- .../common/state/StatefulObjectRegistry.java | 212 +- .../progressia/common/util/BinUtil.java | 79 +- .../common/util/ByteBufferInputStream.java | 109 +- .../common/util/ByteBufferOutputStream.java | 103 +- .../common/util/CoordinatePacker.java | 251 +- .../progressia/common/util/DataBuffer.java | 275 +- .../progressia/common/util/FloatMathUtil.java | 77 +- .../common/util/LowOverheadCache.java | 83 +- .../progressia/common/util/Matrices.java | 146 +- .../progressia/common/util/MultiLOC.java | 26 +- .../progressia/common/util/Named.java | 123 +- .../common/util/SizeLimitedList.java | 162 +- .../progressia/common/util/StashingStack.java | 515 ++-- .../progressia/common/util/TaskQueue.java | 253 +- .../progressia/common/util/VectorUtil.java | 762 ++--- .../progressia/common/util/Vectors.java | 241 +- .../common/util/crash/Analyzer.java | 88 +- .../common/util/crash/ContextProvider.java | 88 +- .../common/util/crash/CrashReports.java | 638 +++-- .../common/util/crash/ReportingEventBus.java | 35 +- .../crash/analyzers/OutOfMemoryAnalyzer.java | 52 +- .../crash/providers/ArgsContextProvider.java | 48 +- .../providers/JavaVersionContextProvider.java | 18 + .../providers/LanguageContextProvider.java | 18 + .../crash/providers/OSContextProvider.java | 58 +- .../providers/OpenALContextProvider.java | 18 + .../crash/providers/RAMContextProvider.java | 24 +- .../common/util/dynstr/DoubleFlusher.java | 53 +- .../common/util/dynstr/DynamicString.java | 102 +- .../common/util/dynstr/DynamicStrings.java | 99 +- .../common/util/dynstr/FloatFlusher.java | 53 +- .../common/util/dynstr/IntFlusher.java | 346 ++- .../util/namespaces/IllegalIdException.java | 25 +- .../common/util/namespaces/Namespaced.java | 127 +- .../namespaces/NamespacedFactoryRegistry.java | 247 +- .../NamespacedInstanceRegistry.java | 245 +- .../util/namespaces/NamespacedUtil.java | 231 +- .../progressia/common/world/BlockRay.java | 97 +- .../progressia/common/world/ChunkData.java | 1117 ++++---- .../common/world/ChunkDataListener.java | 87 +- .../common/world/ChunkDataListeners.java | 27 +- .../progressia/common/world/Coordinates.java | 308 +- .../common/world/DecodingException.java | 19 + .../world/IllegalCoordinatesException.java | 26 +- .../common/world/PacketAffectChunk.java | 18 + .../common/world/PacketAffectWorld.java | 44 +- .../common/world/PacketRevokeChunk.java | 32 +- .../common/world/PacketSendChunk.java | 36 +- .../common/world/PacketSetLocalPlayer.java | 96 +- .../progressia/common/world/PlayerData.java | 22 +- .../progressia/common/world/WorldData.java | 431 +-- .../common/world/WorldDataListener.java | 72 +- .../common/world/block/BlockData.java | 71 +- .../common/world/block/BlockDataRegistry.java | 61 +- .../common/world/block/BlockFace.java | 346 +-- .../common/world/block/BlockRelation.java | 41 +- .../common/world/block/PacketAffectBlock.java | 26 +- .../common/world/block/PacketSetBlock.java | 28 +- .../common/world/entity/EntityData.java | 429 +-- .../world/entity/EntityDataRegistry.java | 52 +- .../world/entity/PacketAffectEntity.java | 28 +- .../world/entity/PacketChangeEntity.java | 152 +- .../world/entity/PacketRevokeEntity.java | 26 +- .../common/world/entity/PacketSendEntity.java | 45 +- .../common/world/generic/ChunkMap.java | 92 +- .../common/world/generic/ChunkSet.java | 126 +- .../common/world/generic/ChunkSets.java | 170 +- .../common/world/generic/GenericBlock.java | 20 +- .../common/world/generic/GenericChunk.java | 100 +- .../common/world/generic/GenericEntity.java | 28 +- .../common/world/generic/GenericTile.java | 20 +- .../world/generic/GenericTileStack.java | 58 +- .../common/world/generic/GenericWorld.java | 92 +- .../world/generic/LongBasedChunkMap.java | 30 +- .../world/generic/LongBasedChunkSet.java | 48 +- .../common/world/io/ChunkCodec.java | 34 +- .../progressia/common/world/io/ChunkIO.java | 85 +- .../common/world/tile/PacketAddTile.java | 32 +- .../common/world/tile/PacketAffectTile.java | 36 +- .../common/world/tile/PacketRemoveTile.java | 47 +- .../common/world/tile/TileData.java | 59 +- .../common/world/tile/TileDataRegistry.java | 61 +- .../common/world/tile/TileDataStack.java | 110 +- .../common/world/tile/TileReference.java | 24 +- .../world/tile/TileStackIsFullException.java | 30 +- .../progressia/server/ChunkLoader.java | 20 +- .../progressia/server/ChunkManager.java | 125 +- .../progressia/server/EntityManager.java | 85 +- .../ru/windcorp/progressia/server/Player.java | 38 +- .../progressia/server/PlayerManager.java | 45 +- .../ru/windcorp/progressia/server/Server.java | 478 ++-- .../progressia/server/ServerState.java | 69 +- .../progressia/server/ServerThread.java | 180 +- .../progressia/server/TickingSettings.java | 23 +- .../progressia/server/comms/Client.java | 62 +- .../progressia/server/comms/ClientChat.java | 18 + .../server/comms/ClientManager.java | 283 +- .../progressia/server/comms/ClientPlayer.java | 38 +- .../comms/DefaultServerCommsListener.java | 96 +- .../server/comms/controls/ControlLogic.java | 94 +- .../comms/controls/ControlLogicRegistry.java | 45 +- .../progressia/server/world/ChunkLogic.java | 383 +-- .../server/world/ChunkTickContext.java | 80 +- .../server/world/TickAndUpdateUtil.java | 103 +- .../progressia/server/world/TickContext.java | 80 +- .../server/world/TickContextMutable.java | 234 +- .../server/world/UpdateTriggerer.java | 32 +- .../progressia/server/world/WorldLogic.java | 219 +- .../server/world/block/BlockLogic.java | 76 +- .../world/block/BlockLogicRegistry.java | 44 +- .../server/world/block/BlockTickContext.java | 209 +- .../server/world/block/TickableBlock.java | 40 +- .../server/world/block/UpdateableBlock.java | 46 +- .../server/world/entity/EntityLogic.java | 52 +- .../world/entity/EntityLogicRegistry.java | 45 +- .../generation/AbstractWorldGenerator.java | 35 +- .../world/generation/WorldGenerator.java | 25 +- .../server/world/tasks/AddTile.java | 20 +- .../world/tasks/BlockTriggeredUpdate.java | 26 +- .../server/world/tasks/CachedBlockChange.java | 35 +- .../server/world/tasks/CachedChange.java | 26 +- .../server/world/tasks/CachedChunkChange.java | 20 +- .../server/world/tasks/CachedEvaluation.java | 26 +- .../server/world/tasks/CachedTileChange.java | 47 +- .../server/world/tasks/CachedWorldChange.java | 28 +- .../server/world/tasks/ChangeEntity.java | 39 +- .../server/world/tasks/RemoveTile.java | 20 +- .../server/world/tasks/SetBlock.java | 20 +- .../server/world/tasks/StateChange.java | 20 +- .../server/world/tasks/TickChunk.java | 121 +- .../server/world/tasks/TickEntitiesTask.java | 20 +- .../world/tasks/TileTriggeredUpdate.java | 38 +- .../server/world/tasks/WorldAccessor.java | 55 +- .../server/world/ticking/Change.java | 40 +- .../world/ticking/DevilInvasionException.java | 20 +- .../server/world/ticking/Evaluation.java | 24 +- .../server/world/ticking/Ticker.java | 91 +- .../world/ticking/TickerCoordinator.java | 165 +- .../server/world/ticking/TickerTask.java | 52 +- .../server/world/ticking/TickingPolicy.java | 45 +- .../server/world/tile/HangingTileLogic.java | 39 +- .../server/world/tile/TSTickContext.java | 72 +- .../server/world/tile/TickableTile.java | 40 +- .../server/world/tile/TileLogic.java | 76 +- .../server/world/tile/TileLogicRegistry.java | 44 +- .../server/world/tile/TileLogicStack.java | 26 +- .../server/world/tile/TileTickContext.java | 131 +- .../server/world/tile/UpdateableTile.java | 32 +- .../test/CollisionModelRenderer.java | 42 +- .../test/ControlBreakBlockData.java | 24 +- .../test/ControlPlaceBlockData.java | 26 +- .../progressia/test/ControlPlaceTileData.java | 28 +- .../windcorp/progressia/test/LayerAbout.java | 59 +- .../progressia/test/LayerTestGUI.java | 729 ++--- .../windcorp/progressia/test/LayerTestUI.java | 319 +-- .../progressia/test/TestBlockLogicAir.java | 24 +- .../progressia/test/TestBlockLogicGlass.java | 18 + .../progressia/test/TestChunkCodec.java | 83 +- .../windcorp/progressia/test/TestContent.java | 805 +++--- .../progressia/test/TestEntityDataStatie.java | 87 +- .../test/TestEntityLogicStatie.java | 64 +- .../test/TestEntityRenderHuman.java | 240 +- .../test/TestEntityRenderJavapony.java | 812 +++--- .../test/TestEntityRenderStatie.java | 101 +- .../progressia/test/TestPlayerControls.java | 719 ++--- .../progressia/test/TestTileLogicGrass.java | 33 +- .../progressia/test/TestWorldDiskIO.java | 117 +- .../test/gen/TestTerrainGenerator.java | 122 +- .../test/gen/TestWorldGenerator.java | 245 +- .../jputil/chars/stringUtil/SplitAtTest.java | 55 +- .../util/BinUtilIsPowerOf2Test.java | 145 +- .../progressia/util/BinUtilRoundTest.java | 153 +- .../util/CoordinatePacker2Test.java | 140 +- .../util/CoordinatePacker3Test.java | 143 +- .../progressia/util/NamespacedTest.java | 345 +-- .../progressia/util/StashingStackTest.java | 204 +- .../eclipse_ide/CodeTemplates.xml | 24 + .../eclipse_ide/FormatterProfile.xml | 382 +++ 438 files changed, 35918 insertions(+), 28764 deletions(-) create mode 100644 templates_and_presets/eclipse_ide/CodeTemplates.xml create mode 100644 templates_and_presets/eclipse_ide/FormatterProfile.xml diff --git a/buildPackages.sh b/buildPackages.sh index 7a0f0dd..f01b54e 100755 --- a/buildPackages.sh +++ b/buildPackages.sh @@ -1,5 +1,23 @@ #!/bin/bash +# +# Progressia +# Copyright (C) 2020-2021 Wind Corporation and contributors +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + echoerr() { echo "$@" 1>&2; } buildDebianPackage() { diff --git a/docs/building/EclipseGuide.md b/docs/building/EclipseGuide.md index 0d3305d..439bb6e 100644 --- a/docs/building/EclipseGuide.md +++ b/docs/building/EclipseGuide.md @@ -100,6 +100,18 @@ Alternatively, specify another location outside of the project's root directory. Step 5 is required to specify that the game must run in some directory other than the project root, which is the default in Eclipse. +### Applying formatting templates + +Windcorp's Progressia repository is formatted with a style defined for Eclipse IDE in +`templates_and_presets/eclipse_ide`. +Please apply these templates to the project to automatically format the source in a similar fashion. + +1. In project context menu, click 'Properties'. +2. In 'Java Code Style' > 'Code Templates', check 'Enable project specific settings', then click 'Import' and select +`templates_and_presets/eclipse_ide/CodeTemplates.xml`. +3. In 'Java Code Style' > 'Formatter', check 'Enable project specific settings', then click 'Import' and select +`templates_and_presets/eclipse_ide/FormatterProfile.xml`. + ## Common problems ### Buildship plugin fails with a cryptic message @@ -110,4 +122,4 @@ searches for Java installations in system path regardless and may fail independe __Solution:__ the simplest solution is to reinstall JDK making sure that system path is affected. See [Build Guide](BuildGuide.md) for details. Another course of action is to manually append the -Java installation directory (specifically its `bin` folder) to the system `PATH` variable. \ No newline at end of file +Java installation directory (specifically its `bin` folder) to the system `PATH` variable. diff --git a/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java b/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java index ff22baf..3a17d8a 100644 --- a/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java +++ b/src/main/java/kdotjpg/opensimplex2/areagen/OpenSimplex2S.java @@ -3,9 +3,11 @@ package kdotjpg.opensimplex2.areagen; * This file has been modified in the following ways: * - added a package declaration at line 1; * - added missing @Override annotations; - * - commented out line 965 due to unused variables. + * - commented out line 967 due to unused variables. * The original version of this file can be found at * https://raw.githubusercontent.com/KdotJPG/OpenSimplex2/master/java/areagen/OpenSimplex2S.java + * + * @formatter:off */ /** @@ -983,16 +985,3 @@ public class OpenSimplex2S { } } } - - - - - - - - - - - - - diff --git a/src/main/java/ru/windcorp/jputil/ArrayUtil.java b/src/main/java/ru/windcorp/jputil/ArrayUtil.java index 81d29a3..4c57314 100644 --- a/src/main/java/ru/windcorp/jputil/ArrayUtil.java +++ b/src/main/java/ru/windcorp/jputil/ArrayUtil.java @@ -1,623 +1,637 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil; - -import java.lang.reflect.Array; -import java.math.BigInteger; -import java.util.Objects; - -public class ArrayUtil { - - private ArrayUtil() {} - - public static int firstIndexOf(byte[] array, byte element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(byte[] array, byte element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(byte[] array, byte element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(byte[] array) { - for (int i = 0; i < array.length; ++i) { - byte a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(byte[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(short[] array, short element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(short[] array, short element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(short[] array, short element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(short[] array) { - for (int i = 0; i < array.length; ++i) { - short a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(short[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(int[] array, int element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(int[] array, int element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(int[] array, int element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(int[] array) { - for (int i = 0; i < array.length; ++i) { - int a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(int[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(long[] array, long element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(long[] array, long element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(long[] array, long element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(long[] array) { - for (int i = 0; i < array.length; ++i) { - long a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(long[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(float[] array, float element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(float[] array, float element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(float[] array, float element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(float[] array) { - for (int i = 0; i < array.length; ++i) { - float a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(float[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(double[] array, double element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(double[] array, double element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(double[] array, double element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(double[] array) { - for (int i = 0; i < array.length; ++i) { - double a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(double[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(boolean[] array, boolean element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(boolean[] array, boolean element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(boolean[] array, boolean element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int firstIndexOf(char[] array, char element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(char[] array, char element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(char[] array, char element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(char[] array) { - for (int i = 0; i < array.length; ++i) { - char a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static boolean isSorted(char[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - if ((array[i] < array[i + 1]) != ascending) { - return false; - } - } - - return true; - } - - public static int firstIndexOf(Object[] array, Object element) { - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int lastIndexOf(Object[] array, Object element) { - for (int i = array.length - 1; i >= 0; --i) { - if (array[i] == element) { - return i; - } - } - return -1; - } - - public static int occurences(Object[] array, Object element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (array[i] == element) { - ++result; - } - } - return result; - } - - public static int hasDuplicates(Object[] array) { - for (int i = 0; i < array.length; ++i) { - Object a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (array[j] == a) { - return i; - } - } - } - - return -1; - } - - public static int firstIndexOfEqual(Object[] array, Object element) { - for (int i = 0; i < array.length; ++i) { - if (Objects.equals(array[i], element)) { - return i; - } - } - return -1; - } - - public static int lastIndexOfEqual(Object[] array, Object element) { - for (int i = array.length - 1; i >= 0; --i) { - if (Objects.equals(array[i], element)) { - return i; - } - } - return -1; - } - - public static int occurencesOfEqual(Object[] array, Object element) { - int result = 0; - for (int i = 0; i < array.length; ++i) { - if (Objects.equals(array[i], element)) { - ++result; - } - } - return result; - } - - public static int hasEquals(Object[] array) { - for (int i = 0; i < array.length; ++i) { - Object a = array[i]; - for (int j = i + 1; j < array.length; ++j) { - if (Objects.equals(array[j], a)) { - return i; - } - } - } - - return -1; - } - - public static > boolean isSorted(T[] array, boolean ascending) { - for (int i = 0; i < array.length - 1; ++i) { - if (array[i] == array[i + 1]) continue; - - int order = array[i].compareTo(array[i + 1]); - - if ((order < 0) != ascending) { - return false; - } - } - - return true; - } - - public static long sum(byte[] array, int start, int length) { - long s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static long sum(short[] array, int start, int length) { - long s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static long sum(int[] array, int start, int length) { - long s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static long sum(long[] array, int start, int length) { - long s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static BigInteger longSum(long[] array, int start, int length) { - BigInteger s = BigInteger.ZERO; - length += start; - for (int i = start; i < length; ++i) { - s = s.add(BigInteger.valueOf(array[i])); - } - return s; - } - - public static float sum(float[] array, int start, int length) { - float s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static double sum(double[] array, int start, int length) { - double s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static long sum(char[] array, int start, int length) { - long s = 0; - length += start; - for (int i = start; i < length; ++i) { - s += array[i]; - } - return s; - } - - public static int checkArrayOffsetLength(Object array, int offset, int length) { - int arrayLength = Array.getLength(array); - - if (length < 0) - length = arrayLength; - - int end = offset + length; - if (end > arrayLength || offset < 0) - throw new IllegalArgumentException("Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")"); - - return length; - } - - public static int checkArrayStartEnd(Object array, int start, int end) { - int arrayLength = Array.getLength(array); - - if (end < 0) - end = arrayLength; - - if (start > end) - throw new IllegalArgumentException("Start > end: " + start + " > " + end); - - if (end > arrayLength || start < 0) - throw new IllegalArgumentException("Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")"); - - return end; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil; + +import java.lang.reflect.Array; +import java.math.BigInteger; +import java.util.Objects; + +public class ArrayUtil { + + private ArrayUtil() { + } + + public static int firstIndexOf(byte[] array, byte element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(byte[] array, byte element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(byte[] array, byte element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(byte[] array) { + for (int i = 0; i < array.length; ++i) { + byte a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(byte[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(short[] array, short element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(short[] array, short element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(short[] array, short element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(short[] array) { + for (int i = 0; i < array.length; ++i) { + short a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(short[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(int[] array, int element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(int[] array, int element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(int[] array, int element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(int[] array) { + for (int i = 0; i < array.length; ++i) { + int a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(int[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(long[] array, long element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(long[] array, long element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(long[] array, long element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(long[] array) { + for (int i = 0; i < array.length; ++i) { + long a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(long[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(float[] array, float element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(float[] array, float element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(float[] array, float element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(float[] array) { + for (int i = 0; i < array.length; ++i) { + float a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(float[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(double[] array, double element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(double[] array, double element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(double[] array, double element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(double[] array) { + for (int i = 0; i < array.length; ++i) { + double a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(double[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(boolean[] array, boolean element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(boolean[] array, boolean element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(boolean[] array, boolean element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int firstIndexOf(char[] array, char element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(char[] array, char element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(char[] array, char element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(char[] array) { + for (int i = 0; i < array.length; ++i) { + char a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static boolean isSorted(char[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + if ((array[i] < array[i + 1]) != ascending) { + return false; + } + } + + return true; + } + + public static int firstIndexOf(Object[] array, Object element) { + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int lastIndexOf(Object[] array, Object element) { + for (int i = array.length - 1; i >= 0; --i) { + if (array[i] == element) { + return i; + } + } + return -1; + } + + public static int occurences(Object[] array, Object element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (array[i] == element) { + ++result; + } + } + return result; + } + + public static int hasDuplicates(Object[] array) { + for (int i = 0; i < array.length; ++i) { + Object a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (array[j] == a) { + return i; + } + } + } + + return -1; + } + + public static int firstIndexOfEqual(Object[] array, Object element) { + for (int i = 0; i < array.length; ++i) { + if (Objects.equals(array[i], element)) { + return i; + } + } + return -1; + } + + public static int lastIndexOfEqual(Object[] array, Object element) { + for (int i = array.length - 1; i >= 0; --i) { + if (Objects.equals(array[i], element)) { + return i; + } + } + return -1; + } + + public static int occurencesOfEqual(Object[] array, Object element) { + int result = 0; + for (int i = 0; i < array.length; ++i) { + if (Objects.equals(array[i], element)) { + ++result; + } + } + return result; + } + + public static int hasEquals(Object[] array) { + for (int i = 0; i < array.length; ++i) { + Object a = array[i]; + for (int j = i + 1; j < array.length; ++j) { + if (Objects.equals(array[j], a)) { + return i; + } + } + } + + return -1; + } + + public static > boolean isSorted(T[] array, boolean ascending) { + for (int i = 0; i < array.length - 1; ++i) { + if (array[i] == array[i + 1]) + continue; + + int order = array[i].compareTo(array[i + 1]); + + if ((order < 0) != ascending) { + return false; + } + } + + return true; + } + + public static long sum(byte[] array, int start, int length) { + long s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static long sum(short[] array, int start, int length) { + long s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static long sum(int[] array, int start, int length) { + long s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static long sum(long[] array, int start, int length) { + long s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static BigInteger longSum(long[] array, int start, int length) { + BigInteger s = BigInteger.ZERO; + length += start; + for (int i = start; i < length; ++i) { + s = s.add(BigInteger.valueOf(array[i])); + } + return s; + } + + public static float sum(float[] array, int start, int length) { + float s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static double sum(double[] array, int start, int length) { + double s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static long sum(char[] array, int start, int length) { + long s = 0; + length += start; + for (int i = start; i < length; ++i) { + s += array[i]; + } + return s; + } + + public static int checkArrayOffsetLength(Object array, int offset, int length) { + int arrayLength = Array.getLength(array); + + if (length < 0) + length = arrayLength; + + int end = offset + length; + if (end > arrayLength || offset < 0) + throw new IllegalArgumentException( + "Array contains [0; " + arrayLength + "), requested [" + offset + "; " + end + ")" + ); + + return length; + } + + public static int checkArrayStartEnd(Object array, int start, int end) { + int arrayLength = Array.getLength(array); + + if (end < 0) + end = arrayLength; + + if (start > end) + throw new IllegalArgumentException("Start > end: " + start + " > " + end); + + if (end > arrayLength || start < 0) + throw new IllegalArgumentException( + "Array contains [0; " + arrayLength + "), requested [" + start + "; " + end + ")" + ); + + return end; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/CSVWriter.java b/src/main/java/ru/windcorp/jputil/CSVWriter.java index 585869e..57ddec0 100644 --- a/src/main/java/ru/windcorp/jputil/CSVWriter.java +++ b/src/main/java/ru/windcorp/jputil/CSVWriter.java @@ -1,20 +1,21 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.jputil; import java.io.OutputStream; @@ -22,53 +23,53 @@ import java.io.PrintWriter; import java.io.Writer; public class CSVWriter { - + private String columnSeparator = ";"; private String rowSeparator = "\n"; - + private boolean shouldAddSeparator = false; - + private final PrintWriter parent; - + public CSVWriter(PrintWriter output) { this.parent = output; } - + public CSVWriter(Writer output) { this(new PrintWriter(output)); } - + public CSVWriter(OutputStream output) { this(new PrintWriter(output)); } - + public PrintWriter getParent() { return parent; } - + public String getColumnSeparator() { return columnSeparator; } - + public CSVWriter setColumnSeparator(String columnSeparator) { this.columnSeparator = columnSeparator; return this; } - + public String getRowSeparator() { return rowSeparator; } - + public CSVWriter setRowSeparator(String rowSeparator) { this.rowSeparator = rowSeparator; return this; } - + public void print(Object object) { skip(); getParent().print(String.valueOf(object)); } - + public void skip() { if (shouldAddSeparator) { getParent().print(getColumnSeparator()); @@ -76,27 +77,27 @@ public class CSVWriter { shouldAddSeparator = true; } } - + public void skip(int amount) { for (int i = 0; i < amount; ++i) { skip(); } } - + public void endRow() { getParent().print(getRowSeparator()); shouldAddSeparator = false; } - + public void endRow(Object object) { print(object); endRow(); } - + public void flush() { getParent().flush(); } - + public void close() { getParent().close(); } diff --git a/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java b/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java index 8da189a..7579413 100644 --- a/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java +++ b/src/main/java/ru/windcorp/jputil/PrimitiveUtil.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,47 +14,57 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.jputil; import java.util.HashMap; import java.util.Map; public class PrimitiveUtil { - - private PrimitiveUtil() {} + + private PrimitiveUtil() { + } private static final Map, Class> PRIMITIVE_TO_BOXED = new HashMap<>(); private static final Map, Object> PRIMITIVE_TO_NULL = new HashMap<>(); - + static { - for (Class boxed : new Class[] { - Boolean.class, Byte.class, Short.class, Character.class, - Integer.class, Long.class, Float.class, Double.class - }) { + for ( + Class boxed : new Class[] { + Boolean.class, + Byte.class, + Short.class, + Character.class, + Integer.class, + Long.class, + Float.class, + Double.class + } + ) { try { PRIMITIVE_TO_BOXED.put((Class) boxed.getField("TYPE").get(null), boxed); } catch (Exception e) { e.printStackTrace(); } } - - PRIMITIVE_TO_NULL.put(Boolean.TYPE, Boolean.FALSE); - PRIMITIVE_TO_NULL.put(Byte.TYPE, Byte.valueOf((byte) 0)); - PRIMITIVE_TO_NULL.put(Short.TYPE, Short.valueOf((short) 0)); - PRIMITIVE_TO_NULL.put(Integer.TYPE, Integer.valueOf(0)); - PRIMITIVE_TO_NULL.put(Long.TYPE, Long.valueOf(0)); - PRIMITIVE_TO_NULL.put(Float.TYPE, Float.valueOf(Float.NaN)); - PRIMITIVE_TO_NULL.put(Double.TYPE, Double.valueOf(Double.NaN)); - PRIMITIVE_TO_NULL.put(Character.TYPE, Character.valueOf('\u0000')); + + PRIMITIVE_TO_NULL.put(Boolean.TYPE, Boolean.FALSE); + PRIMITIVE_TO_NULL.put(Byte.TYPE, Byte.valueOf((byte) 0)); + PRIMITIVE_TO_NULL.put(Short.TYPE, Short.valueOf((short) 0)); + PRIMITIVE_TO_NULL.put(Integer.TYPE, Integer.valueOf(0)); + PRIMITIVE_TO_NULL.put(Long.TYPE, Long.valueOf(0)); + PRIMITIVE_TO_NULL.put(Float.TYPE, Float.valueOf(Float.NaN)); + PRIMITIVE_TO_NULL.put(Double.TYPE, Double.valueOf(Double.NaN)); + PRIMITIVE_TO_NULL.put(Character.TYPE, Character.valueOf('\u0000')); } - + public static Class getBoxedClass(Class primitiveClass) { return PRIMITIVE_TO_BOXED.getOrDefault(primitiveClass, primitiveClass); } - + public static Object getPrimitiveNull(Class primitiveClass) { return PRIMITIVE_TO_NULL.get(primitiveClass); } - + } diff --git a/src/main/java/ru/windcorp/jputil/SyncStreams.java b/src/main/java/ru/windcorp/jputil/SyncStreams.java index e75e9a2..9b2bc3a 100644 --- a/src/main/java/ru/windcorp/jputil/SyncStreams.java +++ b/src/main/java/ru/windcorp/jputil/SyncStreams.java @@ -1,1210 +1,1270 @@ -/* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -package ru.windcorp.jputil; - -import java.util.function.*; - -import java.util.Comparator; -import java.util.DoubleSummaryStatistics; -import java.util.IntSummaryStatistics; -import java.util.Iterator; -import java.util.LongSummaryStatistics; -import java.util.Objects; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.PrimitiveIterator; -import java.util.Spliterator; -import java.util.stream.Collector; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; - -/** - * Contains static methods to create {@link Stream Streams} that synchronize their - * - * terminal operations on a given monitor. - * @author Javapony (kvadropups@gmail.com) - */ - -// SonarLint: "Stream.peek" should be used with caution (java:S3864) -// We are implementing Stream, so peek() is required. -@SuppressWarnings("squid:S3864") - -public class SyncStreams { - - public static class SyncStream implements Stream { - - private final Stream parent; - private final Object monitor; - - public SyncStream(Stream parent, Object monitor) { - this.parent = parent; - this.monitor = monitor == null ? this : monitor; - } - - public Stream getParent() { - return parent; - } - - public Object getMonitor() { - return monitor; - } - - /* - * Returns null when child streams should sync on themselves - */ - private Object getInheritableMonitor() { - return monitor == this ? null : monitor; - } - - @Override - public void close() { - parent.close(); - } - - @Override - public Iterator iterator() { - return parent.iterator(); - } - - @Override - public Spliterator spliterator() { - return parent.spliterator(); - } - - @Override - public boolean isParallel() { - return parent.isParallel(); - } - - @Override - public Stream sequential() { - return synchronizedStream(parent.sequential(), getInheritableMonitor()); - } - - @Override - public Stream parallel() { - return synchronizedStream(parent.parallel(), getInheritableMonitor()); - } - - @Override - public Stream unordered() { - return synchronizedStream(parent.unordered(), getInheritableMonitor()); - } - - @Override - public Stream onClose(Runnable closeHandler) { - return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); - } - - @Override - public Stream filter(Predicate predicate) { - return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); - } - - @Override - public Stream map(Function mapper) { - return synchronizedStream(parent.map(mapper), getInheritableMonitor()); - } - - @Override - public IntStream mapToInt(ToIntFunction mapper) { - return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); - } - - @Override - public LongStream mapToLong(ToLongFunction mapper) { - return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream mapToDouble(ToDoubleFunction mapper) { - return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); - } - - @Override - public Stream flatMap(Function> mapper) { - return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); - } - - @Override - public IntStream flatMapToInt(Function mapper) { - return synchronizedStream(parent.flatMapToInt(mapper), getInheritableMonitor()); - } - - @Override - public LongStream flatMapToLong(Function mapper) { - return synchronizedStream(parent.flatMapToLong(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream flatMapToDouble(Function mapper) { - return synchronizedStream(parent.flatMapToDouble(mapper), getInheritableMonitor()); - } - - @Override - public Stream distinct() { - return synchronizedStream(parent.distinct(), getInheritableMonitor()); - } - - @Override - public Stream sorted() { - return synchronizedStream(parent.sorted(), getInheritableMonitor()); - } - - @Override - public Stream sorted(Comparator comparator) { - return synchronizedStream(parent.sorted(comparator), getInheritableMonitor()); - } - - @Override - public Stream peek(Consumer action) { - return synchronizedStream(parent.peek(action), getInheritableMonitor()); - } - - @Override - public Stream limit(long maxSize) { - return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); - } - - @Override - public Stream skip(long n) { - return synchronizedStream(parent.skip(n), getInheritableMonitor()); - } - - @Override - public T reduce(T identity, BinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(identity, accumulator); - } - } - - @Override - public Optional reduce(BinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(accumulator); - } - } - - @Override - public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { - synchronized (monitor) { - return parent.reduce(identity, accumulator, combiner); - } - } - - @Override - public void forEach(Consumer action) { - synchronized (monitor) { - parent.forEach(action); - } - } - - @Override - public void forEachOrdered(Consumer action) { - synchronized (monitor) { - parent.forEachOrdered(action); - } - } - - @Override - public Object[] toArray() { - synchronized (monitor) { - return parent.toArray(); - } - } - - @Override - public A[] toArray(IntFunction generator) { - synchronized (monitor) { - return parent.toArray(generator); - } - } - - @Override - public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { - synchronized (monitor) { - return parent.collect(supplier, accumulator, combiner); - } - } - - @Override - public R collect(Collector collector) { - synchronized (monitor) { - return parent.collect(collector); - } - } - - @Override - public Optional min(Comparator comparator) { - synchronized (monitor) { - return parent.min(comparator); - } - } - - @Override - public Optional max(Comparator comparator) { - synchronized (monitor) { - return parent.max(comparator); - } - } - - @Override - public long count() { - synchronized (monitor) { - return parent.count(); - } - } - - @Override - public boolean anyMatch(Predicate predicate) { - synchronized (monitor) { - return parent.anyMatch(predicate); - } - } - - @Override - public boolean allMatch(Predicate predicate) { - synchronized (monitor) { - return parent.allMatch(predicate); - } - } - - @Override - public boolean noneMatch(Predicate predicate) { - synchronized (monitor) { - return parent.noneMatch(predicate); - } - } - - @Override - public Optional findFirst() { - synchronized (monitor) { - return parent.findFirst(); - } - } - - @Override - public Optional findAny() { - synchronized (monitor) { - return parent.findAny(); - } - } - - } - - public static class SyncIntStream implements IntStream { - - private final IntStream parent; - private final Object monitor; - - public SyncIntStream(IntStream parent, Object monitor) { - this.parent = parent; - this.monitor = monitor == null ? this : monitor; - } - - public IntStream getParent() { - return parent; - } - - public Object getMonitor() { - return monitor; - } - - /* - * Returns null when child streams should sync on themselves - */ - private Object getInheritableMonitor() { - return monitor == this ? null : monitor; - } - - @Override - public void close() { - parent.close(); - } - - @Override - public PrimitiveIterator.OfInt iterator() { - return parent.iterator(); - } - - @Override - public Spliterator.OfInt spliterator() { - return parent.spliterator(); - } - - @Override - public boolean isParallel() { - return parent.isParallel(); - } - - @Override - public IntStream sequential() { - return synchronizedStream(parent.sequential(), getInheritableMonitor()); - } - - @Override - public IntStream parallel() { - return synchronizedStream(parent.parallel(), getInheritableMonitor()); - } - - @Override - public IntStream unordered() { - return synchronizedStream(parent.unordered(), getInheritableMonitor()); - } - - @Override - public IntStream onClose(Runnable closeHandler) { - return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); - } - - @Override - public IntStream filter(IntPredicate predicate) { - return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); - } - - @Override - public IntStream map(IntUnaryOperator mapper) { - return synchronizedStream(parent.map(mapper), getInheritableMonitor()); - } - - @Override - public LongStream mapToLong(IntToLongFunction mapper) { - return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream mapToDouble(IntToDoubleFunction mapper) { - return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); - } - - @Override - public Stream mapToObj(IntFunction mapper) { - return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); - } - - @Override - public IntStream flatMap(IntFunction mapper) { - return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); - } - - @Override - public IntStream distinct() { - return synchronizedStream(parent.distinct(), getInheritableMonitor()); - } - - @Override - public IntStream sorted() { - return synchronizedStream(parent.sorted(), getInheritableMonitor()); - } - - @Override - public IntStream peek(IntConsumer action) { - return synchronizedStream(parent.peek(action), getInheritableMonitor()); - } - - @Override - public IntStream limit(long maxSize) { - return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); - } - - @Override - public IntStream skip(long n) { - return synchronizedStream(parent.skip(n), getInheritableMonitor()); - } - - @Override - public LongStream asLongStream() { - return synchronizedStream(parent.asLongStream(), getInheritableMonitor()); - } - - @Override - public DoubleStream asDoubleStream() { - return synchronizedStream(parent.asDoubleStream(), getInheritableMonitor()); - } - - @Override - public Stream boxed() { - return synchronizedStream(parent.boxed(), getInheritableMonitor()); - } - - @Override - public int reduce(int identity, IntBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(identity, accumulator); - } - } - - @Override - public OptionalInt reduce(IntBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(accumulator); - } - } - - @Override - public void forEach(IntConsumer action) { - synchronized (monitor) { - parent.forEach(action); - } - } - - @Override - public void forEachOrdered(IntConsumer action) { - synchronized (monitor) { - parent.forEachOrdered(action); - } - } - - @Override - public int[] toArray() { - synchronized (monitor) { - return parent.toArray(); - } - } - - @Override - public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { - synchronized (monitor) { - return parent.collect(supplier, accumulator, combiner); - } - } - - @Override - public int sum() { - synchronized (monitor) { - return parent.sum(); - } - } - - @Override - public OptionalInt min() { - synchronized (monitor) { - return parent.min(); - } - } - - @Override - public OptionalInt max() { - synchronized (monitor) { - return parent.max(); - } - } - - @Override - public long count() { - synchronized (monitor) { - return parent.count(); - } - } - - @Override - public OptionalDouble average() { - synchronized (monitor) { - return parent.average(); - } - } - - @Override - public IntSummaryStatistics summaryStatistics() { - synchronized (monitor) { - return parent.summaryStatistics(); - } - } - - @Override - public boolean anyMatch(IntPredicate predicate) { - synchronized (monitor) { - return parent.anyMatch(predicate); - } - } - - @Override - public boolean allMatch(IntPredicate predicate) { - synchronized (monitor) { - return parent.allMatch(predicate); - } - } - - @Override - public boolean noneMatch(IntPredicate predicate) { - synchronized (monitor) { - return parent.noneMatch(predicate); - } - } - - @Override - public OptionalInt findFirst() { - synchronized (monitor) { - return parent.findFirst(); - } - } - - @Override - public OptionalInt findAny() { - synchronized (monitor) { - return parent.findAny(); - } - } - - } - - public static class SyncLongStream implements LongStream { - - private final LongStream parent; - private final Object monitor; - - public SyncLongStream(LongStream parent, Object monitor) { - this.parent = parent; - this.monitor = monitor == null ? this : monitor; - } - - public LongStream getParent() { - return parent; - } - - public Object getMonitor() { - return monitor; - } - - /* - * Returns null when child streams should sync on themselves - */ - private Object getInheritableMonitor() { - return monitor == this ? null : monitor; - } - - @Override - public void close() { - parent.close(); - } - - @Override - public PrimitiveIterator.OfLong iterator() { - return parent.iterator(); - } - - @Override - public Spliterator.OfLong spliterator() { - return parent.spliterator(); - } - - @Override - public boolean isParallel() { - return parent.isParallel(); - } - - @Override - public LongStream sequential() { - return synchronizedStream(parent.sequential(), getInheritableMonitor()); - } - - @Override - public LongStream parallel() { - return synchronizedStream(parent.parallel(), getInheritableMonitor()); - } - - @Override - public LongStream unordered() { - return synchronizedStream(parent.unordered(), getInheritableMonitor()); - } - - @Override - public LongStream onClose(Runnable closeHandler) { - return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); - } - - @Override - public LongStream filter(LongPredicate predicate) { - return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); - } - - @Override - public LongStream map(LongUnaryOperator mapper) { - return synchronizedStream(parent.map(mapper), getInheritableMonitor()); - } - - @Override - public IntStream mapToInt(LongToIntFunction mapper) { - return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream mapToDouble(LongToDoubleFunction mapper) { - return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); - } - - @Override - public Stream mapToObj(LongFunction mapper) { - return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); - } - - @Override - public LongStream flatMap(LongFunction mapper) { - return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); - } - - @Override - public LongStream distinct() { - return synchronizedStream(parent.distinct(), getInheritableMonitor()); - } - - @Override - public LongStream sorted() { - return synchronizedStream(parent.sorted(), getInheritableMonitor()); - } - - @Override - public LongStream peek(LongConsumer action) { - return synchronizedStream(parent.peek(action), getInheritableMonitor()); - } - - @Override - public LongStream limit(long maxSize) { - return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); - } - - @Override - public LongStream skip(long n) { - return synchronizedStream(parent.skip(n), getInheritableMonitor()); - } - - @Override - public DoubleStream asDoubleStream() { - return synchronizedStream(parent.asDoubleStream(), getInheritableMonitor()); - } - - @Override - public Stream boxed() { - return synchronizedStream(parent.boxed(), getInheritableMonitor()); - } - - @Override - public long reduce(long identity, LongBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(identity, accumulator); - } - } - - @Override - public OptionalLong reduce(LongBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(accumulator); - } - } - - @Override - public void forEach(LongConsumer action) { - synchronized (monitor) { - parent.forEach(action); - } - } - - @Override - public void forEachOrdered(LongConsumer action) { - synchronized (monitor) { - parent.forEachOrdered(action); - } - } - - @Override - public long[] toArray() { - synchronized (monitor) { - return parent.toArray(); - } - } - - @Override - public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { - synchronized (monitor) { - return parent.collect(supplier, accumulator, combiner); - } - } - - @Override - public long sum() { - synchronized (monitor) { - return parent.sum(); - } - } - - @Override - public OptionalLong min() { - synchronized (monitor) { - return parent.min(); - } - } - - @Override - public OptionalLong max() { - synchronized (monitor) { - return parent.max(); - } - } - - @Override - public long count() { - synchronized (monitor) { - return parent.count(); - } - } - - @Override - public OptionalDouble average() { - synchronized (monitor) { - return parent.average(); - } - } - - @Override - public LongSummaryStatistics summaryStatistics() { - synchronized (monitor) { - return parent.summaryStatistics(); - } - } - - @Override - public boolean anyMatch(LongPredicate predicate) { - synchronized (monitor) { - return parent.anyMatch(predicate); - } - } - - @Override - public boolean allMatch(LongPredicate predicate) { - synchronized (monitor) { - return parent.allMatch(predicate); - } - } - - @Override - public boolean noneMatch(LongPredicate predicate) { - synchronized (monitor) { - return parent.noneMatch(predicate); - } - } - - @Override - public OptionalLong findFirst() { - synchronized (monitor) { - return parent.findFirst(); - } - } - - @Override - public OptionalLong findAny() { - synchronized (monitor) { - return parent.findAny(); - } - } - - } - - public static class SyncDoubleStream implements DoubleStream { - - private final DoubleStream parent; - private final Object monitor; - - public SyncDoubleStream(DoubleStream parent, Object monitor) { - this.parent = parent; - this.monitor = monitor == null ? this : monitor; - } - - public DoubleStream getParent() { - return parent; - } - - public Object getMonitor() { - return monitor; - } - - /* - * Returns null when child streams should sync on themselves - */ - private Object getInheritableMonitor() { - return monitor == this ? null : monitor; - } - - @Override - public void close() { - parent.close(); - } - - @Override - public PrimitiveIterator.OfDouble iterator() { - return parent.iterator(); - } - - @Override - public Spliterator.OfDouble spliterator() { - return parent.spliterator(); - } - - @Override - public boolean isParallel() { - return parent.isParallel(); - } - - @Override - public DoubleStream sequential() { - return synchronizedStream(parent.sequential(), getInheritableMonitor()); - } - - @Override - public DoubleStream parallel() { - return synchronizedStream(parent.parallel(), getInheritableMonitor()); - } - - @Override - public DoubleStream unordered() { - return synchronizedStream(parent.unordered(), getInheritableMonitor()); - } - - @Override - public DoubleStream onClose(Runnable closeHandler) { - return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); - } - - @Override - public DoubleStream filter(DoublePredicate predicate) { - return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); - } - - @Override - public DoubleStream map(DoubleUnaryOperator mapper) { - return synchronizedStream(parent.map(mapper), getInheritableMonitor()); - } - - @Override - public IntStream mapToInt(DoubleToIntFunction mapper) { - return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); - } - - @Override - public LongStream mapToLong(DoubleToLongFunction mapper) { - return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); - } - - @Override - public Stream mapToObj(DoubleFunction mapper) { - return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream flatMap(DoubleFunction mapper) { - return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); - } - - @Override - public DoubleStream distinct() { - return synchronizedStream(parent.distinct(), getInheritableMonitor()); - } - - @Override - public DoubleStream sorted() { - return synchronizedStream(parent.sorted(), getInheritableMonitor()); - } - - @Override - public DoubleStream peek(DoubleConsumer action) { - return synchronizedStream(parent.peek(action), getInheritableMonitor()); - } - - @Override - public DoubleStream limit(long maxSize) { - return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); - } - - @Override - public DoubleStream skip(long n) { - return synchronizedStream(parent.skip(n), getInheritableMonitor()); - } - - @Override - public Stream boxed() { - return synchronizedStream(parent.boxed(), getInheritableMonitor()); - } - - @Override - public double reduce(double identity, DoubleBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(identity, accumulator); - } - } - - @Override - public OptionalDouble reduce(DoubleBinaryOperator accumulator) { - synchronized (monitor) { - return parent.reduce(accumulator); - } - } - - @Override - public void forEach(DoubleConsumer action) { - synchronized (monitor) { - parent.forEach(action); - } - } - - @Override - public void forEachOrdered(DoubleConsumer action) { - synchronized (monitor) { - parent.forEachOrdered(action); - } - } - - @Override - public double[] toArray() { - synchronized (monitor) { - return parent.toArray(); - } - } - - @Override - public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { - synchronized (monitor) { - return parent.collect(supplier, accumulator, combiner); - } - } - - @Override - public double sum() { - synchronized (monitor) { - return parent.sum(); - } - } - - @Override - public OptionalDouble min() { - synchronized (monitor) { - return parent.min(); - } - } - - @Override - public OptionalDouble max() { - synchronized (monitor) { - return parent.max(); - } - } - - @Override - public long count() { - synchronized (monitor) { - return parent.count(); - } - } - - @Override - public OptionalDouble average() { - synchronized (monitor) { - return parent.average(); - } - } - - @Override - public DoubleSummaryStatistics summaryStatistics() { - synchronized (monitor) { - return parent.summaryStatistics(); - } - } - - @Override - public boolean anyMatch(DoublePredicate predicate) { - synchronized (monitor) { - return parent.anyMatch(predicate); - } - } - - @Override - public boolean allMatch(DoublePredicate predicate) { - synchronized (monitor) { - return parent.allMatch(predicate); - } - } - - @Override - public boolean noneMatch(DoublePredicate predicate) { - synchronized (monitor) { - return parent.noneMatch(predicate); - } - } - - @Override - public OptionalDouble findFirst() { - synchronized (monitor) { - return parent.findFirst(); - } - } - - @Override - public OptionalDouble findAny() { - synchronized (monitor) { - return parent.findAny(); - } - } - - } - - /** - * Wraps the given {@link Stream} to make all - * - * terminal operations acquire the provided monitor's lock before execution. Intermediate operations - * return streams that are also synchronized on the same object. The created stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize access to stream's source. - *

The returned {@code Stream}'s {@link Stream#iterator() iterator()} and {@link Stream#spliterator() - * spliterator()} methods return regular non-synchronized iterators and spliterators respectively. It - * is the user's responsibility to avoid concurrency issues: - *

-	 * synchronized (stream.getMonitor()) {
-	 *     Iterator it = stream.iterator();
-	 *         ...
-	 * }
-	 * 
- * Usage example: - *
-	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
-	 *    ...
-	 * Stream<?> stream = SyncStreams.synchronizedStream(s.stream(), s);
-	 * stream = stream.map(Object::toString); // Still synchronized
-	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException 
-	 * 
- * - * @param the class of objects in the Stream - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. When {@code null}, the stream - * will synchronize on itself. - * @return a {@link SyncStream SyncStream<T>} synchronized on {@code monitor} and backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. - */ - public static SyncStream synchronizedStream(Stream stream, Object monitor) { - Objects.requireNonNull(stream, "stream cannot be null"); - return new SyncStream<>(stream, monitor); - } - - /** - * Wraps the given {@link IntStream} to make all - * - * terminal operations acquire the provided monitor's lock before execution. Intermediate operations - * return streams that are also synchronized on the same object. The created stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize access to stream's source. - *

The returned {@code IntStream}'s {@link IntStream#iterator() iterator()} and - * {@link IntStream#spliterator() spliterator()} methods return regular non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid concurrency issues: - *

-	 * synchronized (stream.getMonitor()) {
-	 *     PrimitiveIterator.OfInt it = stream.iterator();
-	 *         ...
-	 * }
-	 * 
- * Usage example: - *
-	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
-	 *    ...
-	 * IntStream stream = SyncStreams.synchronizedStream(s.stream().mapToInt(Object::hashCode), s);
-	 * stream = stream.map(i -> i % 67); // Still synchronized
-	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException 
-	 * 
- * - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. When {@code null}, the stream - * will synchronize on itself. - * @return a {@link SyncIntStream} synchronized on {@code monitor} and backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. - */ - public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) { - Objects.requireNonNull(stream, "stream cannot be null"); - return new SyncIntStream(stream, monitor); - } - - /** - * Wraps the given {@link LongStream} to make all - * - * terminal operations acquire the provided monitor's lock before execution. Intermediate operations - * return streams that are also synchronized on the same object. The created stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize access to stream's source. - *

The returned {@code LongStream}'s {@link LongStream#iterator() iterator()} and - * {@link LongStream#spliterator() spliterator()} methods return regular non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid concurrency issues: - *

-	 * synchronized (stream.getMonitor()) {
-	 *     PrimitiveIterator.OfLong it = stream.iterator();
-	 *         ...
-	 * }
-	 * 
- * Usage example: - *
-	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
-	 *    ...
-	 * LongStream stream = SyncStreams.synchronizedStream(s.stream().mapToLong(o -> (long) o.hashCode()), s);
-	 * stream = stream.map(i -> i % 67); // Still synchronized
-	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException 
-	 * 
- * - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. When {@code null}, the stream - * will synchronize on itself. - * @return a {@link SyncLongStream} synchronized on {@code monitor} and backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. - */ - public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) { - Objects.requireNonNull(stream, "stream cannot be null"); - return new SyncLongStream(stream, monitor); - } - - /** - * Wraps the given {@link DoubleStream} to make all - * - * terminal operations acquire the provided monitor's lock before execution. Intermediate operations - * return streams that are also synchronized on the same object. The created stream will behave identically - * to the provided stream in all other aspects. Use this to synchronize access to stream's source. - *

The returned {@code DoubleStream}'s {@link DoubleStream#iterator() iterator()} and - * {@link DoubleStream#spliterator() spliterator()} methods return regular non-synchronized iterators and - * spliterators respectively. It is the user's responsibility to avoid concurrency issues: - *

-	 * synchronized (stream.getMonitor()) {
-	 *     PrimitiveIterator.OfDouble it = stream.iterator();
-	 *         ...
-	 * }
-	 * 
- * Usage example: - *
-	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
-	 *    ...
-	 * DoubleStream stream = SyncStreams.synchronizedStream(s.stream().mapToLong(o -> (double) o.hashCode()), s);
-	 * stream = stream.map(Math::sin); // Still synchronized
-	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException 
-	 * 
- * - * @param stream the stream to wrap. - * @param monitor the object that the stream will use for synchronization. When {@code null}, the stream - * will synchronize on itself. - * @return a {@link SyncDoubleStream} synchronized on {@code monitor} and backed by {@code stream}. - * @throws NullPointerException if {@code stream == null}. - */ - public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) { - Objects.requireNonNull(stream, "stream cannot be null"); - return new SyncDoubleStream(stream, monitor); - } - - /* - * Private constructor - */ - private SyncStreams() {} - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil; + +import java.util.function.*; + +import java.util.Comparator; +import java.util.DoubleSummaryStatistics; +import java.util.IntSummaryStatistics; +import java.util.Iterator; +import java.util.LongSummaryStatistics; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; +import java.util.PrimitiveIterator; +import java.util.Spliterator; +import java.util.stream.Collector; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; + +/** + * Contains static methods to create {@link Stream Streams} that synchronize + * their + * + * terminal operations on a given monitor. + * + * @author Javapony + * (kvadropups@gmail.com) + */ + +// SonarLint: "Stream.peek" should be used with caution (java:S3864) +// We are implementing Stream, so peek() is required. +@SuppressWarnings("squid:S3864") + +public class SyncStreams { + + public static class SyncStream implements Stream { + + private final Stream parent; + private final Object monitor; + + public SyncStream(Stream parent, Object monitor) { + this.parent = parent; + this.monitor = monitor == null ? this : monitor; + } + + public Stream getParent() { + return parent; + } + + public Object getMonitor() { + return monitor; + } + + /* + * Returns null when child streams should sync on themselves + */ + private Object getInheritableMonitor() { + return monitor == this ? null : monitor; + } + + @Override + public void close() { + parent.close(); + } + + @Override + public Iterator iterator() { + return parent.iterator(); + } + + @Override + public Spliterator spliterator() { + return parent.spliterator(); + } + + @Override + public boolean isParallel() { + return parent.isParallel(); + } + + @Override + public Stream sequential() { + return synchronizedStream(parent.sequential(), getInheritableMonitor()); + } + + @Override + public Stream parallel() { + return synchronizedStream(parent.parallel(), getInheritableMonitor()); + } + + @Override + public Stream unordered() { + return synchronizedStream(parent.unordered(), getInheritableMonitor()); + } + + @Override + public Stream onClose(Runnable closeHandler) { + return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); + } + + @Override + public Stream filter(Predicate predicate) { + return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); + } + + @Override + public Stream map(Function mapper) { + return synchronizedStream(parent.map(mapper), getInheritableMonitor()); + } + + @Override + public IntStream mapToInt(ToIntFunction mapper) { + return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); + } + + @Override + public LongStream mapToLong(ToLongFunction mapper) { + return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream mapToDouble(ToDoubleFunction mapper) { + return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); + } + + @Override + public Stream flatMap(Function> mapper) { + return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); + } + + @Override + public IntStream flatMapToInt(Function mapper) { + return synchronizedStream(parent.flatMapToInt(mapper), getInheritableMonitor()); + } + + @Override + public LongStream flatMapToLong(Function mapper) { + return synchronizedStream(parent.flatMapToLong(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream flatMapToDouble(Function mapper) { + return synchronizedStream(parent.flatMapToDouble(mapper), getInheritableMonitor()); + } + + @Override + public Stream distinct() { + return synchronizedStream(parent.distinct(), getInheritableMonitor()); + } + + @Override + public Stream sorted() { + return synchronizedStream(parent.sorted(), getInheritableMonitor()); + } + + @Override + public Stream sorted(Comparator comparator) { + return synchronizedStream(parent.sorted(comparator), getInheritableMonitor()); + } + + @Override + public Stream peek(Consumer action) { + return synchronizedStream(parent.peek(action), getInheritableMonitor()); + } + + @Override + public Stream limit(long maxSize) { + return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); + } + + @Override + public Stream skip(long n) { + return synchronizedStream(parent.skip(n), getInheritableMonitor()); + } + + @Override + public T reduce(T identity, BinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(identity, accumulator); + } + } + + @Override + public Optional reduce(BinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(accumulator); + } + } + + @Override + public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { + synchronized (monitor) { + return parent.reduce(identity, accumulator, combiner); + } + } + + @Override + public void forEach(Consumer action) { + synchronized (monitor) { + parent.forEach(action); + } + } + + @Override + public void forEachOrdered(Consumer action) { + synchronized (monitor) { + parent.forEachOrdered(action); + } + } + + @Override + public Object[] toArray() { + synchronized (monitor) { + return parent.toArray(); + } + } + + @Override + public A[] toArray(IntFunction generator) { + synchronized (monitor) { + return parent.toArray(generator); + } + } + + @Override + public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { + synchronized (monitor) { + return parent.collect(supplier, accumulator, combiner); + } + } + + @Override + public R collect(Collector collector) { + synchronized (monitor) { + return parent.collect(collector); + } + } + + @Override + public Optional min(Comparator comparator) { + synchronized (monitor) { + return parent.min(comparator); + } + } + + @Override + public Optional max(Comparator comparator) { + synchronized (monitor) { + return parent.max(comparator); + } + } + + @Override + public long count() { + synchronized (monitor) { + return parent.count(); + } + } + + @Override + public boolean anyMatch(Predicate predicate) { + synchronized (monitor) { + return parent.anyMatch(predicate); + } + } + + @Override + public boolean allMatch(Predicate predicate) { + synchronized (monitor) { + return parent.allMatch(predicate); + } + } + + @Override + public boolean noneMatch(Predicate predicate) { + synchronized (monitor) { + return parent.noneMatch(predicate); + } + } + + @Override + public Optional findFirst() { + synchronized (monitor) { + return parent.findFirst(); + } + } + + @Override + public Optional findAny() { + synchronized (monitor) { + return parent.findAny(); + } + } + + } + + public static class SyncIntStream implements IntStream { + + private final IntStream parent; + private final Object monitor; + + public SyncIntStream(IntStream parent, Object monitor) { + this.parent = parent; + this.monitor = monitor == null ? this : monitor; + } + + public IntStream getParent() { + return parent; + } + + public Object getMonitor() { + return monitor; + } + + /* + * Returns null when child streams should sync on themselves + */ + private Object getInheritableMonitor() { + return monitor == this ? null : monitor; + } + + @Override + public void close() { + parent.close(); + } + + @Override + public PrimitiveIterator.OfInt iterator() { + return parent.iterator(); + } + + @Override + public Spliterator.OfInt spliterator() { + return parent.spliterator(); + } + + @Override + public boolean isParallel() { + return parent.isParallel(); + } + + @Override + public IntStream sequential() { + return synchronizedStream(parent.sequential(), getInheritableMonitor()); + } + + @Override + public IntStream parallel() { + return synchronizedStream(parent.parallel(), getInheritableMonitor()); + } + + @Override + public IntStream unordered() { + return synchronizedStream(parent.unordered(), getInheritableMonitor()); + } + + @Override + public IntStream onClose(Runnable closeHandler) { + return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); + } + + @Override + public IntStream filter(IntPredicate predicate) { + return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); + } + + @Override + public IntStream map(IntUnaryOperator mapper) { + return synchronizedStream(parent.map(mapper), getInheritableMonitor()); + } + + @Override + public LongStream mapToLong(IntToLongFunction mapper) { + return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream mapToDouble(IntToDoubleFunction mapper) { + return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); + } + + @Override + public Stream mapToObj(IntFunction mapper) { + return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); + } + + @Override + public IntStream flatMap(IntFunction mapper) { + return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); + } + + @Override + public IntStream distinct() { + return synchronizedStream(parent.distinct(), getInheritableMonitor()); + } + + @Override + public IntStream sorted() { + return synchronizedStream(parent.sorted(), getInheritableMonitor()); + } + + @Override + public IntStream peek(IntConsumer action) { + return synchronizedStream(parent.peek(action), getInheritableMonitor()); + } + + @Override + public IntStream limit(long maxSize) { + return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); + } + + @Override + public IntStream skip(long n) { + return synchronizedStream(parent.skip(n), getInheritableMonitor()); + } + + @Override + public LongStream asLongStream() { + return synchronizedStream(parent.asLongStream(), getInheritableMonitor()); + } + + @Override + public DoubleStream asDoubleStream() { + return synchronizedStream(parent.asDoubleStream(), getInheritableMonitor()); + } + + @Override + public Stream boxed() { + return synchronizedStream(parent.boxed(), getInheritableMonitor()); + } + + @Override + public int reduce(int identity, IntBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(identity, accumulator); + } + } + + @Override + public OptionalInt reduce(IntBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(accumulator); + } + } + + @Override + public void forEach(IntConsumer action) { + synchronized (monitor) { + parent.forEach(action); + } + } + + @Override + public void forEachOrdered(IntConsumer action) { + synchronized (monitor) { + parent.forEachOrdered(action); + } + } + + @Override + public int[] toArray() { + synchronized (monitor) { + return parent.toArray(); + } + } + + @Override + public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { + synchronized (monitor) { + return parent.collect(supplier, accumulator, combiner); + } + } + + @Override + public int sum() { + synchronized (monitor) { + return parent.sum(); + } + } + + @Override + public OptionalInt min() { + synchronized (monitor) { + return parent.min(); + } + } + + @Override + public OptionalInt max() { + synchronized (monitor) { + return parent.max(); + } + } + + @Override + public long count() { + synchronized (monitor) { + return parent.count(); + } + } + + @Override + public OptionalDouble average() { + synchronized (monitor) { + return parent.average(); + } + } + + @Override + public IntSummaryStatistics summaryStatistics() { + synchronized (monitor) { + return parent.summaryStatistics(); + } + } + + @Override + public boolean anyMatch(IntPredicate predicate) { + synchronized (monitor) { + return parent.anyMatch(predicate); + } + } + + @Override + public boolean allMatch(IntPredicate predicate) { + synchronized (monitor) { + return parent.allMatch(predicate); + } + } + + @Override + public boolean noneMatch(IntPredicate predicate) { + synchronized (monitor) { + return parent.noneMatch(predicate); + } + } + + @Override + public OptionalInt findFirst() { + synchronized (monitor) { + return parent.findFirst(); + } + } + + @Override + public OptionalInt findAny() { + synchronized (monitor) { + return parent.findAny(); + } + } + + } + + public static class SyncLongStream implements LongStream { + + private final LongStream parent; + private final Object monitor; + + public SyncLongStream(LongStream parent, Object monitor) { + this.parent = parent; + this.monitor = monitor == null ? this : monitor; + } + + public LongStream getParent() { + return parent; + } + + public Object getMonitor() { + return monitor; + } + + /* + * Returns null when child streams should sync on themselves + */ + private Object getInheritableMonitor() { + return monitor == this ? null : monitor; + } + + @Override + public void close() { + parent.close(); + } + + @Override + public PrimitiveIterator.OfLong iterator() { + return parent.iterator(); + } + + @Override + public Spliterator.OfLong spliterator() { + return parent.spliterator(); + } + + @Override + public boolean isParallel() { + return parent.isParallel(); + } + + @Override + public LongStream sequential() { + return synchronizedStream(parent.sequential(), getInheritableMonitor()); + } + + @Override + public LongStream parallel() { + return synchronizedStream(parent.parallel(), getInheritableMonitor()); + } + + @Override + public LongStream unordered() { + return synchronizedStream(parent.unordered(), getInheritableMonitor()); + } + + @Override + public LongStream onClose(Runnable closeHandler) { + return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); + } + + @Override + public LongStream filter(LongPredicate predicate) { + return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); + } + + @Override + public LongStream map(LongUnaryOperator mapper) { + return synchronizedStream(parent.map(mapper), getInheritableMonitor()); + } + + @Override + public IntStream mapToInt(LongToIntFunction mapper) { + return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream mapToDouble(LongToDoubleFunction mapper) { + return synchronizedStream(parent.mapToDouble(mapper), getInheritableMonitor()); + } + + @Override + public Stream mapToObj(LongFunction mapper) { + return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); + } + + @Override + public LongStream flatMap(LongFunction mapper) { + return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); + } + + @Override + public LongStream distinct() { + return synchronizedStream(parent.distinct(), getInheritableMonitor()); + } + + @Override + public LongStream sorted() { + return synchronizedStream(parent.sorted(), getInheritableMonitor()); + } + + @Override + public LongStream peek(LongConsumer action) { + return synchronizedStream(parent.peek(action), getInheritableMonitor()); + } + + @Override + public LongStream limit(long maxSize) { + return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); + } + + @Override + public LongStream skip(long n) { + return synchronizedStream(parent.skip(n), getInheritableMonitor()); + } + + @Override + public DoubleStream asDoubleStream() { + return synchronizedStream(parent.asDoubleStream(), getInheritableMonitor()); + } + + @Override + public Stream boxed() { + return synchronizedStream(parent.boxed(), getInheritableMonitor()); + } + + @Override + public long reduce(long identity, LongBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(identity, accumulator); + } + } + + @Override + public OptionalLong reduce(LongBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(accumulator); + } + } + + @Override + public void forEach(LongConsumer action) { + synchronized (monitor) { + parent.forEach(action); + } + } + + @Override + public void forEachOrdered(LongConsumer action) { + synchronized (monitor) { + parent.forEachOrdered(action); + } + } + + @Override + public long[] toArray() { + synchronized (monitor) { + return parent.toArray(); + } + } + + @Override + public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { + synchronized (monitor) { + return parent.collect(supplier, accumulator, combiner); + } + } + + @Override + public long sum() { + synchronized (monitor) { + return parent.sum(); + } + } + + @Override + public OptionalLong min() { + synchronized (monitor) { + return parent.min(); + } + } + + @Override + public OptionalLong max() { + synchronized (monitor) { + return parent.max(); + } + } + + @Override + public long count() { + synchronized (monitor) { + return parent.count(); + } + } + + @Override + public OptionalDouble average() { + synchronized (monitor) { + return parent.average(); + } + } + + @Override + public LongSummaryStatistics summaryStatistics() { + synchronized (monitor) { + return parent.summaryStatistics(); + } + } + + @Override + public boolean anyMatch(LongPredicate predicate) { + synchronized (monitor) { + return parent.anyMatch(predicate); + } + } + + @Override + public boolean allMatch(LongPredicate predicate) { + synchronized (monitor) { + return parent.allMatch(predicate); + } + } + + @Override + public boolean noneMatch(LongPredicate predicate) { + synchronized (monitor) { + return parent.noneMatch(predicate); + } + } + + @Override + public OptionalLong findFirst() { + synchronized (monitor) { + return parent.findFirst(); + } + } + + @Override + public OptionalLong findAny() { + synchronized (monitor) { + return parent.findAny(); + } + } + + } + + public static class SyncDoubleStream implements DoubleStream { + + private final DoubleStream parent; + private final Object monitor; + + public SyncDoubleStream(DoubleStream parent, Object monitor) { + this.parent = parent; + this.monitor = monitor == null ? this : monitor; + } + + public DoubleStream getParent() { + return parent; + } + + public Object getMonitor() { + return monitor; + } + + /* + * Returns null when child streams should sync on themselves + */ + private Object getInheritableMonitor() { + return monitor == this ? null : monitor; + } + + @Override + public void close() { + parent.close(); + } + + @Override + public PrimitiveIterator.OfDouble iterator() { + return parent.iterator(); + } + + @Override + public Spliterator.OfDouble spliterator() { + return parent.spliterator(); + } + + @Override + public boolean isParallel() { + return parent.isParallel(); + } + + @Override + public DoubleStream sequential() { + return synchronizedStream(parent.sequential(), getInheritableMonitor()); + } + + @Override + public DoubleStream parallel() { + return synchronizedStream(parent.parallel(), getInheritableMonitor()); + } + + @Override + public DoubleStream unordered() { + return synchronizedStream(parent.unordered(), getInheritableMonitor()); + } + + @Override + public DoubleStream onClose(Runnable closeHandler) { + return synchronizedStream(parent.onClose(closeHandler), getInheritableMonitor()); + } + + @Override + public DoubleStream filter(DoublePredicate predicate) { + return synchronizedStream(parent.filter(predicate), getInheritableMonitor()); + } + + @Override + public DoubleStream map(DoubleUnaryOperator mapper) { + return synchronizedStream(parent.map(mapper), getInheritableMonitor()); + } + + @Override + public IntStream mapToInt(DoubleToIntFunction mapper) { + return synchronizedStream(parent.mapToInt(mapper), getInheritableMonitor()); + } + + @Override + public LongStream mapToLong(DoubleToLongFunction mapper) { + return synchronizedStream(parent.mapToLong(mapper), getInheritableMonitor()); + } + + @Override + public Stream mapToObj(DoubleFunction mapper) { + return synchronizedStream(parent.mapToObj(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream flatMap(DoubleFunction mapper) { + return synchronizedStream(parent.flatMap(mapper), getInheritableMonitor()); + } + + @Override + public DoubleStream distinct() { + return synchronizedStream(parent.distinct(), getInheritableMonitor()); + } + + @Override + public DoubleStream sorted() { + return synchronizedStream(parent.sorted(), getInheritableMonitor()); + } + + @Override + public DoubleStream peek(DoubleConsumer action) { + return synchronizedStream(parent.peek(action), getInheritableMonitor()); + } + + @Override + public DoubleStream limit(long maxSize) { + return synchronizedStream(parent.limit(maxSize), getInheritableMonitor()); + } + + @Override + public DoubleStream skip(long n) { + return synchronizedStream(parent.skip(n), getInheritableMonitor()); + } + + @Override + public Stream boxed() { + return synchronizedStream(parent.boxed(), getInheritableMonitor()); + } + + @Override + public double reduce(double identity, DoubleBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(identity, accumulator); + } + } + + @Override + public OptionalDouble reduce(DoubleBinaryOperator accumulator) { + synchronized (monitor) { + return parent.reduce(accumulator); + } + } + + @Override + public void forEach(DoubleConsumer action) { + synchronized (monitor) { + parent.forEach(action); + } + } + + @Override + public void forEachOrdered(DoubleConsumer action) { + synchronized (monitor) { + parent.forEachOrdered(action); + } + } + + @Override + public double[] toArray() { + synchronized (monitor) { + return parent.toArray(); + } + } + + @Override + public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { + synchronized (monitor) { + return parent.collect(supplier, accumulator, combiner); + } + } + + @Override + public double sum() { + synchronized (monitor) { + return parent.sum(); + } + } + + @Override + public OptionalDouble min() { + synchronized (monitor) { + return parent.min(); + } + } + + @Override + public OptionalDouble max() { + synchronized (monitor) { + return parent.max(); + } + } + + @Override + public long count() { + synchronized (monitor) { + return parent.count(); + } + } + + @Override + public OptionalDouble average() { + synchronized (monitor) { + return parent.average(); + } + } + + @Override + public DoubleSummaryStatistics summaryStatistics() { + synchronized (monitor) { + return parent.summaryStatistics(); + } + } + + @Override + public boolean anyMatch(DoublePredicate predicate) { + synchronized (monitor) { + return parent.anyMatch(predicate); + } + } + + @Override + public boolean allMatch(DoublePredicate predicate) { + synchronized (monitor) { + return parent.allMatch(predicate); + } + } + + @Override + public boolean noneMatch(DoublePredicate predicate) { + synchronized (monitor) { + return parent.noneMatch(predicate); + } + } + + @Override + public OptionalDouble findFirst() { + synchronized (monitor) { + return parent.findFirst(); + } + } + + @Override + public OptionalDouble findAny() { + synchronized (monitor) { + return parent.findAny(); + } + } + + } + + /** + * Wraps the given {@link Stream} to make all + * + * terminal operations acquire the provided monitor's lock before + * execution. Intermediate operations + * return streams that are also synchronized on the same object. The created + * stream will behave identically + * to the provided stream in all other aspects. Use this to synchronize + * access to stream's source. + *

+ * The returned {@code Stream}'s {@link Stream#iterator() iterator()} and + * {@link Stream#spliterator() + * spliterator()} methods return regular non-synchronized iterators and + * spliterators respectively. It + * is the user's responsibility to avoid concurrency issues: + * + *

+	 * synchronized (stream.getMonitor()) {
+	 *     Iterator it = stream.iterator();
+	 *         ...
+	 * }
+	 * 
+ * + * Usage example: + * + *
+	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
+	 *    ...
+	 * Stream<?> stream = SyncStreams.synchronizedStream(s.stream(), s);
+	 * stream = stream.map(Object::toString); // Still synchronized
+	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
+	 * 
+ * + * @param the class of objects in the Stream + * @param stream the stream to wrap. + * @param monitor the object that the stream will use for synchronization. + * When {@code null}, the stream + * will synchronize on itself. + * @return a {@link SyncStream SyncStream<T>} synchronized on + * {@code monitor} and backed by {@code stream}. + * @throws NullPointerException if {@code stream == null}. + */ + public static SyncStream synchronizedStream(Stream stream, Object monitor) { + Objects.requireNonNull(stream, "stream cannot be null"); + return new SyncStream<>(stream, monitor); + } + + /** + * Wraps the given {@link IntStream} to make all + * + * terminal operations acquire the provided monitor's lock before + * execution. Intermediate operations + * return streams that are also synchronized on the same object. The created + * stream will behave identically + * to the provided stream in all other aspects. Use this to synchronize + * access to stream's source. + *

+ * The returned {@code IntStream}'s {@link IntStream#iterator() + * iterator()} and + * {@link IntStream#spliterator() spliterator()} methods return regular + * non-synchronized iterators and + * spliterators respectively. It is the user's responsibility to avoid + * concurrency issues: + * + *

+	 * synchronized (stream.getMonitor()) {
+	 *     PrimitiveIterator.OfInt it = stream.iterator();
+	 *         ...
+	 * }
+	 * 
+ * + * Usage example: + * + *
+	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
+	 *    ...
+	 * IntStream stream = SyncStreams.synchronizedStream(s.stream().mapToInt(Object::hashCode), s);
+	 * stream = stream.map(i -> i % 67); // Still synchronized
+	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
+	 * 
+ * + * @param stream the stream to wrap. + * @param monitor the object that the stream will use for synchronization. + * When {@code null}, the stream + * will synchronize on itself. + * @return a {@link SyncIntStream} synchronized on {@code monitor} and + * backed by {@code stream}. + * @throws NullPointerException if {@code stream == null}. + */ + public static SyncIntStream synchronizedStream(IntStream stream, Object monitor) { + Objects.requireNonNull(stream, "stream cannot be null"); + return new SyncIntStream(stream, monitor); + } + + /** + * Wraps the given {@link LongStream} to make all + * + * terminal operations acquire the provided monitor's lock before + * execution. Intermediate operations + * return streams that are also synchronized on the same object. The created + * stream will behave identically + * to the provided stream in all other aspects. Use this to synchronize + * access to stream's source. + *

+ * The returned {@code LongStream}'s {@link LongStream#iterator() + * iterator()} and + * {@link LongStream#spliterator() spliterator()} methods return regular + * non-synchronized iterators and + * spliterators respectively. It is the user's responsibility to avoid + * concurrency issues: + * + *

+	 * synchronized (stream.getMonitor()) {
+	 *     PrimitiveIterator.OfLong it = stream.iterator();
+	 *         ...
+	 * }
+	 * 
+ * + * Usage example: + * + *
+	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
+	 *    ...
+	 * LongStream stream = SyncStreams.synchronizedStream(s.stream().mapToLong(o -> (long) o.hashCode()), s);
+	 * stream = stream.map(i -> i % 67); // Still synchronized
+	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
+	 * 
+ * + * @param stream the stream to wrap. + * @param monitor the object that the stream will use for synchronization. + * When {@code null}, the stream + * will synchronize on itself. + * @return a {@link SyncLongStream} synchronized on {@code monitor} and + * backed by {@code stream}. + * @throws NullPointerException if {@code stream == null}. + */ + public static SyncLongStream synchronizedStream(LongStream stream, Object monitor) { + Objects.requireNonNull(stream, "stream cannot be null"); + return new SyncLongStream(stream, monitor); + } + + /** + * Wraps the given {@link DoubleStream} to make all + * + * terminal operations acquire the provided monitor's lock before + * execution. Intermediate operations + * return streams that are also synchronized on the same object. The created + * stream will behave identically + * to the provided stream in all other aspects. Use this to synchronize + * access to stream's source. + *

+ * The returned {@code DoubleStream}'s {@link DoubleStream#iterator() + * iterator()} and + * {@link DoubleStream#spliterator() spliterator()} methods return regular + * non-synchronized iterators and + * spliterators respectively. It is the user's responsibility to avoid + * concurrency issues: + * + *

+	 * synchronized (stream.getMonitor()) {
+	 *     PrimitiveIterator.OfDouble it = stream.iterator();
+	 *         ...
+	 * }
+	 * 
+ * + * Usage example: + * + *
+	 * Set<Object> s = Collections.synchronizedSet(new HashSet<>());
+	 *    ...
+	 * DoubleStream stream = SyncStreams.synchronizedStream(s.stream().mapToLong(o -> (double) o.hashCode()), s);
+	 * stream = stream.map(Math::sin); // Still synchronized
+	 * stream.forEach(System.out::println); // Should never throw a ConcurrentModificationException
+	 * 
+ * + * @param stream the stream to wrap. + * @param monitor the object that the stream will use for synchronization. + * When {@code null}, the stream + * will synchronize on itself. + * @return a {@link SyncDoubleStream} synchronized on {@code monitor} and + * backed by {@code stream}. + * @throws NullPointerException if {@code stream == null}. + */ + public static SyncDoubleStream synchronizedStream(DoubleStream stream, Object monitor) { + Objects.requireNonNull(stream, "stream cannot be null"); + return new SyncDoubleStream(stream, monitor); + } + + /* + * Private constructor + */ + private SyncStreams() { + } + +} diff --git a/src/main/java/ru/windcorp/jputil/SyntaxException.java b/src/main/java/ru/windcorp/jputil/SyntaxException.java index e47d123..02cc3c4 100644 --- a/src/main/java/ru/windcorp/jputil/SyntaxException.java +++ b/src/main/java/ru/windcorp/jputil/SyntaxException.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil; - -public class SyntaxException extends Exception { - - private static final long serialVersionUID = -4052144233640072750L; - - public SyntaxException() { - - } - - public SyntaxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - - public SyntaxException(String message, Throwable cause) { - super(message, cause); - } - - public SyntaxException(String message) { - super(message); - } - - public SyntaxException(Throwable cause) { - super(cause); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil; + +public class SyntaxException extends Exception { + + private static final long serialVersionUID = -4052144233640072750L; + + public SyntaxException() { + + } + + public SyntaxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public SyntaxException(String message, Throwable cause) { + super(message, cause); + } + + public SyntaxException(String message) { + super(message); + } + + public SyntaxException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java b/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java index f65ddf4..be0940d 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharArrayIterator.java @@ -1,128 +1,132 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.text.CharacterIterator; - -public class CharArrayIterator implements CharacterIterator { - - private final char[] array; - private int pos; - - public CharArrayIterator(char[] array) { - this.array = array; - } - - public CharArrayIterator(String src) { - this(src.toCharArray()); - } - - @Override - public char first() { - pos = 0; - if (array.length != 0) { - return array[pos]; - } - return DONE; - } - - @Override - public char last() { - pos = array.length; - if (array.length != 0) { - pos -= 1; - return array[pos]; - } - return DONE; - } - - @Override - public char current() { - if (array.length != 0 && pos < array.length) { - return array[pos]; - } - return DONE; - } - - @Override - public char next() { - pos += 1; - if (pos >= array.length) { - pos = array.length; - return DONE; - } - return current(); - } - - @Override - public char previous() { - if (pos == 0) { - return DONE; - } - pos -= 1; - return current(); - } - - @Override - public char setIndex(int position) { - if (position < 0 || position > array.length) { - throw new IllegalArgumentException("bad position: " + position); - } - - pos = position; - - if (pos != array.length && array.length != 0) { - return array[pos]; - } - return DONE; - } - - @Override - public int getBeginIndex() { - return 0; - } - - @Override - public int getEndIndex() { - return array.length; - } - - @Override - public int getIndex() { - return pos; - } - -// @SuppressWarnings("all") Just STFU, this _is_ terrific - - // SonarLint: "clone" should not be overridden (java:S2975) - // And I wouldn't have done that if only CharacterIterator had not required exception safety. - // SonarLint: "toString()" and "clone()" methods should not return null (java:S2225) - // The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object. - @SuppressWarnings({"squid:S2975", "squid:S2225"}) - - @Override - public CharArrayIterator clone() { - try { - return (CharArrayIterator) super.clone(); - } catch (CloneNotSupportedException cnse) { - // Impossible - return null; - } - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.text.CharacterIterator; + +public class CharArrayIterator implements CharacterIterator { + + private final char[] array; + private int pos; + + public CharArrayIterator(char[] array) { + this.array = array; + } + + public CharArrayIterator(String src) { + this(src.toCharArray()); + } + + @Override + public char first() { + pos = 0; + if (array.length != 0) { + return array[pos]; + } + return DONE; + } + + @Override + public char last() { + pos = array.length; + if (array.length != 0) { + pos -= 1; + return array[pos]; + } + return DONE; + } + + @Override + public char current() { + if (array.length != 0 && pos < array.length) { + return array[pos]; + } + return DONE; + } + + @Override + public char next() { + pos += 1; + if (pos >= array.length) { + pos = array.length; + return DONE; + } + return current(); + } + + @Override + public char previous() { + if (pos == 0) { + return DONE; + } + pos -= 1; + return current(); + } + + @Override + public char setIndex(int position) { + if (position < 0 || position > array.length) { + throw new IllegalArgumentException("bad position: " + position); + } + + pos = position; + + if (pos != array.length && array.length != 0) { + return array[pos]; + } + return DONE; + } + + @Override + public int getBeginIndex() { + return 0; + } + + @Override + public int getEndIndex() { + return array.length; + } + + @Override + public int getIndex() { + return pos; + } + +// @SuppressWarnings("all") Just STFU, this _is_ terrific + + // SonarLint: "clone" should not be overridden (java:S2975) + // And I wouldn't have done that if only CharacterIterator had not required + // exception safety. + // SonarLint: "toString()" and "clone()" methods should not return null + // (java:S2225) + // The clause is unreachable: CharacterArrayIterator implements Cloneable + // and superclass is Object. + @SuppressWarnings({ "squid:S2975", "squid:S2225" }) + + @Override + public CharArrayIterator clone() { + try { + return (CharArrayIterator) super.clone(); + } catch (CloneNotSupportedException cnse) { + // Impossible + return null; + } + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java b/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java index de1d372..7b68bb1 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharConsumer.java @@ -1,42 +1,43 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.util.function.IntConsumer; - -@FunctionalInterface -public interface CharConsumer { - - void accept(char c); - - public static CharConsumer andThen(CharConsumer first, CharConsumer second) { - return c -> { - first.accept(c); - second.accept(c); - }; - } - - public static IntConsumer toInt(CharConsumer consumer) { - return i -> consumer.accept((char) i); - } - - public static CharConsumer toChar(IntConsumer consumer) { - return consumer::accept; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.util.function.IntConsumer; + +@FunctionalInterface +public interface CharConsumer { + + void accept(char c); + + public static CharConsumer andThen(CharConsumer first, CharConsumer second) { + return c -> { + first.accept(c); + second.accept(c); + }; + } + + public static IntConsumer toInt(CharConsumer consumer) { + return i -> consumer.accept((char) i); + } + + public static CharConsumer toChar(IntConsumer consumer) { + return consumer::accept; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java b/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java index e0613bc..1ac7973 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharConsumers.java @@ -1,69 +1,70 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.util.Objects; - -import ru.windcorp.jputil.ArrayUtil; - -/** - * @author Javapony - * - */ -public class CharConsumers { - - private CharConsumers() {} - - public static CharConsumer fillArray(char[] array, int offset, int length) { - return new ArrayFiller(array, offset, length); - } - - public static CharConsumer fillArray(char[] array) { - return fillArray(array, 0, -1); - } - - private static class ArrayFiller implements CharConsumer { - - final char[] array; - int i; - final int end; - - /** - * @param array - * @param offset - * @param length - */ - ArrayFiller(char[] array, int offset, int length) { - this.array = Objects.requireNonNull(array, "array"); - this.end = ArrayUtil.checkArrayStartEnd(array, offset, offset + length); - this.i = offset; - } - - /** - * @see ru.windcorp.jputil.chars.CharConsumer#accept(char) - */ - @Override - public void accept(char c) { - if (i == end) - throw new ArrayIndexOutOfBoundsException(end); - array[i++] = c; - } - - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.util.Objects; + +import ru.windcorp.jputil.ArrayUtil; + +/** + * @author Javapony + */ +public class CharConsumers { + + private CharConsumers() { + } + + public static CharConsumer fillArray(char[] array, int offset, int length) { + return new ArrayFiller(array, offset, length); + } + + public static CharConsumer fillArray(char[] array) { + return fillArray(array, 0, -1); + } + + private static class ArrayFiller implements CharConsumer { + + final char[] array; + int i; + final int end; + + /** + * @param array + * @param offset + * @param length + */ + ArrayFiller(char[] array, int offset, int length) { + this.array = Objects.requireNonNull(array, "array"); + this.end = ArrayUtil.checkArrayStartEnd(array, offset, offset + length); + this.i = offset; + } + + /** + * @see ru.windcorp.jputil.chars.CharConsumer#accept(char) + */ + @Override + public void accept(char c) { + if (i == end) + throw new ArrayIndexOutOfBoundsException(end); + array[i++] = c; + } + + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java b/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java index b4be567..03ded02 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharPredicate.java @@ -1,84 +1,85 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.util.Arrays; -import java.util.function.IntPredicate; - -import ru.windcorp.jputil.ArrayUtil; - -@FunctionalInterface -public interface CharPredicate { - - boolean test(char c); - - public static CharPredicate and(CharPredicate first, CharPredicate second) { - return c -> first.test(c) && second.test(c); - } - - public static CharPredicate or(CharPredicate first, CharPredicate second) { - return c -> first.test(c) || second.test(c); - } - - public static CharPredicate negate(CharPredicate predicate) { - return c -> !predicate.test(c); - } - - public static IntPredicate toInt(CharPredicate predicate) { - return i -> predicate.test((char) i); - } - - public static CharPredicate toChar(IntPredicate predicate) { - return predicate::test; - } - - public static CharPredicate forArray(char... chars) { - if (chars.length == 0) { - return c -> false; - } - - if (chars.length == 1) { - return forChar(chars[0]); - } - - if (chars.length < 16) { - return c -> ArrayUtil.firstIndexOf(chars, c) >= 0; - } else { - final char[] sorted = Arrays.copyOf(chars, chars.length); - Arrays.sort(sorted); - return c -> Arrays.binarySearch(chars, c) >= 0; - } - } - - public static CharPredicate forChar(final char c) { - return given -> given == c; - } - - public static CharPredicate forRange(final char minInclusive, final char maxExclusive) { - if (minInclusive > maxExclusive) { - throw new IllegalArgumentException("min > max: " + minInclusive + " > " + maxExclusive); - } - - if (minInclusive == maxExclusive) { - return c -> false; - } - - return c -> c >= minInclusive && c < maxExclusive; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.util.Arrays; +import java.util.function.IntPredicate; + +import ru.windcorp.jputil.ArrayUtil; + +@FunctionalInterface +public interface CharPredicate { + + boolean test(char c); + + public static CharPredicate and(CharPredicate first, CharPredicate second) { + return c -> first.test(c) && second.test(c); + } + + public static CharPredicate or(CharPredicate first, CharPredicate second) { + return c -> first.test(c) || second.test(c); + } + + public static CharPredicate negate(CharPredicate predicate) { + return c -> !predicate.test(c); + } + + public static IntPredicate toInt(CharPredicate predicate) { + return i -> predicate.test((char) i); + } + + public static CharPredicate toChar(IntPredicate predicate) { + return predicate::test; + } + + public static CharPredicate forArray(char... chars) { + if (chars.length == 0) { + return c -> false; + } + + if (chars.length == 1) { + return forChar(chars[0]); + } + + if (chars.length < 16) { + return c -> ArrayUtil.firstIndexOf(chars, c) >= 0; + } else { + final char[] sorted = Arrays.copyOf(chars, chars.length); + Arrays.sort(sorted); + return c -> Arrays.binarySearch(chars, c) >= 0; + } + } + + public static CharPredicate forChar(final char c) { + return given -> given == c; + } + + public static CharPredicate forRange(final char minInclusive, final char maxExclusive) { + if (minInclusive > maxExclusive) { + throw new IllegalArgumentException("min > max: " + minInclusive + " > " + maxExclusive); + } + + if (minInclusive == maxExclusive) { + return c -> false; + } + + return c -> c >= minInclusive && c < maxExclusive; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java b/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java index 580deef..0743d79 100644 --- a/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java +++ b/src/main/java/ru/windcorp/jputil/chars/CharSupplier.java @@ -1,35 +1,36 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.util.function.IntSupplier; - -@FunctionalInterface -public interface CharSupplier { - - char getAsChar(); - - public static IntSupplier toInt(CharSupplier consumer) { - return consumer::getAsChar; - } - - public static CharSupplier toChar(IntSupplier consumer) { - return () -> (char) consumer.getAsInt(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.util.function.IntSupplier; + +@FunctionalInterface +public interface CharSupplier { + + char getAsChar(); + + public static IntSupplier toInt(CharSupplier consumer) { + return consumer::getAsChar; + } + + public static CharSupplier toChar(IntSupplier consumer) { + return () -> (char) consumer.getAsInt(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/EscapeException.java b/src/main/java/ru/windcorp/jputil/chars/EscapeException.java index 2578dad..935f72f 100644 --- a/src/main/java/ru/windcorp/jputil/chars/EscapeException.java +++ b/src/main/java/ru/windcorp/jputil/chars/EscapeException.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -public class EscapeException extends Exception { - - private static final long serialVersionUID = -3647188859290365053L; - - public EscapeException() { - super(); - } - - public EscapeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - - public EscapeException(String message, Throwable cause) { - super(message, cause); - } - - public EscapeException(String message) { - super(message); - } - - public EscapeException(Throwable cause) { - super(cause); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +public class EscapeException extends Exception { + + private static final long serialVersionUID = -3647188859290365053L; + + public EscapeException() { + super(); + } + + public EscapeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public EscapeException(String message, Throwable cause) { + super(message, cause); + } + + public EscapeException(String message) { + super(message); + } + + public EscapeException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/Escaper.java b/src/main/java/ru/windcorp/jputil/chars/Escaper.java index 17e9b26..f19f6c7 100644 --- a/src/main/java/ru/windcorp/jputil/chars/Escaper.java +++ b/src/main/java/ru/windcorp/jputil/chars/Escaper.java @@ -1,474 +1,514 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.text.CharacterIterator; - -import ru.windcorp.jputil.ArrayUtil; -import ru.windcorp.jputil.chars.reader.CharReader; -import ru.windcorp.jputil.chars.reader.CharReaders; - -public class Escaper { - - public static class EscaperBuilder { - private char escapeChar = '\\'; - private char unicodeEscapeChar = 'u'; - private char[] safes = null; - private char[] unsafes = null; - - private boolean preferUnicode = false; - private boolean strict = true; - - public EscaperBuilder withEscapeChar(char escapeChar) { - this.escapeChar = escapeChar; - return this; - } - - public EscaperBuilder withUnicodeEscapeChar(char unicodeEscapeChar) { - this.unicodeEscapeChar = unicodeEscapeChar; - return this; - } - - public EscaperBuilder withChars(char[] safes, char[] unsafes) { - this.safes = safes; - this.unsafes = unsafes; - return this; - } - - public EscaperBuilder withChars(String safes, String unsafes) { - this.safes = safes.toCharArray(); - this.unsafes = unsafes.toCharArray(); - return this; - } - - public EscaperBuilder withChars(char[] chars) { - this.safes = this.unsafes = chars; - return this; - } - - public EscaperBuilder withChars(String chars) { - this.safes = this.unsafes = chars.toCharArray(); - return this; - } - - public EscaperBuilder withSafes(char[] safes) { - this.safes = safes; - return this; - } - - public EscaperBuilder withSafes(String safes) { - this.safes = safes.toCharArray(); - return this; - } - - public EscaperBuilder withUnsafes(char[] unsafes) { - this.unsafes = unsafes; - return this; - } - - public EscaperBuilder withUnsafes(String unsafes) { - this.unsafes = unsafes.toCharArray(); - return this; - } - - public EscaperBuilder preferUnicode(boolean preferUnicode) { - this.preferUnicode = preferUnicode; - return this; - } - - public EscaperBuilder strict(boolean strict) { - this.strict = strict; - return this; - } - - public Escaper build() { - return new Escaper(escapeChar, unicodeEscapeChar, safes, unsafes, preferUnicode, strict); - } - - } - - public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(), true, true); - - private final char escapeChar; - private final char unicodeEscapeChar; - private final char[] safes; - private final char[] unsafes; - - private final boolean preferUnicode; - private final boolean strict; - - protected Escaper( - char escapeChar, char unicodeEscapeChar, - char[] safes, char[] unsafes, - boolean preferUnicode, boolean strict) { - this.escapeChar = escapeChar; - this.unicodeEscapeChar = unicodeEscapeChar; - this.safes = safes; - this.unsafes = unsafes; - this.preferUnicode = preferUnicode; - this.strict = strict; - - int duplicate; - if ((duplicate = ArrayUtil.hasDuplicates(safes)) != -1) - throw new IllegalArgumentException("Duplicate safe character '" + safes[duplicate] + "'"); - - if ((duplicate = ArrayUtil.hasDuplicates(unsafes)) != -1) - throw new IllegalArgumentException("Duplicate unsafe character '" + unsafes[duplicate] + "'"); - - for (char c : safes) { - if (c == escapeChar) throw new IllegalArgumentException("Safe characters contain escape chatacter"); - if (c == unicodeEscapeChar) throw new IllegalArgumentException("Safe characters contain Unicode escape chatacter"); - } - - for (char c : unsafes) { - if (c == escapeChar) throw new IllegalArgumentException("Unsafe characters contain escape chatacter (escape character is escaped automatically)"); - if (c == unicodeEscapeChar) throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter"); - } - } - - public static EscaperBuilder create() { - return new EscaperBuilder(); - } - - /* - * Logic - escape - */ - - public void escape(CharReader src, int length, CharPredicate until, CharConsumer output) { - int end; - if (length < 0) end = Integer.MAX_VALUE; - else end = src.getPosition() + length; - while (src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current()))) - escape(src.consume(), output); - } - - public void escape(char c, CharConsumer output) { - if (c == escapeChar) { - output.accept(escapeChar); - output.accept(escapeChar); - return; - } - - int index = ArrayUtil.firstIndexOf(unsafes, c); - - if (index >= 0) { - output.accept(escapeChar); - output.accept(safes[index]); - } else { - if (preferUnicode && !isRegular(c)) { - escapeAsHex(c, output); - } else { - output.accept(c); - } - } - } - - // SonarLint: Assignments should not be made from within sub-expressions (java:S1121) - // Seems self-evident enough - @SuppressWarnings("squid:S1121") - - private void escapeAsHex(char c, CharConsumer output) { - output.accept(escapeChar); - output.accept(unicodeEscapeChar); - output.accept(StringUtil.hexDigit(c >>= (4 * 3))); - output.accept(StringUtil.hexDigit(c >>= (4 * 2))); - output.accept(StringUtil.hexDigit(c >>= (4 * 1))); - output.accept(StringUtil.hexDigit(c >> (4 * 0))); - } - - public int getEscapedLength(CharReader src, int length, CharPredicate until) { - int end; - if (length < 0) end = Integer.MAX_VALUE; - else end = src.getPosition() + length; - - int result = 0; - - while (src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current()))) { - result += getEscapedLength(src.consume()); - } - - return result; - } - - public int getEscapedLength(char c) { - if (c == escapeChar || ArrayUtil.firstIndexOf(unsafes, c) >= 0) - return 2; - else { - if (preferUnicode && !isRegular(c)) - return 6; - else - return 1; - } - } - - /* - * Logic - unescape - */ - - public void unescape(CharReader src, int length, CharPredicate until, CharConsumer output) throws EscapeException { - int end; - if (length < 0) end = Integer.MAX_VALUE; - else end = src.getPosition() + length; - while (src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current()))) { - output.accept(unescapeOneSequence(src)); - } - } - - public char unescapeOneSequence(CharReader src) throws EscapeException { - int resetPos = src.getPosition(); - try { - if (src.current() == escapeChar) { - src.next(); - - if (src.isEnd()) - throw new EscapeException("Incomplete escape sequence at the end"); - - if (src.current() == escapeChar) { - src.next(); - return escapeChar; - } - - if (src.current() == unicodeEscapeChar) { - src.next(); - return (char) ( - hexValue(src.consume()) << (4 * 3) | - hexValue(src.consume()) << (4 * 2) | - hexValue(src.consume()) << (4 * 1) | - hexValue(src.consume()) << (4 * 0) - ); - } - - int index = ArrayUtil.firstIndexOf(safes, src.current()); - if (index >= 0) { - src.next(); - return unsafes[index]; - } - - if (strict) - throw new EscapeException("Unknown escape sequence \"" + escapeChar + src.current() + "\""); - else - return src.consume(); - } else - return src.consume(); - } catch (EscapeException | RuntimeException e) { - src.setPosition(resetPos); - throw e; - } - } - - public int getUnescapedLength(CharReader src, int length, CharPredicate until) { - int end; - if (length < 0) end = Integer.MAX_VALUE; - else end = src.getPosition() + length; - - int result = 0; - - while (src.has() && - src.getPosition() < end && - (until == null || !until.test(src.current()))) { - skipOneSequence(src); - result++; - } - - return result; - } - - public void skipOneSequence(CharReader src) { - if ( - src.current() == escapeChar - && - src.next() == unicodeEscapeChar - ) { - src.advance(4); - } - src.next(); - } - - /* - * Utility - */ - - public void escape(CharReader src, int length, CharConsumer output) { - escape(src, length, null, output); - } - - public void escape(CharReader src, CharPredicate until, CharConsumer output) { - escape(src, -1, until, output); - } - - public void escape(CharReader src, CharConsumer output) { - escape(src, -1, null, output); - } - - public int getEscapedLength(CharReader src, int length) { - return getEscapedLength(src, length, null); - } - - public int getEscapedLength(CharReader src, CharPredicate until) { - return getEscapedLength(src, -1, until); - } - - public int getEscapedLength(CharReader src) { - return getEscapedLength(src, -1, null); - } - - public char[] escape(CharReader src, int length, CharPredicate until) { - src.mark(); - char[] result = new char[getEscapedLength(src, length, until)]; - src.reset(); - escape(src, length, until, CharConsumers.fillArray(result)); - return result; - } - - public char[] escape(CharReader src, int length) { - return escape(src, length, (CharPredicate) null); - } - - public char[] escape(CharReader src, CharPredicate until) { - return escape(src, -1, until); - } - - public char[] escape(CharReader src) { - return escape(src, -1, (CharPredicate) null); - } - - public void unescape(CharReader src, int length, CharConsumer output) throws EscapeException { - unescape(src, length, null, output); - } - - public void unescape(CharReader src, CharPredicate until, CharConsumer output) throws EscapeException { - unescape(src, -1, until, output); - } - - public void unescape(CharReader src, CharConsumer output) throws EscapeException { - unescape(src, -1, null, output); - } - - public int getUnescapedLength(CharReader src, int length) { - return getUnescapedLength(src, length, null); - } - - public int getUnescapedLength(CharReader src, CharPredicate until) { - return getUnescapedLength(src, -1, until); - } - - public int getUnescapedLength(CharReader src) { - return getUnescapedLength(src, -1, null); - } - - public char[] unescape(CharReader src, int length, CharPredicate until) throws EscapeException { - src.mark(); - char[] result = new char[getUnescapedLength(src, length, until)]; - src.reset(); - unescape(src, length, until, CharConsumers.fillArray(result)); - return result; - } - - public char[] unescape(CharReader src, int length) throws EscapeException { - return unescape(src, length, (CharPredicate) null); - } - - public char[] unescape(CharReader src, CharPredicate until) throws EscapeException { - return unescape(src, -1, until); - } - - public char[] unescape(CharReader src) throws EscapeException { - return unescape(src, -1, (CharPredicate) null); - } - - @Deprecated() - public char[] unescape(CharacterIterator src, char until) throws EscapeException { - int index = src.getIndex(); - CharReader reader = CharReaders.wrap(src); - - char[] result = unescape(reader, -1, CharPredicate.forChar(until)); - - src.setIndex(index + reader.getPosition()); - return result; - } - - public String escape(String src) { - StringBuilder result = new StringBuilder(src.length()); - escape(CharReaders.wrap(src), (CharConsumer) result::append); - return result.toString(); - } - - public String unescape(String src) throws EscapeException { - StringBuilder result = new StringBuilder(src.length()); - unescape(CharReaders.wrap(src), (CharConsumer) result::append); - return result.toString(); - } - - /* - * Misc - */ - - private static int hexValue(char c) throws EscapeException { - if (c < '0') throw thisIsNotAHexDigit(c); - if (c <= '9') return c - '0'; - if (c < 'A') throw thisIsNotAHexDigit(c); - if (c <= 'F') return c - 'A'; - if (c < 'a') throw thisIsNotAHexDigit(c); - if (c <= 'f') return c - 'a'; - if (c == CharReader.DONE) throw new EscapeException("Incomplete Unicode escape sequence at the end"); - throw thisIsNotAHexDigit(c); - } - - private static EscapeException thisIsNotAHexDigit(char c) { - return new EscapeException("Invalid hex digit '" + c + "', expected [0-9A-Fa-f]"); - } - - protected static boolean isRegular(char c) { - return c >= ' ' && c <= '~'; - } - - /* - * Getters / setters - */ - - public char getEscapeChar() { - return escapeChar; - } - - public char getUnicodeEscapeChar() { - return unicodeEscapeChar; - } - - public char[] getSafes() { - return safes; - } - - public char[] getUnsafes() { - return unsafes; - } - - public boolean isPreferUnicode() { - return preferUnicode; - } - - public boolean isStrict() { - return strict; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.text.CharacterIterator; + +import ru.windcorp.jputil.ArrayUtil; +import ru.windcorp.jputil.chars.reader.CharReader; +import ru.windcorp.jputil.chars.reader.CharReaders; + +public class Escaper { + + public static class EscaperBuilder { + private char escapeChar = '\\'; + private char unicodeEscapeChar = 'u'; + private char[] safes = null; + private char[] unsafes = null; + + private boolean preferUnicode = false; + private boolean strict = true; + + public EscaperBuilder withEscapeChar(char escapeChar) { + this.escapeChar = escapeChar; + return this; + } + + public EscaperBuilder withUnicodeEscapeChar(char unicodeEscapeChar) { + this.unicodeEscapeChar = unicodeEscapeChar; + return this; + } + + public EscaperBuilder withChars(char[] safes, char[] unsafes) { + this.safes = safes; + this.unsafes = unsafes; + return this; + } + + public EscaperBuilder withChars(String safes, String unsafes) { + this.safes = safes.toCharArray(); + this.unsafes = unsafes.toCharArray(); + return this; + } + + public EscaperBuilder withChars(char[] chars) { + this.safes = this.unsafes = chars; + return this; + } + + public EscaperBuilder withChars(String chars) { + this.safes = this.unsafes = chars.toCharArray(); + return this; + } + + public EscaperBuilder withSafes(char[] safes) { + this.safes = safes; + return this; + } + + public EscaperBuilder withSafes(String safes) { + this.safes = safes.toCharArray(); + return this; + } + + public EscaperBuilder withUnsafes(char[] unsafes) { + this.unsafes = unsafes; + return this; + } + + public EscaperBuilder withUnsafes(String unsafes) { + this.unsafes = unsafes.toCharArray(); + return this; + } + + public EscaperBuilder preferUnicode(boolean preferUnicode) { + this.preferUnicode = preferUnicode; + return this; + } + + public EscaperBuilder strict(boolean strict) { + this.strict = strict; + return this; + } + + public Escaper build() { + return new Escaper(escapeChar, unicodeEscapeChar, safes, unsafes, preferUnicode, strict); + } + + } + + public static final Escaper JAVA = new Escaper( + '\\', + 'u', + "tbnrf'\"".toCharArray(), + "\t\b\n\r\f\'\"".toCharArray(), + true, + true + ); + + private final char escapeChar; + private final char unicodeEscapeChar; + private final char[] safes; + private final char[] unsafes; + + private final boolean preferUnicode; + private final boolean strict; + + protected Escaper( + char escapeChar, + char unicodeEscapeChar, + char[] safes, + char[] unsafes, + boolean preferUnicode, + boolean strict + ) { + this.escapeChar = escapeChar; + this.unicodeEscapeChar = unicodeEscapeChar; + this.safes = safes; + this.unsafes = unsafes; + this.preferUnicode = preferUnicode; + this.strict = strict; + + int duplicate; + if ((duplicate = ArrayUtil.hasDuplicates(safes)) != -1) + throw new IllegalArgumentException("Duplicate safe character '" + safes[duplicate] + "'"); + + if ((duplicate = ArrayUtil.hasDuplicates(unsafes)) != -1) + throw new IllegalArgumentException("Duplicate unsafe character '" + unsafes[duplicate] + "'"); + + for (char c : safes) { + if (c == escapeChar) + throw new IllegalArgumentException("Safe characters contain escape chatacter"); + if (c == unicodeEscapeChar) + throw new IllegalArgumentException("Safe characters contain Unicode escape chatacter"); + } + + for (char c : unsafes) { + if (c == escapeChar) + throw new IllegalArgumentException( + "Unsafe characters contain escape chatacter (escape character is escaped automatically)" + ); + if (c == unicodeEscapeChar) + throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter"); + } + } + + public static EscaperBuilder create() { + return new EscaperBuilder(); + } + + /* + * Logic - escape + */ + + public void escape(CharReader src, int length, CharPredicate until, CharConsumer output) { + int end; + if (length < 0) + end = Integer.MAX_VALUE; + else + end = src.getPosition() + length; + while ( + src.has() && + src.getPosition() < end && + (until == null || !until.test(src.current())) + ) + escape(src.consume(), output); + } + + public void escape(char c, CharConsumer output) { + if (c == escapeChar) { + output.accept(escapeChar); + output.accept(escapeChar); + return; + } + + int index = ArrayUtil.firstIndexOf(unsafes, c); + + if (index >= 0) { + output.accept(escapeChar); + output.accept(safes[index]); + } else { + if (preferUnicode && !isRegular(c)) { + escapeAsHex(c, output); + } else { + output.accept(c); + } + } + } + + // SonarLint: Assignments should not be made from within sub-expressions + // (java:S1121) + // Seems self-evident enough + @SuppressWarnings("squid:S1121") + + private void escapeAsHex(char c, CharConsumer output) { + output.accept(escapeChar); + output.accept(unicodeEscapeChar); + output.accept(StringUtil.hexDigit(c >>= (4 * 3))); + output.accept(StringUtil.hexDigit(c >>= (4 * 2))); + output.accept(StringUtil.hexDigit(c >>= (4 * 1))); + output.accept(StringUtil.hexDigit(c >> (4 * 0))); + } + + public int getEscapedLength(CharReader src, int length, CharPredicate until) { + int end; + if (length < 0) + end = Integer.MAX_VALUE; + else + end = src.getPosition() + length; + + int result = 0; + + while ( + src.has() && + src.getPosition() < end && + (until == null || !until.test(src.current())) + ) { + result += getEscapedLength(src.consume()); + } + + return result; + } + + public int getEscapedLength(char c) { + if (c == escapeChar || ArrayUtil.firstIndexOf(unsafes, c) >= 0) + return 2; + else { + if (preferUnicode && !isRegular(c)) + return 6; + else + return 1; + } + } + + /* + * Logic - unescape + */ + + public void unescape(CharReader src, int length, CharPredicate until, CharConsumer output) throws EscapeException { + int end; + if (length < 0) + end = Integer.MAX_VALUE; + else + end = src.getPosition() + length; + while ( + src.has() && + src.getPosition() < end && + (until == null || !until.test(src.current())) + ) { + output.accept(unescapeOneSequence(src)); + } + } + + public char unescapeOneSequence(CharReader src) throws EscapeException { + int resetPos = src.getPosition(); + try { + if (src.current() == escapeChar) { + src.next(); + + if (src.isEnd()) + throw new EscapeException("Incomplete escape sequence at the end"); + + if (src.current() == escapeChar) { + src.next(); + return escapeChar; + } + + if (src.current() == unicodeEscapeChar) { + src.next(); + return (char) (hexValue(src.consume()) << (4 * 3) | + hexValue(src.consume()) << (4 * 2) | + hexValue(src.consume()) << (4 * 1) | + hexValue(src.consume()) << (4 * 0)); + } + + int index = ArrayUtil.firstIndexOf(safes, src.current()); + if (index >= 0) { + src.next(); + return unsafes[index]; + } + + if (strict) + throw new EscapeException("Unknown escape sequence \"" + escapeChar + src.current() + "\""); + else + return src.consume(); + } else + return src.consume(); + } catch (EscapeException | RuntimeException e) { + src.setPosition(resetPos); + throw e; + } + } + + public int getUnescapedLength(CharReader src, int length, CharPredicate until) { + int end; + if (length < 0) + end = Integer.MAX_VALUE; + else + end = src.getPosition() + length; + + int result = 0; + + while ( + src.has() && + src.getPosition() < end && + (until == null || !until.test(src.current())) + ) { + skipOneSequence(src); + result++; + } + + return result; + } + + public void skipOneSequence(CharReader src) { + if ( + src.current() == escapeChar + && + src.next() == unicodeEscapeChar + ) { + src.advance(4); + } + src.next(); + } + + /* + * Utility + */ + + public void escape(CharReader src, int length, CharConsumer output) { + escape(src, length, null, output); + } + + public void escape(CharReader src, CharPredicate until, CharConsumer output) { + escape(src, -1, until, output); + } + + public void escape(CharReader src, CharConsumer output) { + escape(src, -1, null, output); + } + + public int getEscapedLength(CharReader src, int length) { + return getEscapedLength(src, length, null); + } + + public int getEscapedLength(CharReader src, CharPredicate until) { + return getEscapedLength(src, -1, until); + } + + public int getEscapedLength(CharReader src) { + return getEscapedLength(src, -1, null); + } + + public char[] escape(CharReader src, int length, CharPredicate until) { + src.mark(); + char[] result = new char[getEscapedLength(src, length, until)]; + src.reset(); + escape(src, length, until, CharConsumers.fillArray(result)); + return result; + } + + public char[] escape(CharReader src, int length) { + return escape(src, length, (CharPredicate) null); + } + + public char[] escape(CharReader src, CharPredicate until) { + return escape(src, -1, until); + } + + public char[] escape(CharReader src) { + return escape(src, -1, (CharPredicate) null); + } + + public void unescape(CharReader src, int length, CharConsumer output) throws EscapeException { + unescape(src, length, null, output); + } + + public void unescape(CharReader src, CharPredicate until, CharConsumer output) throws EscapeException { + unescape(src, -1, until, output); + } + + public void unescape(CharReader src, CharConsumer output) throws EscapeException { + unescape(src, -1, null, output); + } + + public int getUnescapedLength(CharReader src, int length) { + return getUnescapedLength(src, length, null); + } + + public int getUnescapedLength(CharReader src, CharPredicate until) { + return getUnescapedLength(src, -1, until); + } + + public int getUnescapedLength(CharReader src) { + return getUnescapedLength(src, -1, null); + } + + public char[] unescape(CharReader src, int length, CharPredicate until) throws EscapeException { + src.mark(); + char[] result = new char[getUnescapedLength(src, length, until)]; + src.reset(); + unescape(src, length, until, CharConsumers.fillArray(result)); + return result; + } + + public char[] unescape(CharReader src, int length) throws EscapeException { + return unescape(src, length, (CharPredicate) null); + } + + public char[] unescape(CharReader src, CharPredicate until) throws EscapeException { + return unescape(src, -1, until); + } + + public char[] unescape(CharReader src) throws EscapeException { + return unescape(src, -1, (CharPredicate) null); + } + + @Deprecated() + public char[] unescape(CharacterIterator src, char until) throws EscapeException { + int index = src.getIndex(); + CharReader reader = CharReaders.wrap(src); + + char[] result = unescape(reader, -1, CharPredicate.forChar(until)); + + src.setIndex(index + reader.getPosition()); + return result; + } + + public String escape(String src) { + StringBuilder result = new StringBuilder(src.length()); + escape(CharReaders.wrap(src), (CharConsumer) result::append); + return result.toString(); + } + + public String unescape(String src) throws EscapeException { + StringBuilder result = new StringBuilder(src.length()); + unescape(CharReaders.wrap(src), (CharConsumer) result::append); + return result.toString(); + } + + /* + * Misc + */ + + private static int hexValue(char c) throws EscapeException { + if (c < '0') + throw thisIsNotAHexDigit(c); + if (c <= '9') + return c - '0'; + if (c < 'A') + throw thisIsNotAHexDigit(c); + if (c <= 'F') + return c - 'A'; + if (c < 'a') + throw thisIsNotAHexDigit(c); + if (c <= 'f') + return c - 'a'; + if (c == CharReader.DONE) + throw new EscapeException("Incomplete Unicode escape sequence at the end"); + throw thisIsNotAHexDigit(c); + } + + private static EscapeException thisIsNotAHexDigit(char c) { + return new EscapeException("Invalid hex digit '" + c + "', expected [0-9A-Fa-f]"); + } + + protected static boolean isRegular(char c) { + return c >= ' ' && c <= '~'; + } + + /* + * Getters / setters + */ + + public char getEscapeChar() { + return escapeChar; + } + + public char getUnicodeEscapeChar() { + return unicodeEscapeChar; + } + + public char[] getSafes() { + return safes; + } + + public char[] getUnsafes() { + return unsafes; + } + + public boolean isPreferUnicode() { + return preferUnicode; + } + + public boolean isStrict() { + return strict; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java b/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java index b309786..183b672 100644 --- a/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java +++ b/src/main/java/ru/windcorp/jputil/chars/FancyCharacterIterator.java @@ -1,17 +1,21 @@ -/* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + package ru.windcorp.jputil.chars; import java.text.CharacterIterator; @@ -26,77 +30,81 @@ public class FancyCharacterIterator implements CharacterIterator { this.data = data; } - @Override + @Override public char first() { return obj.first(); } - @Override + @Override public char last() { return obj.last(); } - @Override + @Override public char setIndex(int p) { return obj.setIndex(p); } - @Override + @Override public char current() { return obj.current(); } - @Override + @Override public char next() { return obj.next(); } - @Override + @Override public char previous() { return obj.previous(); } - @Override + @Override public int getBeginIndex() { return obj.getBeginIndex(); } - @Override + @Override public int getEndIndex() { return obj.getEndIndex(); } - @Override + @Override public int getIndex() { return obj.getIndex(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder("\""); sb.append(data); sb.append("\"\n "); - for (int i = 0; i < obj.getIndex(); ++i) sb.append(' '); + for (int i = 0; i < obj.getIndex(); ++i) + sb.append(' '); sb.append("^ Here."); return sb.toString(); } - -// @SuppressWarnings("all") Just STFU, this _is_ terrific - - // SonarLint: "clone" should not be overridden (java:S2975) - // And I wouldn't have done that if only CharacterIterator had not required exception safety. - // SonarLint: "toString()" and "clone()" methods should not return null (java:S2225) - // The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object. - @SuppressWarnings({"squid:S2975", "squid:S2225"}) - - @Override - public FancyCharacterIterator clone() { - try { - return (FancyCharacterIterator) super.clone(); - } catch (CloneNotSupportedException cnse) { - // Impossible - return null; - } - } -} \ No newline at end of file +// @SuppressWarnings("all") Just STFU, this _is_ terrific + + // SonarLint: "clone" should not be overridden (java:S2975) + // And I wouldn't have done that if only CharacterIterator had not required + // exception safety. + // SonarLint: "toString()" and "clone()" methods should not return null + // (java:S2225) + // The clause is unreachable: CharacterArrayIterator implements Cloneable + // and superclass is Object. + @SuppressWarnings({ "squid:S2975", "squid:S2225" }) + + @Override + public FancyCharacterIterator clone() { + try { + return (FancyCharacterIterator) super.clone(); + } catch (CloneNotSupportedException cnse) { + // Impossible + return null; + } + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java b/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java index 2bfe3b6..92ba836 100644 --- a/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java +++ b/src/main/java/ru/windcorp/jputil/chars/IndentedStringBuilder.java @@ -1,135 +1,138 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -public class IndentedStringBuilder { - - private final StringBuilder sb = new StringBuilder(); - - private int indentLevel = 0; - private boolean indentApplied = false; - - private String[] indentCache = new String[16]; - private String indent = ""; - private final char[] indentFill; - - public IndentedStringBuilder(char[] indentFill) { - this.indentFill = indentFill; - } - - public IndentedStringBuilder(String indentFill) { - this(indentFill.toCharArray()); - } - - public IndentedStringBuilder(char indentChar, int length) { - this(StringUtil.sequence(indentChar, length)); - } - - public IndentedStringBuilder() { - this(new char[] {' '}); - } - - @Override - public String toString() { - return sb.toString(); - } - - public int getIndentLevel() { - return indentLevel; - } - - public void setIndentLevel(int level) { - this.indentLevel = level; - updateIndent(); - } - - public char[] getIndentFill() { - return indentFill; - } - - protected void updateIndent() { - if (indentLevel < indentCache.length) { - indent = indentCache[indentLevel]; - if (indent != null) return; - } - - char[] fill = getIndentFill(); - char[] array = new char[fill.length * getIndentLevel()]; - for (int i = 0; i < array.length; i += fill.length) - System.arraycopy(fill, 0, array, i, fill.length); - indent = new String(array); - - if (indentLevel < indentCache.length) { - indentCache[indentLevel] = indent; - } - } - - public IndentedStringBuilder indent() { - setIndentLevel(getIndentLevel() + 1); - return this; - } - - public IndentedStringBuilder unindent() { - setIndentLevel(getIndentLevel() - 1); - return this; - } - - public IndentedStringBuilder append(Object x) { - if (x == null) { - appendRaw("null"); - return this; - } - - String str = x.toString(); - int newLines = StringUtil.count(str, '\n'); - - if (newLines == 0) { - appendRaw(str); - return this; - } - - String[] lines = StringUtil.split(str, '\n', newLines + 1); - appendRaw(lines[0]); - - for (int i = 1; i < lines.length; ++i) { - newLine(); - appendRaw(lines[i]); - } - - return this; - } - - public IndentedStringBuilder appendRaw(String str) { - if (str.isEmpty()) return this; // Do not append indent - - if (!indentApplied) { - sb.append(indent); - indentApplied = true; - } - - sb.append(str); - return this; - } - - public IndentedStringBuilder newLine() { - sb.append('\n'); - indentApplied = false; - return this; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +public class IndentedStringBuilder { + + private final StringBuilder sb = new StringBuilder(); + + private int indentLevel = 0; + private boolean indentApplied = false; + + private String[] indentCache = new String[16]; + private String indent = ""; + private final char[] indentFill; + + public IndentedStringBuilder(char[] indentFill) { + this.indentFill = indentFill; + } + + public IndentedStringBuilder(String indentFill) { + this(indentFill.toCharArray()); + } + + public IndentedStringBuilder(char indentChar, int length) { + this(StringUtil.sequence(indentChar, length)); + } + + public IndentedStringBuilder() { + this(new char[] { ' ' }); + } + + @Override + public String toString() { + return sb.toString(); + } + + public int getIndentLevel() { + return indentLevel; + } + + public void setIndentLevel(int level) { + this.indentLevel = level; + updateIndent(); + } + + public char[] getIndentFill() { + return indentFill; + } + + protected void updateIndent() { + if (indentLevel < indentCache.length) { + indent = indentCache[indentLevel]; + if (indent != null) + return; + } + + char[] fill = getIndentFill(); + char[] array = new char[fill.length * getIndentLevel()]; + for (int i = 0; i < array.length; i += fill.length) + System.arraycopy(fill, 0, array, i, fill.length); + indent = new String(array); + + if (indentLevel < indentCache.length) { + indentCache[indentLevel] = indent; + } + } + + public IndentedStringBuilder indent() { + setIndentLevel(getIndentLevel() + 1); + return this; + } + + public IndentedStringBuilder unindent() { + setIndentLevel(getIndentLevel() - 1); + return this; + } + + public IndentedStringBuilder append(Object x) { + if (x == null) { + appendRaw("null"); + return this; + } + + String str = x.toString(); + int newLines = StringUtil.count(str, '\n'); + + if (newLines == 0) { + appendRaw(str); + return this; + } + + String[] lines = StringUtil.split(str, '\n', newLines + 1); + appendRaw(lines[0]); + + for (int i = 1; i < lines.length; ++i) { + newLine(); + appendRaw(lines[i]); + } + + return this; + } + + public IndentedStringBuilder appendRaw(String str) { + if (str.isEmpty()) + return this; // Do not append indent + + if (!indentApplied) { + sb.append(indent); + indentApplied = true; + } + + sb.append(str); + return this; + } + + public IndentedStringBuilder newLine() { + sb.append('\n'); + indentApplied = false; + return this; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java index 0aaf7a6..f08018a 100644 --- a/src/main/java/ru/windcorp/jputil/chars/StringUtil.java +++ b/src/main/java/ru/windcorp/jputil/chars/StringUtil.java @@ -1,940 +1,1032 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.Objects; -import java.util.function.IntFunction; - -import ru.windcorp.jputil.ArrayUtil; - -public class StringUtil { - - private StringUtil() {} - - private static final String NULL_PLACEHOLDER = "[null]"; - private static final String EMPTY_PLACEHOLDER = "[empty]"; - private static final String DEFAULT_SEPARATOR = "; "; - - public static String arrayToString( - T[] array, - String separator, - String empty, - String nullPlaceholder, - String nullArray - ) { - - if (separator == null) { - throw new IllegalArgumentException(new NullPointerException()); - } - - if (array == null) { - return nullArray; - } - - if (array.length == 0) { - return empty; - } - - StringBuilder sb = new StringBuilder(array[0] == null ? nullPlaceholder : array[0].toString()); - - for (int i = 1; i < array.length; ++i) { - sb.append(separator); - sb.append(array[i] == null ? nullPlaceholder : array[i].toString()); - } - - return sb.toString(); - } - - public static String arrayToString(T[] array, String separator) { - return arrayToString(array, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null array]"); - } - - public static String arrayToString(T[] array) { - return arrayToString(array, DEFAULT_SEPARATOR); - } - - public static String iteratorToString( - Iterator iterator, - String separator, - String empty, - String nullPlaceholder, - String nullIterator - ) { - - if (separator == null) { - throw new IllegalArgumentException(new NullPointerException()); - } - - if (iterator == null) { - return nullIterator; - } - - if (!iterator.hasNext()) { - return empty; - } - - Object obj = iterator.next(); - StringBuilder sb = new StringBuilder(obj == null ? nullPlaceholder : obj.toString()); - - while (iterator.hasNext()) { - obj = iterator.next(); - sb.append(separator); - sb.append(obj == null ? nullPlaceholder : obj.toString()); - } - - return sb.toString(); - } - - public static String iteratorToString(Iterator iterator, String separator) { - return iteratorToString(iterator, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterator]"); - } - - public static String iteratorToString(Iterator iterator) { - return iteratorToString(iterator, DEFAULT_SEPARATOR); - } - - public static String iterableToString( - Iterable iterable, - String separator, - String empty, - String nullPlaceholder, - String nullIterable - ) { - - if (separator == null) { - throw new IllegalArgumentException(new NullPointerException()); - } - - if (iterable == null) { - return nullIterable; - } - - return iteratorToString(iterable.iterator(), separator, empty, nullPlaceholder, nullIterable); - } - - public static String iterableToString(Iterable iterable, String separator) { - return iterableToString(iterable, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterable]"); - } - - public static String iterableToString(Iterable iterable) { - return iterableToString(iterable, DEFAULT_SEPARATOR); - } - - public static String supplierToString( - IntFunction supplier, - int length, - String separator, - String empty, - String nullPlaceholder, - String nullSupplier - ) { - - if (separator == null) throw new IllegalArgumentException(new NullPointerException()); - if (supplier == null) return nullSupplier; - if (length == 0) return empty; - - if (length > 0) { - return supplierToStringExactly( - supplier, - length, - separator, - nullPlaceholder - ); - } else { - return supplierToStringUntilNull( - supplier, - separator, - empty - ); - } - - } - - private static String supplierToStringExactly( - IntFunction supplier, - int length, - String separator, - String nullPlaceholder - ) { - T element = supplier.apply(0); - - StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString()); - - for (int i = 1; i < length; ++i) { - sb.append(separator); - element = supplier.apply(i); - sb.append(element == null ? nullPlaceholder : element.toString()); - } - - return sb.toString(); - } - - private static String supplierToStringUntilNull( - IntFunction supplier, - String separator, - String empty - ) { - T element = supplier.apply(0); - - if (element == null) { - return empty; - } - - StringBuilder sb = new StringBuilder(element.toString()); - - int i = 0; - while ((element = supplier.apply(i++)) != null) { - sb.append(separator); - sb.append(element); - } - - return sb.toString(); - } - - public static String supplierToString(IntFunction supplier, int length, String separator) { - return supplierToString(supplier, length, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]"); - } - - public static String supplierToString(IntFunction supplier, String separator) { - return supplierToString(supplier, -1, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]"); - } - - public static String supplierToString(IntFunction supplier, int length) { - return supplierToString(supplier, length, DEFAULT_SEPARATOR); - } - - public static String supplierToString(IntFunction supplier) { - return supplierToString(supplier, -1, DEFAULT_SEPARATOR); - } - - public static byte[] toJavaByteArray(String str) { - char[] chars = str.toCharArray(); - byte[] bytes = new byte[chars.length]; - - for (int i = 0; i < bytes.length; ++i) { - bytes[i] = (byte) chars[i]; - } - - return bytes; - } - - public static int count(String src, char target) { - int i = 0; - for (char c : src.toCharArray()) { - if (c == target) { - ++i; - } - } - - return i; - } - - public static String[] split(String src, char separator) { - return split(src, separator, count(src, separator) + 1); - } - - public static String[] split(String src, char separator, int arrayLength) { - if (arrayLength < 0) throw illegalArrayLength(arrayLength); - else if (arrayLength == 0) return new String[0]; - else if (arrayLength == 1) return new String[] { src }; - - String[] result = new String[arrayLength]; - - int resultIndex = 0; - StringBuilder sb = new StringBuilder(); - for (char c : src.toCharArray()) { - if (c == separator && (resultIndex + 1) < arrayLength) { - result[resultIndex] = resetStringBuilder(sb); - ++resultIndex; - } else { - sb.append(c); - } - } - - result[resultIndex] = sb.toString(); - - return result; - } - - public static int count(String src, char... target) { - int i = 0; - for (char c : src.toCharArray()) { - for (char t : target) { - if (c == t) { - ++i; - break; - } - } - } - - return i; - } - - public static String[] split(String src, char... separator) { - return split(src, count(src, separator) + 1, separator); - } - - public static String[] split(String src, int arrayLength, char... separator) { - if (arrayLength < 0) throw illegalArrayLength(arrayLength); - else if (arrayLength == 0) return new String[0]; - else if (arrayLength == 1) return new String[] { src }; - - String[] result = new String[arrayLength]; - - int resultIndex = 0; - StringBuilder sb = new StringBuilder(); - - charLoop: - for (char c : src.toCharArray()) { - if ((resultIndex + 1) < arrayLength) { - for (char h : separator) { - if (c == h) { - result[resultIndex] = resetStringBuilder(sb); - ++resultIndex; - continue charLoop; - } - } - } - - sb.append(c); - } - - result[resultIndex] = sb.toString(); - - return result; - } - - public static int count(String src, CharPredicate test) { - int i = 0; - for (char c : src.toCharArray()) { - if (test.test(c)) i++; - } - - return i; - } - - public static String[] split(String src, CharPredicate test) { - return split(src, count(src, test) + 1, test); - } - - public static String[] split(String src, int arrayLength, CharPredicate test) { - if (arrayLength < 0) throw illegalArrayLength(arrayLength); - else if (arrayLength == 0) return new String[0]; - else if (arrayLength == 1) return new String[] { src }; - - String[] result = new String[arrayLength]; - - int resultIndex = 0; - StringBuilder sb = new StringBuilder(); - - charLoop: - for (char c : src.toCharArray()) { - if ( - (resultIndex + 1) < arrayLength - && - test.test(c) - ) { - result[resultIndex] = resetStringBuilder(sb); - ++resultIndex; - continue charLoop; - } - - sb.append(c); - } - - result[resultIndex] = sb.toString(); - - return result; - } - - /** - * Splits {@code src} at index {@code at} discarding the character at that index. - *

- * Indices {@code 0} and {@code src.length() - 1} produce {@code str} excluding - * the specified character and {@code ""}. - *

- * @param src the String to split - * @param at index to split at - * @throws IllegalArgumentException if the index is out of bounds for {@code src} - * @return an array containing the substrings, in order of encounter in {@code src}. - * Its length is always 2. - */ - public static String[] splitAt(String src, int at) { - Objects.requireNonNull(src, "src"); - - if (at < 0) { - throw new StringIndexOutOfBoundsException(at); - } else if (at >= src.length()) { - throw new StringIndexOutOfBoundsException(at); - } - - if (at == 0) { - return new String[] {"", src.substring(1)}; - } else if (at == src.length()) { - return new String[] {src.substring(0, src.length() - 1), ""}; - } - - return new String[] { - src.substring(0, at), - src.substring(at + 1) - }; - } - - /** - * Splits {@code src} at indices {@code at} discarding characters at those indices. - *

- * Indices {@code 0} and {@code src.length() - 1} produce extra zero-length outputs. - * Duplicate indices produce extra zero-length outputs. - *

- * Examples: - *

-	 * splitAt("a.b.c", new int[] {1, 3})    -> {"a", "b", "c"}
-	 * splitAt("a..b",  new int[] {1, 2})    -> {"a", "", "b"}
-	 * splitAt(".b.",   new int[] {0, 2})    -> {"", "b", ""}
-	 * splitAt("a.b",   new int[] {1, 1, 1}) -> {"a", "", "", "b"}
-	 * 
- * @param src the String to split - * @param at indices to split at, in any order - * @throws IllegalArgumentException if some index is out of bounds for {@code src} - * @return an array containing the substrings, in order of encounter in {@code src}. - * Its length is always {@code at.length + 1}. - */ - public static String[] splitAt(String src, int... at) { - Objects.requireNonNull(src, "src"); - Objects.requireNonNull(at, "at"); - - if (at.length == 0) return new String[] {src}; - if (at.length == 1) return splitAt(src, at[0]); - - int[] indices; // Always sorted - - if (ArrayUtil.isSorted(at, true)) { - indices = at; - } else { - indices = at.clone(); - Arrays.sort(indices); - } - - if (indices[0] < 0) { - throw new StringIndexOutOfBoundsException(indices[0]); - } else if (indices[indices.length - 1] >= src.length()) { - throw new StringIndexOutOfBoundsException(indices[indices.length - 1]); - } - - String[] result = new String[at.length + 1]; - - int start = 0; - int resultIndex = 0; - for (int index : indices) { - int end = index; - - String substring; - - if (end <= start) { - // Duplicate or successive index - substring = ""; - } else { - substring = src.substring(start, end); - } - - result[resultIndex] = substring; - resultIndex++; - start = end + 1; - } - - result[resultIndex] = src.substring(start); - - return result; - } - - private static IllegalArgumentException illegalArrayLength(int length) { - return new IllegalArgumentException("arrayLength must be non-negative (" + length + ")"); - } - - public static String remove(String src, char... remove) { - char[] result = new char[src.length() - count(src, remove)]; - - char current; - int resultIndex = 0; - - mainLoop: - for (int srcIndex = 0; srcIndex < src.length(); ++srcIndex) { - current = src.charAt(srcIndex); - - for (char c : remove) { - if (current == c) { - continue mainLoop; - } - } - - result[resultIndex++] = current; - } - - return new String(result); - } - - public static String resetStringBuilder(StringBuilder sb) { - String result = sb.toString(); - sb.setLength(0); - sb.ensureCapacity(10); - return result; - } - - public static String readToString(InputStream is, Charset encoding, int bufferSize) throws IOException { - char[] buffer = new char[bufferSize]; - StringBuilder result = new StringBuilder(); - - Reader reader = new InputStreamReader(is, encoding); - while (true) { - int readChars = reader.read(buffer, 0, buffer.length); - - if (readChars == -1) { - break; - } - - result.append(buffer, 0, readChars); - } - - return result.toString(); - } - - public static boolean equalsPart(char[] a, char[] b, int beginPos, int endPos) { - if (beginPos < 0) { - throw new IllegalArgumentException("beginPos must be non-negative (" + beginPos + ")"); - } - - if (endPos < beginPos) { - throw new IllegalArgumentException("endPos must be greater than or equal to beginPos (endPos=" - + endPos + ", beginPos=" + beginPos + ")"); - } - - if (endPos >= Math.min(a.length, b.length)) { - return false; // At least one of the arrays does not contain at least one of the required elements - } - - for (int i = beginPos; i < endPos; ++i) { - if (a[i] != b[i]) { - return false; - } - } - - return true; - } - - // Java 8 is for pussies - public static char[] join(char[]... srcs) { - int tmp = 0; - for (int i = 0; i < srcs.length; ++i) { - tmp += srcs[i].length; - } - - char[] result = new char[tmp]; - tmp = 0; - for (int i = 0; i < srcs.length; ++i) { - System.arraycopy(srcs[i], 0, result, tmp, srcs[i].length); - tmp += srcs[i].length; - } - - return result; - } - - /** - * Finds and returns the index of the specified appearance of the specified character - * in the given array. The search starts at index 0.

- * Examples:

- * - * - * - * - * - * - * - * - * - * - * - *
srctargetskipreturns
a.b.c'.'01
a.b.c'.'13
a.b.c'.'2-1
a.b.c'd'any-1
- * @param src - the array to search in. - * @param target - the character to search for. - * @param skip - the amount of target characters to be skipped. - * @return The index of the skip+1th target character or -1, if none found. - * @see StringUtil#indexFromEnd(char[], char, int) - */ - public static int indexFromBeginning(char[] src, char target, int skip) { - for (int i = 0; i < src.length; ++i) { - if (src[i] == target) { - if (skip == 0) { - return i; - } - - --skip; - } - } - return -1; - } - - /** - * Finds and returns the index of the specified appearance of the specified character - * in the given array. The search starts at index src.length - 1.

- * Examples:

- * - * - * - * - * - * - * - * - * - * - * - *
srctargetskipreturns
a.b.c'.'03
a.b.c'.'11
a.b.c'.'2-1
a.b.c'd'any-1
- * @param src - the array to search in. - * @param target - the character to search for. - * @param skip - the amount of target characters to be skipped. - * @return The index of the skip+1th targetcharacter - * from the end of the array or -1, if none found. - * @see StringUtil#indexFromBeginning(char[], char, int) - */ - public static int indexFromEnd(char[] src, char target, int skip) { - for (int i = src.length - 1; i >= 0; --i) { - if (src[i] == target) { - if (skip == 0) { - return i; - } - - --skip; - } - } - - return -1; - } - - public static String padToLeft(String src, int length, char c) { - if (length <= 0) { - throw new IllegalArgumentException("length must be positive (" + length + ")"); - } - - if (length <= src.length()) { - return src; - } - - char[] result = new char[length]; - - int i = 0; - for (; i < src.length(); ++i) { - result[i] = src.charAt(i); - } - - for (; i < length; ++i) { - result[i] = c; - } - - return new String(result); - } - - public static String padToLeft(String src, int length) { - return padToLeft(src, length, ' '); - } - - public static String padToRight(String src, int length, char c) { - if (length <= 0) { - throw new IllegalArgumentException("length must be positive (" + length + ")"); - } - - if (length <= src.length()) { - return src; - } - - char[] result = new char[length]; - - int i = 0; - int srcLength = src.length(); - - for (; i < length - srcLength; ++i) { - result[i] = c; - } - - for (; i < length; ++i) { - result[i] = src.charAt(i - (length - srcLength)); - } - - return new String(result); - } - - public static String padToRight(String src, int length) { - return padToRight(src, length, ' '); - } - - public static String center(String src, int length) { - return center(src, length, ' '); - } - - public static String center(String src, int length, char filler) { - if (length <= 0) { - throw new IllegalArgumentException("length must be positive (" + length + ")"); - } - - if (src == null || length <= src.length()) { - return src; - } - - char[] result = new char[length]; - - int leftPaddingLength = (length - src.length()) / 2; - - Arrays.fill(result, 0, leftPaddingLength, filler); - - for (int i = 0; i < src.length(); ++i) { - result[i + leftPaddingLength] = src.charAt(i); - } - - Arrays.fill(result, leftPaddingLength + src.length(), result.length, filler); - - return new String(result); - } - - public static int countWords(String src) { - int i = 0; - boolean isWord = false; - - for (char c : src.toCharArray()) { - if (Character.isWhitespace(c)) { - if (isWord) { - isWord = false; - i++; - } - } else { - isWord = true; - } - } - - if (isWord) { - i++; - } - - return i; - } - - public static String[] splitWords(String src) { - String[] result = new String[countWords(src)]; - - int i = 0; - StringBuilder sb = new StringBuilder(); - for (char c : src.toCharArray()) { - if (Character.isWhitespace(c)) { - if (sb.length() != 0) { - result[i++] = resetStringBuilder(sb); - } - } else { - sb.append(c); - } - } - - if (sb.length() != 0) { - result[i] = resetStringBuilder(sb); - } - - return result; - } - - public static char[] sequence(char c, int length) { - char[] result = new char[length]; - Arrays.fill(result, c); - return result; - } - - public static String stripPrefix(String string, String prefix) { - if (prefix != null && string.startsWith(prefix)) { - return string.substring(prefix.length()); - } - - return string; - } - - public static String stripSuffix(String string, String suffix) { - if (suffix != null && string.endsWith(suffix)) { - return string.substring(suffix.length()); - } - - return string; - } - - @SafeVarargs - public static Collection allCombinations(Iterable... parts) { - StringBuilder sb = new StringBuilder(); - Collection result = new ArrayList<>(); - buildCombinations(sb, result, parts, 0); - return result; - } - - private static void buildCombinations(StringBuilder sb, Collection result, Iterable[] parts, - int index) { - if (index >= parts.length) { - result.add(sb.toString()); - } else { - int startLength = sb.length(); - for (String part : parts[index]) { - sb.append(part); - buildCombinations(sb, result, parts, index + 1); - sb.setLength(startLength); - } - } - } - - @SafeVarargs - public static String[] allCombinations(String[]... parts) { - StringBuilder sb = new StringBuilder(); - - int length = 1; - for (String[] array : parts) length *= array.length; - String[] result = new String[length]; - - buildCombinations(sb, result, new int[] {0}, parts, 0); - return result; - } - - private static void buildCombinations(StringBuilder sb, String[] result, int[] resultIndex, String[][] parts, - int index) { - if (index >= parts.length) { - result[resultIndex[0]++] = sb.toString(); - } else { - int startLength = sb.length(); - for (String part : parts[index]) { - sb.append(part); - buildCombinations(sb, result, resultIndex, parts, index + 1); - sb.setLength(startLength); - } - } - } - - public static String toUnsignedHexString(byte b) { - int unsigned = b; - if (b < 0) { - unsigned += 0x100; - } - - char[] chars = new char[2]; - - chars[0] = Character.forDigit(unsigned >>> 4, 0x10); - chars[1] = Character.forDigit(unsigned & 0x0F, 0x10); - - return new String(chars); - } - - public static String toUnsignedHexString(byte[] bytes, String separator, int size) { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < bytes.length; ++i) { - sb.append(toUnsignedHexString(bytes[i])); - if (i < bytes.length - 1 && ((i + 1) % size == 0)) { - sb.append(separator); - } - } - - return sb.toString(); - } - - public static String toUnsignedHexString(byte[] bytes) { - return toUnsignedHexString(bytes, ", ", 1); - } - - public static char[] toFullHex(byte x) { - return toFullHex(x, Byte.BYTES); - } - - public static char[] toFullHex(short x) { - return toFullHex(x, Short.BYTES); - } - - public static char[] toFullHex(int x) { - return toFullHex(x, Integer.BYTES); - } - - public static char[] toFullHex(long x) { - return toFullHex(x, Long.BYTES); - } - - private static char[] toFullHex(long x, int bytes) { - final int digits = bytes * 2; - - char[] result = new char[digits + 2]; - result[0] = '0'; - result[1] = 'x'; - - for (int digit = 0; digit < digits; ++digit) { - result[(digits - digit - 1) + 2] = - hexDigit(x, digit); - } - - return result; - } - - private static char hexDigit(long value, int digit) { - return hexDigit( - (int) (value >>> (4 * digit)) - & 0xF - ); - } - - public static char hexDigit(int value) { - if (value < 0xA) return (char) ('0' + value); - else return (char) ('A' - 0xA + value); - } - - public static String replaceAll(String source, String substring, String replacement) { - Objects.requireNonNull(source, "source"); - Objects.requireNonNull(substring, "substring"); - - if (substring.isEmpty()) { - throw new IllegalArgumentException("substring is empty"); - } - - if (!source.contains(substring)) { // also passes if source is empty - return source; - } - - if (substring.equals(replacement)) { // null-safe - return source; - } - - StringBuilder sb = new StringBuilder(2 * source.length()); - - for (int i = 0; i < source.length() - substring.length() + 1; ++i) { - if (source.startsWith(substring, i)) { - if (replacement != null) { - sb.append(replacement); - } - } else { - sb.append(source.charAt(i)); - } - } - - return sb.toString(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.Objects; +import java.util.function.IntFunction; + +import ru.windcorp.jputil.ArrayUtil; + +public class StringUtil { + + private StringUtil() { + } + + private static final String NULL_PLACEHOLDER = "[null]"; + private static final String EMPTY_PLACEHOLDER = "[empty]"; + private static final String DEFAULT_SEPARATOR = "; "; + + public static String arrayToString( + T[] array, + String separator, + String empty, + String nullPlaceholder, + String nullArray + ) { + + if (separator == null) { + throw new IllegalArgumentException(new NullPointerException()); + } + + if (array == null) { + return nullArray; + } + + if (array.length == 0) { + return empty; + } + + StringBuilder sb = new StringBuilder(array[0] == null ? nullPlaceholder : array[0].toString()); + + for (int i = 1; i < array.length; ++i) { + sb.append(separator); + sb.append(array[i] == null ? nullPlaceholder : array[i].toString()); + } + + return sb.toString(); + } + + public static String arrayToString(T[] array, String separator) { + return arrayToString(array, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null array]"); + } + + public static String arrayToString(T[] array) { + return arrayToString(array, DEFAULT_SEPARATOR); + } + + public static String iteratorToString( + Iterator iterator, + String separator, + String empty, + String nullPlaceholder, + String nullIterator + ) { + + if (separator == null) { + throw new IllegalArgumentException(new NullPointerException()); + } + + if (iterator == null) { + return nullIterator; + } + + if (!iterator.hasNext()) { + return empty; + } + + Object obj = iterator.next(); + StringBuilder sb = new StringBuilder(obj == null ? nullPlaceholder : obj.toString()); + + while (iterator.hasNext()) { + obj = iterator.next(); + sb.append(separator); + sb.append(obj == null ? nullPlaceholder : obj.toString()); + } + + return sb.toString(); + } + + public static String iteratorToString(Iterator iterator, String separator) { + return iteratorToString(iterator, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterator]"); + } + + public static String iteratorToString(Iterator iterator) { + return iteratorToString(iterator, DEFAULT_SEPARATOR); + } + + public static String iterableToString( + Iterable iterable, + String separator, + String empty, + String nullPlaceholder, + String nullIterable + ) { + + if (separator == null) { + throw new IllegalArgumentException(new NullPointerException()); + } + + if (iterable == null) { + return nullIterable; + } + + return iteratorToString(iterable.iterator(), separator, empty, nullPlaceholder, nullIterable); + } + + public static String iterableToString(Iterable iterable, String separator) { + return iterableToString(iterable, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null iterable]"); + } + + public static String iterableToString(Iterable iterable) { + return iterableToString(iterable, DEFAULT_SEPARATOR); + } + + public static String supplierToString( + IntFunction supplier, + int length, + String separator, + String empty, + String nullPlaceholder, + String nullSupplier + ) { + + if (separator == null) + throw new IllegalArgumentException(new NullPointerException()); + if (supplier == null) + return nullSupplier; + if (length == 0) + return empty; + + if (length > 0) { + return supplierToStringExactly( + supplier, + length, + separator, + nullPlaceholder + ); + } else { + return supplierToStringUntilNull( + supplier, + separator, + empty + ); + } + + } + + private static String supplierToStringExactly( + IntFunction supplier, + int length, + String separator, + String nullPlaceholder + ) { + T element = supplier.apply(0); + + StringBuilder sb = new StringBuilder(element == null ? nullPlaceholder : element.toString()); + + for (int i = 1; i < length; ++i) { + sb.append(separator); + element = supplier.apply(i); + sb.append(element == null ? nullPlaceholder : element.toString()); + } + + return sb.toString(); + } + + private static String supplierToStringUntilNull( + IntFunction supplier, + String separator, + String empty + ) { + T element = supplier.apply(0); + + if (element == null) { + return empty; + } + + StringBuilder sb = new StringBuilder(element.toString()); + + int i = 0; + while ((element = supplier.apply(i++)) != null) { + sb.append(separator); + sb.append(element); + } + + return sb.toString(); + } + + public static String supplierToString(IntFunction supplier, int length, String separator) { + return supplierToString(supplier, length, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]"); + } + + public static String supplierToString(IntFunction supplier, String separator) { + return supplierToString(supplier, -1, separator, EMPTY_PLACEHOLDER, NULL_PLACEHOLDER, "[null supplier]"); + } + + public static String supplierToString(IntFunction supplier, int length) { + return supplierToString(supplier, length, DEFAULT_SEPARATOR); + } + + public static String supplierToString(IntFunction supplier) { + return supplierToString(supplier, -1, DEFAULT_SEPARATOR); + } + + public static byte[] toJavaByteArray(String str) { + char[] chars = str.toCharArray(); + byte[] bytes = new byte[chars.length]; + + for (int i = 0; i < bytes.length; ++i) { + bytes[i] = (byte) chars[i]; + } + + return bytes; + } + + public static int count(String src, char target) { + int i = 0; + for (char c : src.toCharArray()) { + if (c == target) { + ++i; + } + } + + return i; + } + + public static String[] split(String src, char separator) { + return split(src, separator, count(src, separator) + 1); + } + + public static String[] split(String src, char separator, int arrayLength) { + if (arrayLength < 0) + throw illegalArrayLength(arrayLength); + else if (arrayLength == 0) + return new String[0]; + else if (arrayLength == 1) + return new String[] { src }; + + String[] result = new String[arrayLength]; + + int resultIndex = 0; + StringBuilder sb = new StringBuilder(); + for (char c : src.toCharArray()) { + if (c == separator && (resultIndex + 1) < arrayLength) { + result[resultIndex] = resetStringBuilder(sb); + ++resultIndex; + } else { + sb.append(c); + } + } + + result[resultIndex] = sb.toString(); + + return result; + } + + public static int count(String src, char... target) { + int i = 0; + for (char c : src.toCharArray()) { + for (char t : target) { + if (c == t) { + ++i; + break; + } + } + } + + return i; + } + + public static String[] split(String src, char... separator) { + return split(src, count(src, separator) + 1, separator); + } + + public static String[] split(String src, int arrayLength, char... separator) { + if (arrayLength < 0) + throw illegalArrayLength(arrayLength); + else if (arrayLength == 0) + return new String[0]; + else if (arrayLength == 1) + return new String[] { src }; + + String[] result = new String[arrayLength]; + + int resultIndex = 0; + StringBuilder sb = new StringBuilder(); + + charLoop: for (char c : src.toCharArray()) { + if ((resultIndex + 1) < arrayLength) { + for (char h : separator) { + if (c == h) { + result[resultIndex] = resetStringBuilder(sb); + ++resultIndex; + continue charLoop; + } + } + } + + sb.append(c); + } + + result[resultIndex] = sb.toString(); + + return result; + } + + public static int count(String src, CharPredicate test) { + int i = 0; + for (char c : src.toCharArray()) { + if (test.test(c)) + i++; + } + + return i; + } + + public static String[] split(String src, CharPredicate test) { + return split(src, count(src, test) + 1, test); + } + + public static String[] split(String src, int arrayLength, CharPredicate test) { + if (arrayLength < 0) + throw illegalArrayLength(arrayLength); + else if (arrayLength == 0) + return new String[0]; + else if (arrayLength == 1) + return new String[] { src }; + + String[] result = new String[arrayLength]; + + int resultIndex = 0; + StringBuilder sb = new StringBuilder(); + + charLoop: for (char c : src.toCharArray()) { + if ( + (resultIndex + 1) < arrayLength + && + test.test(c) + ) { + result[resultIndex] = resetStringBuilder(sb); + ++resultIndex; + continue charLoop; + } + + sb.append(c); + } + + result[resultIndex] = sb.toString(); + + return result; + } + + /** + * Splits {@code src} at index {@code at} discarding the character at that + * index. + *

+ * Indices {@code 0} and {@code src.length() - 1} produce {@code str} + * excluding + * the specified character and {@code ""}. + *

+ * + * @param src the String to split + * @param at index to split at + * @throws IllegalArgumentException if the index is out of bounds for + * {@code src} + * @return an array containing the substrings, in order of encounter in + * {@code src}. + * Its length is always 2. + */ + public static String[] splitAt(String src, int at) { + Objects.requireNonNull(src, "src"); + + if (at < 0) { + throw new StringIndexOutOfBoundsException(at); + } else if (at >= src.length()) { + throw new StringIndexOutOfBoundsException(at); + } + + if (at == 0) { + return new String[] { "", src.substring(1) }; + } else if (at == src.length()) { + return new String[] { src.substring(0, src.length() - 1), "" }; + } + + return new String[] { + src.substring(0, at), + src.substring(at + 1) + }; + } + + /** + * Splits {@code src} at indices {@code at} discarding characters at those + * indices. + *

+ * Indices {@code 0} and {@code src.length() - 1} produce extra zero-length + * outputs. + * Duplicate indices produce extra zero-length outputs. + *

+ * Examples: + * + *

+	 * splitAt("a.b.c", 1, 3)    -> {"a", "b", "c"}
+	 * splitAt("a..b",  1, 2)    -> {"a", "", "b"}
+	 * splitAt(".b.",   0, 2)    -> {"", "b", ""}
+	 * splitAt("a.b",   1, 1, 1) -> {"a", "", "", "b"}
+	 * 
+ * + * @param src the String to split + * @param at indices to split at, in any order + * @throws IllegalArgumentException if some index is out of bounds for + * {@code src} + * @return an array containing the substrings, in order of encounter in + * {@code src}. + * Its length is always {@code at.length + 1}. + */ + public static String[] splitAt(String src, int... at) { + Objects.requireNonNull(src, "src"); + Objects.requireNonNull(at, "at"); + + if (at.length == 0) + return new String[] { src }; + if (at.length == 1) + return splitAt(src, at[0]); + + int[] indices; // Always sorted + + if (ArrayUtil.isSorted(at, true)) { + indices = at; + } else { + indices = at.clone(); + Arrays.sort(indices); + } + + if (indices[0] < 0) { + throw new StringIndexOutOfBoundsException(indices[0]); + } else if (indices[indices.length - 1] >= src.length()) { + throw new StringIndexOutOfBoundsException(indices[indices.length - 1]); + } + + String[] result = new String[at.length + 1]; + + int start = 0; + int resultIndex = 0; + for (int index : indices) { + int end = index; + + String substring; + + if (end <= start) { + // Duplicate or successive index + substring = ""; + } else { + substring = src.substring(start, end); + } + + result[resultIndex] = substring; + resultIndex++; + start = end + 1; + } + + result[resultIndex] = src.substring(start); + + return result; + } + + private static IllegalArgumentException illegalArrayLength(int length) { + return new IllegalArgumentException("arrayLength must be non-negative (" + length + ")"); + } + + public static String remove(String src, char... remove) { + char[] result = new char[src.length() - count(src, remove)]; + + char current; + int resultIndex = 0; + + mainLoop: for (int srcIndex = 0; srcIndex < src.length(); ++srcIndex) { + current = src.charAt(srcIndex); + + for (char c : remove) { + if (current == c) { + continue mainLoop; + } + } + + result[resultIndex++] = current; + } + + return new String(result); + } + + public static String resetStringBuilder(StringBuilder sb) { + String result = sb.toString(); + sb.setLength(0); + sb.ensureCapacity(10); + return result; + } + + public static String readToString(InputStream is, Charset encoding, int bufferSize) throws IOException { + char[] buffer = new char[bufferSize]; + StringBuilder result = new StringBuilder(); + + Reader reader = new InputStreamReader(is, encoding); + while (true) { + int readChars = reader.read(buffer, 0, buffer.length); + + if (readChars == -1) { + break; + } + + result.append(buffer, 0, readChars); + } + + return result.toString(); + } + + public static boolean equalsPart(char[] a, char[] b, int beginPos, int endPos) { + if (beginPos < 0) { + throw new IllegalArgumentException("beginPos must be non-negative (" + beginPos + ")"); + } + + if (endPos < beginPos) { + throw new IllegalArgumentException( + "endPos must be greater than or equal to beginPos (endPos=" + + endPos + ", beginPos=" + beginPos + ")" + ); + } + + if (endPos >= Math.min(a.length, b.length)) { + return false; // At least one of the arrays does not contain at + // least one of the required elements + } + + for (int i = beginPos; i < endPos; ++i) { + if (a[i] != b[i]) { + return false; + } + } + + return true; + } + + // Java 8 is for pussies + public static char[] join(char[]... srcs) { + int tmp = 0; + for (int i = 0; i < srcs.length; ++i) { + tmp += srcs[i].length; + } + + char[] result = new char[tmp]; + tmp = 0; + for (int i = 0; i < srcs.length; ++i) { + System.arraycopy(srcs[i], 0, result, tmp, srcs[i].length); + tmp += srcs[i].length; + } + + return result; + } + + /** + * Finds and returns the index of the specified appearance of the specified + * character + * in the given array. The search starts at index 0. + *

+ * Examples: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
srctargetskipreturns
a.b.c'.'01
a.b.c'.'13
a.b.c'.'2-1
a.b.c'd'any-1
+ * + * @param src - the array to search in. + * @param target - the character to search for. + * @param skip - the amount of target characters to be + * skipped. + * @return The index of the skip+1th target + * character or -1, if none found. + * @see StringUtil#indexFromEnd(char[], char, int) + */ + public static int indexFromBeginning(char[] src, char target, int skip) { + for (int i = 0; i < src.length; ++i) { + if (src[i] == target) { + if (skip == 0) { + return i; + } + + --skip; + } + } + return -1; + } + + /** + * Finds and returns the index of the specified appearance of the specified + * character + * in the given array. The search starts at index + * src.length - 1. + *

+ * Examples: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
srctargetskipreturns
a.b.c'.'03
a.b.c'.'11
a.b.c'.'2-1
a.b.c'd'any-1
+ * + * @param src - the array to search in. + * @param target - the character to search for. + * @param skip - the amount of target characters to be + * skipped. + * @return The index of the skip+1th + * targetcharacter + * from the end of the array or -1, if none found. + * @see StringUtil#indexFromBeginning(char[], char, int) + */ + public static int indexFromEnd(char[] src, char target, int skip) { + for (int i = src.length - 1; i >= 0; --i) { + if (src[i] == target) { + if (skip == 0) { + return i; + } + + --skip; + } + } + + return -1; + } + + public static String padToLeft(String src, int length, char c) { + if (length <= 0) { + throw new IllegalArgumentException("length must be positive (" + length + ")"); + } + + if (length <= src.length()) { + return src; + } + + char[] result = new char[length]; + + int i = 0; + for (; i < src.length(); ++i) { + result[i] = src.charAt(i); + } + + for (; i < length; ++i) { + result[i] = c; + } + + return new String(result); + } + + public static String padToLeft(String src, int length) { + return padToLeft(src, length, ' '); + } + + public static String padToRight(String src, int length, char c) { + if (length <= 0) { + throw new IllegalArgumentException("length must be positive (" + length + ")"); + } + + if (length <= src.length()) { + return src; + } + + char[] result = new char[length]; + + int i = 0; + int srcLength = src.length(); + + for (; i < length - srcLength; ++i) { + result[i] = c; + } + + for (; i < length; ++i) { + result[i] = src.charAt(i - (length - srcLength)); + } + + return new String(result); + } + + public static String padToRight(String src, int length) { + return padToRight(src, length, ' '); + } + + public static String center(String src, int length) { + return center(src, length, ' '); + } + + public static String center(String src, int length, char filler) { + if (length <= 0) { + throw new IllegalArgumentException("length must be positive (" + length + ")"); + } + + if (src == null || length <= src.length()) { + return src; + } + + char[] result = new char[length]; + + int leftPaddingLength = (length - src.length()) / 2; + + Arrays.fill(result, 0, leftPaddingLength, filler); + + for (int i = 0; i < src.length(); ++i) { + result[i + leftPaddingLength] = src.charAt(i); + } + + Arrays.fill(result, leftPaddingLength + src.length(), result.length, filler); + + return new String(result); + } + + public static int countWords(String src) { + int i = 0; + boolean isWord = false; + + for (char c : src.toCharArray()) { + if (Character.isWhitespace(c)) { + if (isWord) { + isWord = false; + i++; + } + } else { + isWord = true; + } + } + + if (isWord) { + i++; + } + + return i; + } + + public static String[] splitWords(String src) { + String[] result = new String[countWords(src)]; + + int i = 0; + StringBuilder sb = new StringBuilder(); + for (char c : src.toCharArray()) { + if (Character.isWhitespace(c)) { + if (sb.length() != 0) { + result[i++] = resetStringBuilder(sb); + } + } else { + sb.append(c); + } + } + + if (sb.length() != 0) { + result[i] = resetStringBuilder(sb); + } + + return result; + } + + public static char[] sequence(char c, int length) { + char[] result = new char[length]; + Arrays.fill(result, c); + return result; + } + + public static String stripPrefix(String string, String prefix) { + if (prefix != null && string.startsWith(prefix)) { + return string.substring(prefix.length()); + } + + return string; + } + + public static String stripSuffix(String string, String suffix) { + if (suffix != null && string.endsWith(suffix)) { + return string.substring(suffix.length()); + } + + return string; + } + + @SafeVarargs + public static Collection allCombinations(Iterable... parts) { + StringBuilder sb = new StringBuilder(); + Collection result = new ArrayList<>(); + buildCombinations(sb, result, parts, 0); + return result; + } + + private static void buildCombinations( + StringBuilder sb, + Collection result, + Iterable[] parts, + int index + ) { + if (index >= parts.length) { + result.add(sb.toString()); + } else { + int startLength = sb.length(); + for (String part : parts[index]) { + sb.append(part); + buildCombinations(sb, result, parts, index + 1); + sb.setLength(startLength); + } + } + } + + @SafeVarargs + public static String[] allCombinations(String[]... parts) { + StringBuilder sb = new StringBuilder(); + + int length = 1; + for (String[] array : parts) + length *= array.length; + String[] result = new String[length]; + + buildCombinations(sb, result, new int[] { 0 }, parts, 0); + return result; + } + + private static void buildCombinations( + StringBuilder sb, + String[] result, + int[] resultIndex, + String[][] parts, + int index + ) { + if (index >= parts.length) { + result[resultIndex[0]++] = sb.toString(); + } else { + int startLength = sb.length(); + for (String part : parts[index]) { + sb.append(part); + buildCombinations(sb, result, resultIndex, parts, index + 1); + sb.setLength(startLength); + } + } + } + + public static String toUnsignedHexString(byte b) { + int unsigned = b; + if (b < 0) { + unsigned += 0x100; + } + + char[] chars = new char[2]; + + chars[0] = Character.forDigit(unsigned >>> 4, 0x10); + chars[1] = Character.forDigit(unsigned & 0x0F, 0x10); + + return new String(chars); + } + + public static String toUnsignedHexString(byte[] bytes, String separator, int size) { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < bytes.length; ++i) { + sb.append(toUnsignedHexString(bytes[i])); + if (i < bytes.length - 1 && ((i + 1) % size == 0)) { + sb.append(separator); + } + } + + return sb.toString(); + } + + public static String toUnsignedHexString(byte[] bytes) { + return toUnsignedHexString(bytes, ", ", 1); + } + + public static char[] toFullHex(byte x) { + return toFullHex(x, Byte.BYTES); + } + + public static char[] toFullHex(short x) { + return toFullHex(x, Short.BYTES); + } + + public static char[] toFullHex(int x) { + return toFullHex(x, Integer.BYTES); + } + + public static char[] toFullHex(long x) { + return toFullHex(x, Long.BYTES); + } + + private static char[] toFullHex(long x, int bytes) { + final int digits = bytes * 2; + + char[] result = new char[digits + 2]; + result[0] = '0'; + result[1] = 'x'; + + for (int digit = 0; digit < digits; ++digit) { + result[(digits - digit - 1) + 2] = hexDigit(x, digit); + } + + return result; + } + + private static char hexDigit(long value, int digit) { + return hexDigit( + (int) (value >>> (4 * digit)) + & 0xF + ); + } + + public static char hexDigit(int value) { + if (value < 0xA) + return (char) ('0' + value); + else + return (char) ('A' - 0xA + value); + } + + public static String replaceAll(String source, String substring, String replacement) { + Objects.requireNonNull(source, "source"); + Objects.requireNonNull(substring, "substring"); + + if (substring.isEmpty()) { + throw new IllegalArgumentException("substring is empty"); + } + + if (!source.contains(substring)) { // also passes if source is empty + return source; + } + + if (substring.equals(replacement)) { // null-safe + return source; + } + + StringBuilder sb = new StringBuilder(2 * source.length()); + + for (int i = 0; i < source.length() - substring.length() + 1; ++i) { + if (source.startsWith(substring, i)) { + if (replacement != null) { + sb.append(replacement); + } + } else { + sb.append(source.charAt(i)); + } + } + + return sb.toString(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java b/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java index 03c7a5f..33717ee 100644 --- a/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java +++ b/src/main/java/ru/windcorp/jputil/chars/UncheckedEscapeException.java @@ -1,37 +1,38 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -public class UncheckedEscapeException extends RuntimeException { - - private static final long serialVersionUID = 5392628641744570926L; - - public UncheckedEscapeException(String message, EscapeException cause) { - super(message, cause); - } - - public UncheckedEscapeException(EscapeException cause) { - super(cause); - } - - @Override - public synchronized EscapeException getCause() { - return (EscapeException) super.getCause(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +public class UncheckedEscapeException extends RuntimeException { + + private static final long serialVersionUID = 5392628641744570926L; + + public UncheckedEscapeException(String message, EscapeException cause) { + super(message, cause); + } + + public UncheckedEscapeException(EscapeException cause) { + super(cause); + } + + @Override + public synchronized EscapeException getCause() { + return (EscapeException) super.getCause(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/WordReader.java b/src/main/java/ru/windcorp/jputil/chars/WordReader.java index 8636734..22d6969 100644 --- a/src/main/java/ru/windcorp/jputil/chars/WordReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/WordReader.java @@ -1,139 +1,143 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars; - -import java.io.IOException; -import java.io.Reader; -import java.nio.CharBuffer; -import java.util.Arrays; -import java.util.Iterator; -import java.util.NoSuchElementException; - -public class WordReader implements Iterator { - - private final Reader reader; - - private char[] wordBuffer = new char[1024]; - private final CharBuffer inputBuffer; - - private String next = null; - private boolean isExhausted = false; - - private IOException lastException = null; - - public WordReader(Reader src, int bufferSize) { - this.reader = src; - this.inputBuffer = CharBuffer.allocate(bufferSize); - } - - public WordReader(Reader src) { - this(src, 2048); - } - - public WordReader(char[] array, int offset, int length) { - this.reader = null; - this.inputBuffer = CharBuffer.wrap(Arrays.copyOfRange(array, offset, length + offset)); - } - - public WordReader(char[] array) { - this.reader = null; - this.inputBuffer = CharBuffer.wrap(array); - } - - public WordReader(String str) { - this(str.toCharArray()); - } - - @Override - public String next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - - String result = next; - next = null; - return result; - } - - @Override - public boolean hasNext() { - if (next != null) { - return true; - } - - if (isExhausted) { - return false; - } - - int length = 0; - char c; - while (true) { - c = nextChar(); - - if (isExhausted) break; - - if (Character.isWhitespace(c)) { - if (length == 0) continue; - else break; - } - - if (wordBuffer.length == length) { - char[] newBuf = new char[wordBuffer.length * 2]; - System.arraycopy(wordBuffer, 0, newBuf, 0, wordBuffer.length); - wordBuffer = newBuf; - } - - wordBuffer[length++] = c; - } - - if (length == 0) { - return false; - } - - next = new String(wordBuffer, 0, length); - return true; - } - - private char nextChar() { - if (!inputBuffer.hasRemaining()) { - if (reader == null) { - isExhausted = true; - return 0; - } - - inputBuffer.rewind(); - try { - if (reader.read(inputBuffer) == -1) { - isExhausted = true; - } - } catch (IOException e) { - lastException = e; - isExhausted = true; - return 0; - } - - } - - return inputBuffer.get(); - } - - public IOException getLastException() { - return lastException; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars; + +import java.io.IOException; +import java.io.Reader; +import java.nio.CharBuffer; +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class WordReader implements Iterator { + + private final Reader reader; + + private char[] wordBuffer = new char[1024]; + private final CharBuffer inputBuffer; + + private String next = null; + private boolean isExhausted = false; + + private IOException lastException = null; + + public WordReader(Reader src, int bufferSize) { + this.reader = src; + this.inputBuffer = CharBuffer.allocate(bufferSize); + } + + public WordReader(Reader src) { + this(src, 2048); + } + + public WordReader(char[] array, int offset, int length) { + this.reader = null; + this.inputBuffer = CharBuffer.wrap(Arrays.copyOfRange(array, offset, length + offset)); + } + + public WordReader(char[] array) { + this.reader = null; + this.inputBuffer = CharBuffer.wrap(array); + } + + public WordReader(String str) { + this(str.toCharArray()); + } + + @Override + public String next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + String result = next; + next = null; + return result; + } + + @Override + public boolean hasNext() { + if (next != null) { + return true; + } + + if (isExhausted) { + return false; + } + + int length = 0; + char c; + while (true) { + c = nextChar(); + + if (isExhausted) + break; + + if (Character.isWhitespace(c)) { + if (length == 0) + continue; + else + break; + } + + if (wordBuffer.length == length) { + char[] newBuf = new char[wordBuffer.length * 2]; + System.arraycopy(wordBuffer, 0, newBuf, 0, wordBuffer.length); + wordBuffer = newBuf; + } + + wordBuffer[length++] = c; + } + + if (length == 0) { + return false; + } + + next = new String(wordBuffer, 0, length); + return true; + } + + private char nextChar() { + if (!inputBuffer.hasRemaining()) { + if (reader == null) { + isExhausted = true; + return 0; + } + + inputBuffer.rewind(); + try { + if (reader.read(inputBuffer) == -1) { + isExhausted = true; + } + } catch (IOException e) { + lastException = e; + isExhausted = true; + return 0; + } + + } + + return inputBuffer.get(); + } + + public IOException getLastException() { + return lastException; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java index 1d48158..d31e092 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/AbstractCharReader.java @@ -1,104 +1,108 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -/** - * @author Javapony - * - */ -public abstract class AbstractCharReader implements CharReader { - - protected static final int DEFAULT_MARK_STACK_SIZE = 8; - - /** - * Current position of this CharReader. The reader maps its input to positions starting from 0. - * Positions that are negative or lower than 0 are invalid. {@link #current()} - * will throw an exception if position is invalid. - */ - protected int position = 0; - - private int[] marks = new int[DEFAULT_MARK_STACK_SIZE]; - private int nextMark = 0; - - protected static int closestGreaterPowerOf2(int x) { - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x + 1; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#getPosition() - */ - @Override - public int getPosition() { - return position; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#setPosition(int) - */ - @Override - public int setPosition(int position) { - this.position = position; - return position; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#mark() - */ - @Override - public int mark() { - ensureMarksCapacity(); - marks[nextMark++] = position; - return position; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#forget() - */ - @Override - public int forget() { - return marks[--nextMark]; - } - - private void ensureMarksCapacity() { - if (nextMark < marks.length) return; - int[] newMarks = new int[closestGreaterPowerOf2(nextMark)]; - System.arraycopy(marks, 0, newMarks, 0, nextMark); - marks = newMarks; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("\""); - - mark(); - position = 0; - sb.append(getChars()); - reset(); - - sb.append("\"\n "); - for (int i = 0; i < position; ++i) sb.append(' '); - sb.append("^ (pos " + position + ")"); - return sb.toString(); - } - -} \ No newline at end of file +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +/** + * @author Javapony + */ +public abstract class AbstractCharReader implements CharReader { + + protected static final int DEFAULT_MARK_STACK_SIZE = 8; + + /** + * Current position of this CharReader. The reader maps its input to + * positions starting from 0. + * Positions that are negative or lower than 0 are invalid. + * {@link #current()} + * will throw an exception if position is invalid. + */ + protected int position = 0; + + private int[] marks = new int[DEFAULT_MARK_STACK_SIZE]; + private int nextMark = 0; + + protected static int closestGreaterPowerOf2(int x) { + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#getPosition() + */ + @Override + public int getPosition() { + return position; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#setPosition(int) + */ + @Override + public int setPosition(int position) { + this.position = position; + return position; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#mark() + */ + @Override + public int mark() { + ensureMarksCapacity(); + marks[nextMark++] = position; + return position; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#forget() + */ + @Override + public int forget() { + return marks[--nextMark]; + } + + private void ensureMarksCapacity() { + if (nextMark < marks.length) + return; + int[] newMarks = new int[closestGreaterPowerOf2(nextMark)]; + System.arraycopy(marks, 0, newMarks, 0, nextMark); + marks = newMarks; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("\""); + + mark(); + position = 0; + sb.append(getChars()); + reset(); + + sb.append("\"\n "); + for (int i = 0; i < position; ++i) + sb.append(' '); + sb.append("^ (pos " + position + ")"); + return sb.toString(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java index 13a32d2..f12f590 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/ArrayCharReader.java @@ -1,59 +1,60 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -import java.util.Objects; - -import ru.windcorp.jputil.ArrayUtil; - -/** - * @author Javapony - * - */ -public class ArrayCharReader extends AbstractCharReader { - - private final char[] array; - private final int offset; - private final int length; - - public ArrayCharReader(char[] array, int offset, int length) { - this.array = Objects.requireNonNull(array, "array"); - this.length = ArrayUtil.checkArrayOffsetLength(array, offset, length); - this.offset = offset; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#current() - */ - @Override - public char current() { - if (position >= length) return DONE; - if (position < 0) - throw new IllegalStateException("Position " + position + " is invalid"); - return array[position + offset]; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() - */ - @Override - public int remaining() { - return length - position; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +import java.util.Objects; + +import ru.windcorp.jputil.ArrayUtil; + +/** + * @author Javapony + */ +public class ArrayCharReader extends AbstractCharReader { + + private final char[] array; + private final int offset; + private final int length; + + public ArrayCharReader(char[] array, int offset, int length) { + this.array = Objects.requireNonNull(array, "array"); + this.length = ArrayUtil.checkArrayOffsetLength(array, offset, length); + this.offset = offset; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#current() + */ + @Override + public char current() { + if (position >= length) + return DONE; + if (position < 0) + throw new IllegalStateException("Position " + position + " is invalid"); + return array[position + offset]; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() + */ + @Override + public int remaining() { + return length - position; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java index 5c6d5bd..83ae6b2 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/BufferedCharReader.java @@ -1,122 +1,128 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -/** - * @author Javapony - * - */ -public abstract class BufferedCharReader extends AbstractCharReader { - - protected static final int DEFAULT_BUFFER_SIZE = 256; - /** - * Buffer to store data acquired with {@link #pullChars(char[], int, int)}. - * Contains characters for positions [0; bufferNextIndex). - */ - private char[] buffer = new char[DEFAULT_BUFFER_SIZE]; - - /** - * The index of the next character. - */ - private int bufferNextIndex = 0; - - /** - * Whether this reader has been buffered completely. - */ - private boolean exhausted = false; - - /** - * Acquires the next character. - * @return the character or {@link #DONE} if the end of the reader has been reached - */ - protected abstract char pullChar(); - - /** - * Acquires next characters and stores them in the array. - * - * @param buffer the output array - * @param offset index of the first character - * @param length maximum amount of characters to be pulled - * @return the amount of characters actually pulled - */ - protected int pullChars(char[] buffer, int offset, int length) { - for (int i = 0; i < length; ++i) { - if ((buffer[offset + i] = pullChar()) == DONE) { - return i; - } - } - - return length; - } - - private int pullChars(int offset, int length) { - if (exhausted || length == 0) return 0; - - int pulled = pullChars(buffer, offset, length); - if (pulled != length) { - exhausted = true; - } - - return pulled; - } - - @Override - public char current() { - if (getPosition() < 0) { - throw new IllegalStateException("Position " + getPosition() + " is invalid"); - } - - if (getPosition() >= bufferNextIndex) { - if (exhausted) return DONE; - - ensureBufferCapacity(); - - int needToPull = getPosition() - bufferNextIndex + 1; - assert needToPull <= buffer.length : "buffer size not ensured!"; - - int pulled = pullChars(bufferNextIndex, needToPull); - bufferNextIndex += pulled; - - if (exhausted) return DONE; - } - - // TODO test the shit out of current() - - return buffer[getPosition()]; - } - - private void ensureBufferCapacity() { - if (getPosition() < buffer.length) return; - char[] newBuffer = new char[closestGreaterPowerOf2(getPosition())]; - System.arraycopy(buffer, 0, newBuffer, 0, bufferNextIndex); - buffer = newBuffer; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() - */ - @Override - public int remaining() { - if (exhausted) { - return Math.max(bufferNextIndex - getPosition(), 0); - } - - return super.remaining(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +/** + * @author Javapony + */ +public abstract class BufferedCharReader extends AbstractCharReader { + + protected static final int DEFAULT_BUFFER_SIZE = 256; + /** + * Buffer to store data acquired with {@link #pullChars(char[], int, int)}. + * Contains characters for positions [0; bufferNextIndex). + */ + private char[] buffer = new char[DEFAULT_BUFFER_SIZE]; + + /** + * The index of the next character. + */ + private int bufferNextIndex = 0; + + /** + * Whether this reader has been buffered completely. + */ + private boolean exhausted = false; + + /** + * Acquires the next character. + * + * @return the character or {@link #DONE} if the end of the reader has been + * reached + */ + protected abstract char pullChar(); + + /** + * Acquires next characters and stores them in the array. + * + * @param buffer the output array + * @param offset index of the first character + * @param length maximum amount of characters to be pulled + * @return the amount of characters actually pulled + */ + protected int pullChars(char[] buffer, int offset, int length) { + for (int i = 0; i < length; ++i) { + if ((buffer[offset + i] = pullChar()) == DONE) { + return i; + } + } + + return length; + } + + private int pullChars(int offset, int length) { + if (exhausted || length == 0) + return 0; + + int pulled = pullChars(buffer, offset, length); + if (pulled != length) { + exhausted = true; + } + + return pulled; + } + + @Override + public char current() { + if (getPosition() < 0) { + throw new IllegalStateException("Position " + getPosition() + " is invalid"); + } + + if (getPosition() >= bufferNextIndex) { + if (exhausted) + return DONE; + + ensureBufferCapacity(); + + int needToPull = getPosition() - bufferNextIndex + 1; + assert needToPull <= buffer.length : "buffer size not ensured!"; + + int pulled = pullChars(bufferNextIndex, needToPull); + bufferNextIndex += pulled; + + if (exhausted) + return DONE; + } + + // TODO test the shit out of current() + + return buffer[getPosition()]; + } + + private void ensureBufferCapacity() { + if (getPosition() < buffer.length) + return; + char[] newBuffer = new char[closestGreaterPowerOf2(getPosition())]; + System.arraycopy(buffer, 0, newBuffer, 0, bufferNextIndex); + buffer = newBuffer; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() + */ + @Override + public int remaining() { + if (exhausted) { + return Math.max(bufferNextIndex - getPosition(), 0); + } + + return super.remaining(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java index c6dd90a..147daf3 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/CharReader.java @@ -1,270 +1,284 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -import java.io.IOException; -import java.util.Arrays; - -import ru.windcorp.jputil.chars.CharPredicate; -import ru.windcorp.jputil.chars.EscapeException; -import ru.windcorp.jputil.chars.Escaper; - -/** - * @author Javapony - * - */ - -// SonarLint: Constants should not be defined in interfaces (java:S1214) -// DONE is an essential part of the interface -@SuppressWarnings("squid:S1214") - -public interface CharReader { - - char DONE = '\uFFFF'; - - char current(); - int getPosition(); - int setPosition(int position); - - default char next() { - return advance(1); - } - - default char previous() { - return rollBack(1); - } - - default char consume() { - char c = current(); - advance(1); - return c; - } - - default char advance(int forward) { - setPosition(getPosition() + forward); - return current(); - } - - default char rollBack(int backward) { - return advance(-backward); - } - - default boolean isEnd() { - return current() == DONE; - } - - default boolean has() { - return current() != DONE; - } - - default boolean is(char c) { - return current() == c; - } - - default int getChars(char[] output, int offset, int length) { - for (int i = 0; i < length; ++i) { - if ((output[offset + i] = current()) == DONE) { - return i; - } - next(); - } - - return length; - } - - default int getChars(char[] output) { - return getChars(output, 0, output.length); - } - - default char[] getChars(int length) { - char[] result = new char[length]; - int from = getChars(result); - if (from != length) Arrays.fill(result, from, length, DONE); - return result; - } - - default char[] getChars() { - return getChars(remaining()); - } - - default String getString(int length) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length && !isEnd(); ++i) sb.append(consume()); - return sb.toString(); - } - - default String getString() { - return getString(Integer.MAX_VALUE); - } - - default boolean match(CharSequence seq) { - for (int i = 0; i < seq.length(); ++i) { - if (isEnd()) return false; - if (current() != seq.charAt(i)) return false; - next(); - } - - return true; - } - - default boolean matchOrReset(CharSequence seq) { - mark(); - if (match(seq)) { - forget(); - return true; - } else { - reset(); - return false; - } - } - - default boolean match(char[] array) { - for (int i = 0; i < array.length; ++i) { - if (isEnd()) return false; - if (current() != array[i]) return false; - next(); - } - - return true; - } - - default boolean matchOrReset(char[] array) { - mark(); - if (match(array)) { - forget(); - return true; - } else { - reset(); - return false; - } - } - - default int skip(CharPredicate condition) { - int i = 0; - - while (has() && condition.test(current())) { - i++; - next(); - } - - return i; - } - - default int skipWhitespace() { - return skip(Character::isWhitespace); - } - - /** - * Skips to the end of the current line. Both "\n", "\r" - * and "\r\n" are considered line separators. - * @return the amount of characters in the skipped line - */ - default int skipLine() { - int i = 0; - - while (!isEnd()) { - if (current() == '\r') { - if (next() == '\n') { - next(); - } - break; - } else if (current() == '\n') { - next(); - break; - } - - i++; - next(); - } - - return i; - } - - default char[] readWhile(CharPredicate condition) { - return readUntil(CharPredicate.negate(condition)); - } - - default char[] readUntil(CharPredicate condition) { - mark(); - int length = 0; - while (!isEnd() && !condition.test(current())) { - length++; - next(); - } - reset(); - - char[] result = new char[length]; - for (int i = 0; i < length; ++i) result[i] = consume(); - return result; - } - - default char[] readWord() { - skipWhitespace(); - return readUntil(Character::isWhitespace); - } - - default char[] readWord(Escaper escaper, char quotes) throws EscapeException { - skipWhitespace(); - - if (current() == quotes) { - return escaper.unescape(this, quotes); - } else { - return readWord(); - } - } - - default char[] readLine() { - mark(); - int length = skipLine(); - reset(); - - char[] result = new char[length]; - for (int i = 0; i < result.length; ++i) result[i] = consume(); - return result; - } - - default int remaining() { - mark(); - int result = 0; - - while (consume() != DONE) result++; - - reset(); - return result; - } - - int mark(); - int forget(); - - default int reset() { - return setPosition(forget()); - } - - default IOException getLastException() { - return null; - } - - default void resetLastException() { - // Do nothing - } - - default boolean hasErrored() { - return getLastException() != null; - } - -} \ No newline at end of file +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +import java.io.IOException; +import java.util.Arrays; + +import ru.windcorp.jputil.chars.CharPredicate; +import ru.windcorp.jputil.chars.EscapeException; +import ru.windcorp.jputil.chars.Escaper; + +/** + * @author Javapony + */ + +// SonarLint: Constants should not be defined in interfaces (java:S1214) +// DONE is an essential part of the interface +@SuppressWarnings("squid:S1214") + +public interface CharReader { + + char DONE = '\uFFFF'; + + char current(); + + int getPosition(); + + int setPosition(int position); + + default char next() { + return advance(1); + } + + default char previous() { + return rollBack(1); + } + + default char consume() { + char c = current(); + advance(1); + return c; + } + + default char advance(int forward) { + setPosition(getPosition() + forward); + return current(); + } + + default char rollBack(int backward) { + return advance(-backward); + } + + default boolean isEnd() { + return current() == DONE; + } + + default boolean has() { + return current() != DONE; + } + + default boolean is(char c) { + return current() == c; + } + + default int getChars(char[] output, int offset, int length) { + for (int i = 0; i < length; ++i) { + if ((output[offset + i] = current()) == DONE) { + return i; + } + next(); + } + + return length; + } + + default int getChars(char[] output) { + return getChars(output, 0, output.length); + } + + default char[] getChars(int length) { + char[] result = new char[length]; + int from = getChars(result); + if (from != length) + Arrays.fill(result, from, length, DONE); + return result; + } + + default char[] getChars() { + return getChars(remaining()); + } + + default String getString(int length) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length && !isEnd(); ++i) + sb.append(consume()); + return sb.toString(); + } + + default String getString() { + return getString(Integer.MAX_VALUE); + } + + default boolean match(CharSequence seq) { + for (int i = 0; i < seq.length(); ++i) { + if (isEnd()) + return false; + if (current() != seq.charAt(i)) + return false; + next(); + } + + return true; + } + + default boolean matchOrReset(CharSequence seq) { + mark(); + if (match(seq)) { + forget(); + return true; + } else { + reset(); + return false; + } + } + + default boolean match(char[] array) { + for (int i = 0; i < array.length; ++i) { + if (isEnd()) + return false; + if (current() != array[i]) + return false; + next(); + } + + return true; + } + + default boolean matchOrReset(char[] array) { + mark(); + if (match(array)) { + forget(); + return true; + } else { + reset(); + return false; + } + } + + default int skip(CharPredicate condition) { + int i = 0; + + while (has() && condition.test(current())) { + i++; + next(); + } + + return i; + } + + default int skipWhitespace() { + return skip(Character::isWhitespace); + } + + /** + * Skips to the end of the current line. Both "\n", + * "\r" + * and "\r\n" are considered line separators. + * + * @return the amount of characters in the skipped line + */ + default int skipLine() { + int i = 0; + + while (!isEnd()) { + if (current() == '\r') { + if (next() == '\n') { + next(); + } + break; + } else if (current() == '\n') { + next(); + break; + } + + i++; + next(); + } + + return i; + } + + default char[] readWhile(CharPredicate condition) { + return readUntil(CharPredicate.negate(condition)); + } + + default char[] readUntil(CharPredicate condition) { + mark(); + int length = 0; + while (!isEnd() && !condition.test(current())) { + length++; + next(); + } + reset(); + + char[] result = new char[length]; + for (int i = 0; i < length; ++i) + result[i] = consume(); + return result; + } + + default char[] readWord() { + skipWhitespace(); + return readUntil(Character::isWhitespace); + } + + default char[] readWord(Escaper escaper, char quotes) throws EscapeException { + skipWhitespace(); + + if (current() == quotes) { + return escaper.unescape(this, quotes); + } else { + return readWord(); + } + } + + default char[] readLine() { + mark(); + int length = skipLine(); + reset(); + + char[] result = new char[length]; + for (int i = 0; i < result.length; ++i) + result[i] = consume(); + return result; + } + + default int remaining() { + mark(); + int result = 0; + + while (consume() != DONE) + result++; + + reset(); + return result; + } + + int mark(); + + int forget(); + + default int reset() { + return setPosition(forget()); + } + + default IOException getLastException() { + return null; + } + + default void resetLastException() { + // Do nothing + } + + default boolean hasErrored() { + return getLastException() != null; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java b/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java index 9cd02e0..a181dbf 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/CharReaders.java @@ -1,112 +1,113 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.text.CharacterIterator; -import java.util.function.IntSupplier; - -import ru.windcorp.jputil.chars.CharSupplier; - -/** - * @author Javapony - * - */ -public class CharReaders { - - private CharReaders() {} - - public static CharReader wrap(char[] array, int offset, int length) { - return new ArrayCharReader(array, offset, length); - } - - public static CharReader wrap(char[] array) { - return wrap(array, 0, array.length); - } - - public static CharReader wrap(String str, int offset, int length) { - return new StringCharReader(str, offset, length); - } - - public static CharReader wrap(String str) { - return wrap(str, 0, str.length()); - } - - public static CharReader wrap(CharSupplier supplier) { - return new BufferedCharReader() { - @Override - protected char pullChar() { - try { - return supplier.getAsChar(); - } catch (Exception e) { - return DONE; - } - } - }; - } - - public static CharReader wrap(IntSupplier supplier) { - return new BufferedCharReader() { - @Override - protected char pullChar() { - try { - int i = supplier.getAsInt(); - if (i < 0 || i > Character.MAX_VALUE) { - return DONE; - } else { - return (char) i; - } - } catch (Exception e) { - return DONE; - } - } - }; - } - - public static CharReader wrap(CharacterIterator it) { - return new BufferedCharReader() { - @Override - protected char pullChar() { - char result = it.current(); - it.next(); - return result; - } - }; - } - - public static CharReader wrap(Reader reader) { - return new ReaderCharReader(reader); - } - - public static CharReader wrap(InputStream is, Charset charset) { - return wrap(new InputStreamReader(is, charset)); - } - - public static CharReader wrapDefaultCS(InputStream is) { - return wrap(new InputStreamReader(is)); - } - - public static CharReader wrapUTF8(InputStream is) { - return wrap(new InputStreamReader(is, StandardCharsets.UTF_8)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.text.CharacterIterator; +import java.util.function.IntSupplier; + +import ru.windcorp.jputil.chars.CharSupplier; + +/** + * @author Javapony + */ +public class CharReaders { + + private CharReaders() { + } + + public static CharReader wrap(char[] array, int offset, int length) { + return new ArrayCharReader(array, offset, length); + } + + public static CharReader wrap(char[] array) { + return wrap(array, 0, array.length); + } + + public static CharReader wrap(String str, int offset, int length) { + return new StringCharReader(str, offset, length); + } + + public static CharReader wrap(String str) { + return wrap(str, 0, str.length()); + } + + public static CharReader wrap(CharSupplier supplier) { + return new BufferedCharReader() { + @Override + protected char pullChar() { + try { + return supplier.getAsChar(); + } catch (Exception e) { + return DONE; + } + } + }; + } + + public static CharReader wrap(IntSupplier supplier) { + return new BufferedCharReader() { + @Override + protected char pullChar() { + try { + int i = supplier.getAsInt(); + if (i < 0 || i > Character.MAX_VALUE) { + return DONE; + } else { + return (char) i; + } + } catch (Exception e) { + return DONE; + } + } + }; + } + + public static CharReader wrap(CharacterIterator it) { + return new BufferedCharReader() { + @Override + protected char pullChar() { + char result = it.current(); + it.next(); + return result; + } + }; + } + + public static CharReader wrap(Reader reader) { + return new ReaderCharReader(reader); + } + + public static CharReader wrap(InputStream is, Charset charset) { + return wrap(new InputStreamReader(is, charset)); + } + + public static CharReader wrapDefaultCS(InputStream is) { + return wrap(new InputStreamReader(is)); + } + + public static CharReader wrapUTF8(InputStream is) { + return wrap(new InputStreamReader(is, StandardCharsets.UTF_8)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java index 0a2435f..51a88db 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/ReaderCharReader.java @@ -1,70 +1,71 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -import java.io.IOException; -import java.io.Reader; - -/** - * @author Javapony - * - */ -public class ReaderCharReader extends BufferedCharReader { - - private final Reader src; - private IOException lastException = null; - - public ReaderCharReader(Reader src) { - this.src = src; - } - - /** - * @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChar() - */ - @Override - protected char pullChar() { - try { - return (char) src.read(); // Handles DONE correctly - } catch (IOException e) { - lastException = e; - return DONE; - } - } - - /** - * @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChars(char[], int, int) - */ - @Override - protected int pullChars(char[] buffer, int offset, int length) { - try { - return src.read(buffer, offset, length); - } catch (IOException e) { - lastException = e; - return 0; - } - } - - /** - * @return the exception - */ - @Override - public IOException getLastException() { - return lastException; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +import java.io.IOException; +import java.io.Reader; + +/** + * @author Javapony + */ +public class ReaderCharReader extends BufferedCharReader { + + private final Reader src; + private IOException lastException = null; + + public ReaderCharReader(Reader src) { + this.src = src; + } + + /** + * @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChar() + */ + @Override + protected char pullChar() { + try { + return (char) src.read(); // Handles DONE correctly + } catch (IOException e) { + lastException = e; + return DONE; + } + } + + /** + * @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChars(char[], + * int, int) + */ + @Override + protected int pullChars(char[] buffer, int offset, int length) { + try { + return src.read(buffer, offset, length); + } catch (IOException e) { + lastException = e; + return 0; + } + } + + /** + * @return the exception + */ + @Override + public IOException getLastException() { + return lastException; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java b/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java index c082321..5836d15 100644 --- a/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java +++ b/src/main/java/ru/windcorp/jputil/chars/reader/StringCharReader.java @@ -1,65 +1,68 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.chars.reader; - -import java.util.Objects; - -/** - * @author Javapony - * - */ -public class StringCharReader extends AbstractCharReader { - - private final String str; - private final int offset; - private final int length; - - public StringCharReader(String str, int offset, int length) { - this.str = Objects.requireNonNull(str, "str"); - - if (length < 0) - length = str.length(); - - int end = offset + length; - if (end > str.length() || offset < 0) - throw new IllegalArgumentException("String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"); - - this.offset = offset; - this.length = length; - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#current() - */ - @Override - public char current() { - if (position >= length) return DONE; - if (position < 0) - throw new IllegalStateException("Position " + position + " is invalid"); - return str.charAt(position + offset); - } - - /** - * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() - */ - @Override - public int remaining() { - return length - position; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.chars.reader; + +import java.util.Objects; + +/** + * @author Javapony + */ +public class StringCharReader extends AbstractCharReader { + + private final String str; + private final int offset; + private final int length; + + public StringCharReader(String str, int offset, int length) { + this.str = Objects.requireNonNull(str, "str"); + + if (length < 0) + length = str.length(); + + int end = offset + length; + if (end > str.length() || offset < 0) + throw new IllegalArgumentException( + "String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")" + ); + + this.offset = offset; + this.length = length; + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#current() + */ + @Override + public char current() { + if (position >= length) + return DONE; + if (position < 0) + throw new IllegalStateException("Position " + position + " is invalid"); + return str.charAt(position + offset); + } + + /** + * @see ru.windcorp.jputil.chars.reader.CharReader#remaining() + */ + @Override + public int remaining() { + return length - position; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java b/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java index 060b06a..a157032 100644 --- a/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java +++ b/src/main/java/ru/windcorp/jputil/functions/FloatSupplier.java @@ -1,8 +1,26 @@ -package ru.windcorp.jputil.functions; - -@FunctionalInterface -public interface FloatSupplier { - - float getAsFloat(); - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +@FunctionalInterface +public interface FloatSupplier { + + float getAsFloat(); + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java index 4e1c26e..be7cb8f 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingBiConsumer.java @@ -1,72 +1,76 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.functions; - -import java.util.function.BiConsumer; - -@FunctionalInterface -public interface ThrowingBiConsumer { - - @FunctionalInterface - public static interface BiConsumerHandler { - void handle(T t, U u, E e); - } - - void accept(T t, U u) throws E; - - @SuppressWarnings("unchecked") - default BiConsumer withHandler(BiConsumerHandler handler) { - return (t, u) -> { - try { - accept(t, u); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - handler.handle(t, u, (E) e); - } - }; - } - - public static ThrowingBiConsumer concat( - ThrowingBiConsumer first, - ThrowingBiConsumer second) { - return (t, u) -> { - first.accept(t, u); - second.accept(t, u); - }; - } - - public static ThrowingBiConsumer concat( - BiConsumer first, - ThrowingBiConsumer second) { - return (t, u) -> { - first.accept(t, u); - second.accept(t, u); - }; - } - - public static ThrowingBiConsumer concat( - ThrowingBiConsumer first, - BiConsumer second) { - return (t, u) -> { - first.accept(t, u); - second.accept(t, u); - }; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +import java.util.function.BiConsumer; + +@FunctionalInterface +public interface ThrowingBiConsumer { + + @FunctionalInterface + public static interface BiConsumerHandler { + void handle(T t, U u, E e); + } + + void accept(T t, U u) throws E; + + @SuppressWarnings("unchecked") + default BiConsumer withHandler(BiConsumerHandler handler) { + return (t, u) -> { + try { + accept(t, u); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + handler.handle(t, u, (E) e); + } + }; + } + + public static ThrowingBiConsumer concat( + ThrowingBiConsumer first, + ThrowingBiConsumer second + ) { + return (t, u) -> { + first.accept(t, u); + second.accept(t, u); + }; + } + + public static ThrowingBiConsumer concat( + BiConsumer first, + ThrowingBiConsumer second + ) { + return (t, u) -> { + first.accept(t, u); + second.accept(t, u); + }; + } + + public static ThrowingBiConsumer concat( + ThrowingBiConsumer first, + BiConsumer second + ) { + return (t, u) -> { + first.accept(t, u); + second.accept(t, u); + }; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java index dcd1931..14449ca 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingConsumer.java @@ -1,62 +1,72 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.functions; - -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -@FunctionalInterface -public interface ThrowingConsumer { - - void accept(T t) throws E; - - @SuppressWarnings("unchecked") - default Consumer withHandler(BiConsumer handler) { - return t -> { - try { - accept(t); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - handler.accept(t, (E) e); - } - }; - } - - public static ThrowingConsumer concat(ThrowingConsumer first, ThrowingConsumer second) { - return t -> { - first.accept(t); - second.accept(t); - }; - } - - public static ThrowingConsumer concat(Consumer first, ThrowingConsumer second) { - return t -> { - first.accept(t); - second.accept(t); - }; - } - - public static ThrowingConsumer concat(ThrowingConsumer first, Consumer second) { - return t -> { - first.accept(t); - second.accept(t); - }; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +@FunctionalInterface +public interface ThrowingConsumer { + + void accept(T t) throws E; + + @SuppressWarnings("unchecked") + default Consumer withHandler(BiConsumer handler) { + return t -> { + try { + accept(t); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + handler.accept(t, (E) e); + } + }; + } + + public static ThrowingConsumer concat( + ThrowingConsumer first, + ThrowingConsumer second + ) { + return t -> { + first.accept(t); + second.accept(t); + }; + } + + public static ThrowingConsumer concat( + Consumer first, + ThrowingConsumer second + ) { + return t -> { + first.accept(t); + second.accept(t); + }; + } + + public static ThrowingConsumer concat( + ThrowingConsumer first, + Consumer second + ) { + return t -> { + first.accept(t); + second.accept(t); + }; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java index faffb44..afdd078 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingFunction.java @@ -1,73 +1,81 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.functions; - -import java.util.function.BiConsumer; -import java.util.function.Function; -import java.util.function.Supplier; - -@FunctionalInterface -public interface ThrowingFunction { - - R apply(T t) throws E; - - @SuppressWarnings("unchecked") - default Function withHandler(BiConsumer handler, Function value) { - return t -> { - try { - return apply(t); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - if (handler != null) handler.accept(t, (E) e); - return value == null ? null : value.apply(t); - } - }; - } - - default Function withHandler(BiConsumer handler, Supplier value) { - return withHandler(handler, t -> value.get()); - } - - default Function withHandler(BiConsumer handler, R value) { - return withHandler(handler, t -> value); - } - - default Function withHandler(BiConsumer handler) { - return withHandler(handler, (Function) null); - } - - public static ThrowingFunction compose( - ThrowingFunction first, - ThrowingFunction second) { - return t -> second.apply(first.apply(t)); - } - - public static ThrowingFunction compose( - Function first, - ThrowingFunction second) { - return t -> second.apply(first.apply(t)); - } - - public static ThrowingFunction compose( - ThrowingFunction first, - Function second) { - return t -> second.apply(first.apply(t)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +@FunctionalInterface +public interface ThrowingFunction { + + R apply(T t) throws E; + + @SuppressWarnings("unchecked") + default Function withHandler( + BiConsumer handler, + Function value + ) { + return t -> { + try { + return apply(t); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + if (handler != null) + handler.accept(t, (E) e); + return value == null ? null : value.apply(t); + } + }; + } + + default Function withHandler(BiConsumer handler, Supplier value) { + return withHandler(handler, t -> value.get()); + } + + default Function withHandler(BiConsumer handler, R value) { + return withHandler(handler, t -> value); + } + + default Function withHandler(BiConsumer handler) { + return withHandler(handler, (Function) null); + } + + public static ThrowingFunction compose( + ThrowingFunction first, + ThrowingFunction second + ) { + return t -> second.apply(first.apply(t)); + } + + public static ThrowingFunction compose( + Function first, + ThrowingFunction second + ) { + return t -> second.apply(first.apply(t)); + } + + public static ThrowingFunction compose( + ThrowingFunction first, + Function second + ) { + return t -> second.apply(first.apply(t)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java index 0684122..f27429b 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingRunnable.java @@ -1,64 +1,65 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.functions; - -import java.util.function.Consumer; - -@FunctionalInterface -public interface ThrowingRunnable { - - void run() throws E; - - @SuppressWarnings("unchecked") - default Runnable withHandler(Consumer handler) { - return () -> { - try { - run(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - handler.accept((E) e); - } - }; - } - - public static ThrowingRunnable concat( - ThrowingRunnable first, - ThrowingRunnable second - ) { - return () -> { - first.run(); - second.run(); - }; - } - - public static ThrowingRunnable concat(Runnable first, ThrowingRunnable second) { - return () -> { - first.run(); - second.run(); - }; - } - - public static ThrowingRunnable concat(ThrowingRunnable first, Runnable second) { - return () -> { - first.run(); - second.run(); - }; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +import java.util.function.Consumer; + +@FunctionalInterface +public interface ThrowingRunnable { + + void run() throws E; + + @SuppressWarnings("unchecked") + default Runnable withHandler(Consumer handler) { + return () -> { + try { + run(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + handler.accept((E) e); + } + }; + } + + public static ThrowingRunnable concat( + ThrowingRunnable first, + ThrowingRunnable second + ) { + return () -> { + first.run(); + second.run(); + }; + } + + public static ThrowingRunnable concat(Runnable first, ThrowingRunnable second) { + return () -> { + first.run(); + second.run(); + }; + } + + public static ThrowingRunnable concat(ThrowingRunnable first, Runnable second) { + return () -> { + first.run(); + second.run(); + }; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java b/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java index 32327e5..84ad690 100644 --- a/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java +++ b/src/main/java/ru/windcorp/jputil/functions/ThrowingSupplier.java @@ -1,50 +1,52 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.functions; - -import java.util.function.Consumer; -import java.util.function.Supplier; - -@FunctionalInterface -public interface ThrowingSupplier { - - T get() throws E; - - @SuppressWarnings("unchecked") - default Supplier withHandler(Consumer handler, Supplier value) { - return () -> { - try { - return get(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - if (handler != null) handler.accept((E) e); - return value == null ? null : value.get(); - } - }; - } - - default Supplier withHandler(Consumer handler, T value) { - return withHandler(handler, () -> value); - } - - default Supplier withHandler(Consumer handler) { - return withHandler(handler, (Supplier) null); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.functions; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +@FunctionalInterface +public interface ThrowingSupplier { + + T get() throws E; + + @SuppressWarnings("unchecked") + default Supplier withHandler(Consumer handler, Supplier value) { + return () -> { + try { + return get(); + } catch (RuntimeException e) { + throw e; + } catch (Exception e) { + if (handler != null) + handler.accept((E) e); + return value == null ? null : value.get(); + } + }; + } + + default Supplier withHandler(Consumer handler, T value) { + return withHandler(handler, () -> value); + } + + default Supplier withHandler(Consumer handler) { + return withHandler(handler, (Supplier) null); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java b/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java index dc0cdcd..0b8fab2 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/ArrayIterator.java @@ -1,47 +1,48 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.iterators; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -public class ArrayIterator implements Iterator { - - private final E[] array; - private int next; - - @SafeVarargs - public ArrayIterator(E... array) { - this.array = array; - } - - @Override - public boolean hasNext() { - return next < array.length; - } - - @Override - public E next() { - try { - return array[next++]; - } catch (ArrayIndexOutOfBoundsException e) { - throw new NoSuchElementException(); - } - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class ArrayIterator implements Iterator { + + private final E[] array; + private int next; + + @SafeVarargs + public ArrayIterator(E... array) { + this.array = array; + } + + @Override + public boolean hasNext() { + return next < array.length; + } + + @Override + public E next() { + try { + return array[next++]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + +} diff --git a/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java b/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java index a8d63ae..abc5b44 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/FunctionIterator.java @@ -1,61 +1,61 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.iterators; - -import java.util.Iterator; -import java.util.function.Function; - -/** - * @author Javapony - * - */ -public class FunctionIterator implements Iterator { - - private final Iterator parent; - private final Function function; - - public FunctionIterator(Iterator parent, Function function) { - this.parent = parent; - this.function = function; - } - - /** - * @see java.util.Iterator#hasNext() - */ - @Override - public boolean hasNext() { - return parent.hasNext(); - } - - /** - * @see java.util.Iterator#next() - */ - @Override - public E next() { - return function.apply(parent.next()); - } - - /** - * @see java.util.Iterator#remove() - */ - @Override - public void remove() { - parent.remove(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.iterators; + +import java.util.Iterator; +import java.util.function.Function; + +/** + * @author Javapony + */ +public class FunctionIterator implements Iterator { + + private final Iterator parent; + private final Function function; + + public FunctionIterator(Iterator parent, Function function) { + this.parent = parent; + this.function = function; + } + + /** + * @see java.util.Iterator#hasNext() + */ + @Override + public boolean hasNext() { + return parent.hasNext(); + } + + /** + * @see java.util.Iterator#next() + */ + @Override + public E next() { + return function.apply(parent.next()); + } + + /** + * @see java.util.Iterator#remove() + */ + @Override + public void remove() { + parent.remove(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java b/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java index 0eaff06..67f3da9 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/PeekingIterator.java @@ -1,60 +1,62 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.iterators; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -public class PeekingIterator implements Iterator { - - private final Iterator source; - private E next = null; - - public PeekingIterator(Iterator source) { - this.source = source; - } - - @Override - public boolean hasNext() { - return next != null || source.hasNext(); - } - - public E peek() { - if (next == null) { - if (source.hasNext()) { - next = source.next(); - } else { - throw new NoSuchElementException(); - } - } - - return next; - } - - // SonarLint: "Iterator.next()" methods should throw "NoSuchElementException" (java:S2272) - // peek() throws NoSuchElementException as expected - @SuppressWarnings("squid:S2272") - - @Override - public E next() { - E element = peek(); - next = null; - return element; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class PeekingIterator implements Iterator { + + private final Iterator source; + private E next = null; + + public PeekingIterator(Iterator source) { + this.source = source; + } + + @Override + public boolean hasNext() { + return next != null || source.hasNext(); + } + + public E peek() { + if (next == null) { + if (source.hasNext()) { + next = source.next(); + } else { + throw new NoSuchElementException(); + } + } + + return next; + } + + // SonarLint: "Iterator.next()" methods should throw + // "NoSuchElementException" (java:S2272) + // peek() throws NoSuchElementException as expected + @SuppressWarnings("squid:S2272") + + @Override + public E next() { + E element = peek(); + next = null; + return element; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java b/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java index 49d69fa..7da8ada 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/RangeIterator.java @@ -1,67 +1,70 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.iterators; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -public class RangeIterator implements Iterator { - - private final Iterator parent; - private final int from; - private final int amount; - - private int nextIndex = 0; - - public RangeIterator(Iterator iterator, int from, int amount) { - this.parent = iterator; - this.from = from; - this.amount = amount < 0 ? Integer.MAX_VALUE : amount; - } - - public RangeIterator(Iterator iterator, int from) { - this(iterator, from, -1); - } - - @Override - public boolean hasNext() { - update(); - return nextIndex < from + amount && parent.hasNext(); - } - - @Override - public E next() { - update(); - if (nextIndex >= from + amount) { - throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex - + " which exceeds upper boundary " + (from + amount)); - } - - E result = parent.next(); - nextIndex++; - return result; - } - - protected void update() { - while (nextIndex < from && parent.hasNext()) { - parent.next(); - nextIndex++; - } - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.iterators; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class RangeIterator implements Iterator { + + private final Iterator parent; + private final int from; + private final int amount; + + private int nextIndex = 0; + + public RangeIterator(Iterator iterator, int from, int amount) { + this.parent = iterator; + this.from = from; + this.amount = amount < 0 ? Integer.MAX_VALUE : amount; + } + + public RangeIterator(Iterator iterator, int from) { + this(iterator, from, -1); + } + + @Override + public boolean hasNext() { + update(); + return nextIndex < from + amount && parent.hasNext(); + } + + @Override + public E next() { + update(); + if (nextIndex >= from + amount) { + throw new NoSuchElementException( + "RangeIterator about to retrieve element " + nextIndex + + " which exceeds upper boundary " + (from + amount) + ); + } + + E result = parent.next(); + nextIndex++; + return result; + } + + protected void update() { + while (nextIndex < from && parent.hasNext()) { + parent.next(); + nextIndex++; + } + } + +} diff --git a/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java b/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java index 71adb06..7969bc1 100644 --- a/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java +++ b/src/main/java/ru/windcorp/jputil/iterators/Reiterator.java @@ -1,70 +1,72 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.iterators; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.NoSuchElementException; - -public class Reiterator implements Iterable { - - private class ReiteratorIterator implements Iterator { - - int index = 0; - - @Override - public boolean hasNext() { - synchronized (source) { - if (index >= data.size()) { - if (!source.hasNext()) { - return false; - } else { - data.add(source.next()); - } - } - - return true; - } - } - - @Override - public E next() { - E result; - synchronized (source) { - if (!hasNext()) throw new NoSuchElementException(); - result = data.get(index); - } - index++; - return result; - } - - } - - private final Iterator source; - private final ArrayList data = new ArrayList<>(); - - public Reiterator(Iterator source) { - this.source = source; - } - - @Override - public Iterator iterator() { - return new ReiteratorIterator(); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.iterators; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class Reiterator implements Iterable { + + private class ReiteratorIterator implements Iterator { + + int index = 0; + + @Override + public boolean hasNext() { + synchronized (source) { + if (index >= data.size()) { + if (!source.hasNext()) { + return false; + } else { + data.add(source.next()); + } + } + + return true; + } + } + + @Override + public E next() { + E result; + synchronized (source) { + if (!hasNext()) + throw new NoSuchElementException(); + result = data.get(index); + } + index++; + return result; + } + + } + + private final Iterator source; + private final ArrayList data = new ArrayList<>(); + + public Reiterator(Iterator source) { + this.source = source; + } + + @Override + public Iterator iterator() { + return new ReiteratorIterator(); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java b/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java index 1b0181f..481e558 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java +++ b/src/main/java/ru/windcorp/jputil/selectors/AbstractSelectorOperator.java @@ -1,39 +1,40 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -public abstract class AbstractSelectorOperator implements SelectorOperator { - - private final String[] names; - - public AbstractSelectorOperator(String[] names) { - this.names = names; - } - - @Override - public boolean matchesName(String name) { - for (String n : names) { - if (n.equals(name)) { - return true; - } - } - - return false; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +public abstract class AbstractSelectorOperator implements SelectorOperator { + + private final String[] names; + + public AbstractSelectorOperator(String[] names) { + this.names = names; + } + + @Override + public boolean matchesName(String name) { + for (String n : names) { + if (n.equals(name)) { + return true; + } + } + + return false; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java b/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java index 8893a05..e0676fd 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/NamedParameterizedSelector.java @@ -1,57 +1,58 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import ru.windcorp.jputil.SyntaxException; -import ru.windcorp.jputil.chars.StringUtil; - -public abstract class NamedParameterizedSelector extends NamedSelector { - - private final char separator; - private String givenName; - - public NamedParameterizedSelector(char separator, String... names) { - super(names); - this.separator = separator; - } - - @Override - public Selector derive(String name) throws SyntaxException { - String[] parts = StringUtil.split(name, separator, 2); - - if (parts[1] == null) { - return null; - } - - if (!matchesName(parts[0])) { - return null; - } - - NamedParameterizedSelector selector = deriveImpl(parts[1]); - selector.givenName = name; - return selector; - } - - protected abstract NamedParameterizedSelector deriveImpl(String param) throws SyntaxException; - - @Override - public String toString() { - return givenName; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import ru.windcorp.jputil.SyntaxException; +import ru.windcorp.jputil.chars.StringUtil; + +public abstract class NamedParameterizedSelector extends NamedSelector { + + private final char separator; + private String givenName; + + public NamedParameterizedSelector(char separator, String... names) { + super(names); + this.separator = separator; + } + + @Override + public Selector derive(String name) throws SyntaxException { + String[] parts = StringUtil.split(name, separator, 2); + + if (parts[1] == null) { + return null; + } + + if (!matchesName(parts[0])) { + return null; + } + + NamedParameterizedSelector selector = deriveImpl(parts[1]); + selector.givenName = name; + return selector; + } + + protected abstract NamedParameterizedSelector deriveImpl(String param) throws SyntaxException; + + @Override + public String toString() { + return givenName; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java b/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java index 864c214..196be14 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/NamedSelector.java @@ -1,50 +1,51 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import ru.windcorp.jputil.SyntaxException; - -public abstract class NamedSelector implements Selector { - - private final String[] names; - - public NamedSelector(String... names) { - this.names = names; - } - - public boolean matchesName(String name) { - for (String n : names) { - if (n.equalsIgnoreCase(name)) { - return true; - } - } - - return false; - } - - @Override - public Selector derive(String name) throws SyntaxException { - return matchesName(name) ? this : null; - } - - @Override - public String toString() { - return names[0]; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import ru.windcorp.jputil.SyntaxException; + +public abstract class NamedSelector implements Selector { + + private final String[] names; + + public NamedSelector(String... names) { + this.names = names; + } + + public boolean matchesName(String name) { + for (String n : names) { + if (n.equalsIgnoreCase(name)) { + return true; + } + } + + return false; + } + + @Override + public Selector derive(String name) throws SyntaxException { + return matchesName(name) ? this : null; + } + + @Override + public String toString() { + return names[0]; + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java index 61641c4..603c6d4 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorAnd.java @@ -1,36 +1,37 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public class OperatorAnd extends AbstractSelectorOperator { - - public OperatorAnd(String... names) { - super(names); - } - - @Override - public void process(Deque> stack) { - Predicate arg2 = stack.pop(); - Predicate arg1 = stack.pop(); - stack.push(obj -> arg1.test(obj) && arg2.test(obj)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public class OperatorAnd extends AbstractSelectorOperator { + + public OperatorAnd(String... names) { + super(names); + } + + @Override + public void process(Deque> stack) { + Predicate arg2 = stack.pop(); + Predicate arg1 = stack.pop(); + stack.push(obj -> arg1.test(obj) && arg2.test(obj)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java index 5e7235a..a805a2f 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorExclude.java @@ -1,36 +1,37 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public class OperatorExclude extends AbstractSelectorOperator { - - public OperatorExclude(String... names) { - super(names); - } - - @Override - public void process(Deque> stack) { - Predicate arg2 = stack.pop(); - Predicate arg1 = stack.pop(); - stack.push(obj -> arg1.test(obj) && !arg2.test(obj)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public class OperatorExclude extends AbstractSelectorOperator { + + public OperatorExclude(String... names) { + super(names); + } + + @Override + public void process(Deque> stack) { + Predicate arg2 = stack.pop(); + Predicate arg1 = stack.pop(); + stack.push(obj -> arg1.test(obj) && !arg2.test(obj)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java index cd445d8..2bf0300 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorNot.java @@ -1,34 +1,35 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public class OperatorNot extends AbstractSelectorOperator { - - public OperatorNot(String... names) { - super(names); - } - - @Override - public void process(Deque> stack) { - stack.push(stack.pop().negate()); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public class OperatorNot extends AbstractSelectorOperator { + + public OperatorNot(String... names) { + super(names); + } + + @Override + public void process(Deque> stack) { + stack.push(stack.pop().negate()); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java index e40a1a1..367e6c3 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorOr.java @@ -1,36 +1,37 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public class OperatorOr extends AbstractSelectorOperator { - - public OperatorOr(String... names) { - super(names); - } - - @Override - public void process(Deque> stack) { - Predicate arg2 = stack.pop(); - Predicate arg1 = stack.pop(); - stack.push(obj -> arg1.test(obj) || arg2.test(obj)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public class OperatorOr extends AbstractSelectorOperator { + + public OperatorOr(String... names) { + super(names); + } + + @Override + public void process(Deque> stack) { + Predicate arg2 = stack.pop(); + Predicate arg1 = stack.pop(); + stack.push(obj -> arg1.test(obj) || arg2.test(obj)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java b/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java index e4ff44d..467e6a0 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java +++ b/src/main/java/ru/windcorp/jputil/selectors/OperatorXor.java @@ -1,36 +1,37 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public class OperatorXor extends AbstractSelectorOperator { - - public OperatorXor(String... names) { - super(names); - } - - @Override - public void process(Deque> stack) { - Predicate arg2 = stack.pop(); - Predicate arg1 = stack.pop(); - stack.push(obj -> arg1.test(obj) != arg2.test(obj)); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public class OperatorXor extends AbstractSelectorOperator { + + public OperatorXor(String... names) { + super(names); + } + + @Override + public void process(Deque> stack) { + Predicate arg2 = stack.pop(); + Predicate arg1 = stack.pop(); + stack.push(obj -> arg1.test(obj) != arg2.test(obj)); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java b/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java index 86f21fc..278df45 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java +++ b/src/main/java/ru/windcorp/jputil/selectors/PredicateWrapper.java @@ -1,36 +1,37 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.function.Predicate; - -public class PredicateWrapper extends NamedSelector { - - private final Predicate predicate; - - public PredicateWrapper(String name, Predicate predicate) { - super(name); - this.predicate = predicate; - } - - @Override - public boolean test(T obj) { - return predicate.test(obj); - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.function.Predicate; + +public class PredicateWrapper extends NamedSelector { + + private final Predicate predicate; + + public PredicateWrapper(String name, Predicate predicate) { + super(name); + this.predicate = predicate; + } + + @Override + public boolean test(T obj) { + return predicate.test(obj); + } + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/Selector.java b/src/main/java/ru/windcorp/jputil/selectors/Selector.java index 4db3a08..eec8b06 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/Selector.java +++ b/src/main/java/ru/windcorp/jputil/selectors/Selector.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.function.Predicate; - -import ru.windcorp.jputil.SyntaxException; - -public interface Selector extends Predicate { - - public Selector derive(String name) throws SyntaxException; - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.function.Predicate; + +import ru.windcorp.jputil.SyntaxException; + +public interface Selector extends Predicate { + + public Selector derive(String name) throws SyntaxException; + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java b/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java index fc8250f..665d231 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java +++ b/src/main/java/ru/windcorp/jputil/selectors/SelectorOperator.java @@ -1,29 +1,30 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.Deque; -import java.util.function.Predicate; - -public interface SelectorOperator { - - public void process(Deque> stack); - - public boolean matchesName(String name); - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.Deque; +import java.util.function.Predicate; + +public interface SelectorOperator { + + public void process(Deque> stack); + + public boolean matchesName(String name); + +} diff --git a/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java b/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java index 9238c2b..0361795 100644 --- a/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java +++ b/src/main/java/ru/windcorp/jputil/selectors/SelectorSystem.java @@ -1,176 +1,175 @@ -/******************************************************************************* - * JPUtil - * Copyright (C) 2019 Javapony/OLEGSHA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.jputil.selectors; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.function.Predicate; - -import ru.windcorp.jputil.SyntaxException; -import ru.windcorp.jputil.iterators.PeekingIterator; - -public class SelectorSystem { - - public static final char EXPRESSION_OPEN = '('; - public static final char EXPRESSION_CLOSE = ')'; - - private final Collection> selectors = - Collections.synchronizedCollection(new ArrayList>()); - - private final Collection operators = - Collections.synchronizedCollection(new ArrayList()); - - private String stackPrefix = null; - - public Collection> getSelectors() { - return this.selectors; - } - - public Collection getSelectorOperators() { - return this.operators; - } - - public String getStackPrefix() { - return stackPrefix; - } - - public SelectorSystem setStackPrefix(String stackPrefix) { - this.stackPrefix = stackPrefix; - return this; - } - - public SelectorSystem add(Selector selector) { - getSelectors().add(selector); - return this; - } - - public SelectorSystem add(SelectorOperator operator) { - getSelectorOperators().add(operator); - return this; - } - - public Predicate parse(Iterator tokens) throws SyntaxException { - PeekingIterator peeker = new PeekingIterator<>(tokens); - - if (getStackPrefix() != null && peeker.hasNext() && getStackPrefix().equals(peeker.peek())) { - peeker.next(); - return parseStack(peeker); - } - - Deque> stack = new LinkedList<>(); - - synchronized (getSelectorOperators()) { - synchronized (getSelectors()) { - - while (peeker.hasNext()) { - parseToken(stack, peeker); - } - - } - } - - return compress(stack); - } - - private void parseToken(Deque> stack, Iterator tokens) throws SyntaxException { - - if (!tokens.hasNext()) { - throw new SyntaxException("Not enough tokens"); - } - String token = tokens.next(); - - for (SelectorOperator operator : getSelectorOperators()) { - if (operator.matchesName(token.toLowerCase())) { - parseToken(stack, tokens); - operator.process(stack); - return; - } - } - - Selector tmp; - for (Selector selector : getSelectors()) { - if ((tmp = selector.derive(token)) != null) { - stack.push(tmp); - return; - } - } - - throw new SyntaxException("Unknown token \"" + token + "\""); - } - - public Predicate parseStack(Iterator tokens) throws SyntaxException { - Deque> stack = new LinkedList<>(); - - String token; - - synchronized (getSelectorOperators()) { - synchronized (getSelectors()) { - - tokenCycle: - while (tokens.hasNext()) { - token = tokens.next(); - - for (SelectorOperator operator : getSelectorOperators()) { - if (operator.matchesName(token.toLowerCase())) { - operator.process(stack); - continue tokenCycle; - } - } - - for (Selector selector : getSelectors()) { - Selector tmp; - if ((tmp = selector.derive(token)) != null) { - stack.push(tmp); - continue tokenCycle; - } - } - - throw new SyntaxException("Unknown token \"" + token + "\""); - - } - } - } - - return compress(stack); - } - - private Predicate compress(Deque> stack) throws SyntaxException { - if (stack.isEmpty()) { - throw new SyntaxException("Stack is empty"); - } - - if (stack.size() == 1) { - return stack.pop(); - } - - return obj -> { - for (Predicate predicate : stack) { - if (predicate.test(obj)) { - return true; - } - } - - return false; - }; - } - -} +/* + * JPUtil + * Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.jputil.selectors; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.function.Predicate; + +import ru.windcorp.jputil.SyntaxException; +import ru.windcorp.jputil.iterators.PeekingIterator; + +public class SelectorSystem { + + public static final char EXPRESSION_OPEN = '('; + public static final char EXPRESSION_CLOSE = ')'; + + private final Collection> selectors = Collections.synchronizedCollection(new ArrayList>()); + + private final Collection operators = Collections + .synchronizedCollection(new ArrayList()); + + private String stackPrefix = null; + + public Collection> getSelectors() { + return this.selectors; + } + + public Collection getSelectorOperators() { + return this.operators; + } + + public String getStackPrefix() { + return stackPrefix; + } + + public SelectorSystem setStackPrefix(String stackPrefix) { + this.stackPrefix = stackPrefix; + return this; + } + + public SelectorSystem add(Selector selector) { + getSelectors().add(selector); + return this; + } + + public SelectorSystem add(SelectorOperator operator) { + getSelectorOperators().add(operator); + return this; + } + + public Predicate parse(Iterator tokens) throws SyntaxException { + PeekingIterator peeker = new PeekingIterator<>(tokens); + + if (getStackPrefix() != null && peeker.hasNext() && getStackPrefix().equals(peeker.peek())) { + peeker.next(); + return parseStack(peeker); + } + + Deque> stack = new LinkedList<>(); + + synchronized (getSelectorOperators()) { + synchronized (getSelectors()) { + + while (peeker.hasNext()) { + parseToken(stack, peeker); + } + + } + } + + return compress(stack); + } + + private void parseToken(Deque> stack, Iterator tokens) throws SyntaxException { + + if (!tokens.hasNext()) { + throw new SyntaxException("Not enough tokens"); + } + String token = tokens.next(); + + for (SelectorOperator operator : getSelectorOperators()) { + if (operator.matchesName(token.toLowerCase())) { + parseToken(stack, tokens); + operator.process(stack); + return; + } + } + + Selector tmp; + for (Selector selector : getSelectors()) { + if ((tmp = selector.derive(token)) != null) { + stack.push(tmp); + return; + } + } + + throw new SyntaxException("Unknown token \"" + token + "\""); + } + + public Predicate parseStack(Iterator tokens) throws SyntaxException { + Deque> stack = new LinkedList<>(); + + String token; + + synchronized (getSelectorOperators()) { + synchronized (getSelectors()) { + + tokenCycle: while (tokens.hasNext()) { + token = tokens.next(); + + for (SelectorOperator operator : getSelectorOperators()) { + if (operator.matchesName(token.toLowerCase())) { + operator.process(stack); + continue tokenCycle; + } + } + + for (Selector selector : getSelectors()) { + Selector tmp; + if ((tmp = selector.derive(token)) != null) { + stack.push(tmp); + continue tokenCycle; + } + } + + throw new SyntaxException("Unknown token \"" + token + "\""); + + } + } + } + + return compress(stack); + } + + private Predicate compress(Deque> stack) throws SyntaxException { + if (stack.isEmpty()) { + throw new SyntaxException("Stack is empty"); + } + + if (stack.size() == 1) { + return stack.pop(); + } + + return obj -> { + for (Predicate predicate : stack) { + if (predicate.test(obj)) { + return true; + } + } + + return false; + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/Progressia.java b/src/main/java/ru/windcorp/progressia/Progressia.java index bba4100..db899ea 100644 --- a/src/main/java/ru/windcorp/progressia/Progressia.java +++ b/src/main/java/ru/windcorp/progressia/Progressia.java @@ -1,22 +1,23 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia; - -public class Progressia { - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia; + +public class Progressia { + +} diff --git a/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java b/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java index dfda8c5..4944f1c 100644 --- a/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java +++ b/src/main/java/ru/windcorp/progressia/ProgressiaLauncher.java @@ -1,50 +1,51 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia; - -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer; -import ru.windcorp.progressia.common.util.crash.providers.*; - -public class ProgressiaLauncher { - - public static String[] arguments; - - public static void launch(String[] args, Proxy proxy) { - arguments = args.clone(); - setupCrashReports(); - proxy.initialize(); - } - - private static void setupCrashReports() { - // Context providers - CrashReports.registerProvider(new OSContextProvider()); - CrashReports.registerProvider(new RAMContextProvider()); - CrashReports.registerProvider(new JavaVersionContextProvider()); - CrashReports.registerProvider(new OpenALContextProvider()); - CrashReports.registerProvider(new ArgsContextProvider()); - CrashReports.registerProvider(new LanguageContextProvider()); - // Analyzers - CrashReports.registerAnalyzer(new OutOfMemoryAnalyzer()); - - Thread.setDefaultUncaughtExceptionHandler((Thread thread, Throwable t)-> { - CrashReports.crash(t, "Uncaught exception in thread %s", thread.getName()); - }); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia; + +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer; +import ru.windcorp.progressia.common.util.crash.providers.*; + +public class ProgressiaLauncher { + + public static String[] arguments; + + public static void launch(String[] args, Proxy proxy) { + arguments = args.clone(); + setupCrashReports(); + proxy.initialize(); + } + + private static void setupCrashReports() { + // Context providers + CrashReports.registerProvider(new OSContextProvider()); + CrashReports.registerProvider(new RAMContextProvider()); + CrashReports.registerProvider(new JavaVersionContextProvider()); + CrashReports.registerProvider(new OpenALContextProvider()); + CrashReports.registerProvider(new ArgsContextProvider()); + CrashReports.registerProvider(new LanguageContextProvider()); + // Analyzers + CrashReports.registerAnalyzer(new OutOfMemoryAnalyzer()); + + Thread.setDefaultUncaughtExceptionHandler((Thread thread, Throwable t) -> { + CrashReports.crash(t, "Uncaught exception in thread %s", thread.getName()); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/Proxy.java b/src/main/java/ru/windcorp/progressia/Proxy.java index 516e4eb..a1af080 100644 --- a/src/main/java/ru/windcorp/progressia/Proxy.java +++ b/src/main/java/ru/windcorp/progressia/Proxy.java @@ -1,24 +1,25 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia; - -public interface Proxy { - - void initialize(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia; + +public interface Proxy { + + void initialize(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/Client.java b/src/main/java/ru/windcorp/progressia/client/Client.java index 0d84fe3..d8800c7 100644 --- a/src/main/java/ru/windcorp/progressia/client/Client.java +++ b/src/main/java/ru/windcorp/progressia/client/Client.java @@ -1,59 +1,79 @@ -package ru.windcorp.progressia.client; - -import ru.windcorp.progressia.client.comms.DefaultClientCommsListener; -import ru.windcorp.progressia.client.comms.ServerCommsChannel; -import ru.windcorp.progressia.client.graphics.world.Camera; -import ru.windcorp.progressia.client.graphics.world.EntityAnchor; -import ru.windcorp.progressia.client.graphics.world.LocalPlayer; -import ru.windcorp.progressia.client.world.WorldRender; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.entity.EntityData; - -public class Client { - - private final WorldRender world; - private final LocalPlayer localPlayer = new LocalPlayer(this); - - private final Camera camera = new Camera((float) Math.toRadians(70)); - - private final ServerCommsChannel comms; - - public Client(WorldData world, ServerCommsChannel comms) { - this.world = new WorldRender(world, this); - this.comms = comms; - - comms.addListener(new DefaultClientCommsListener(this)); - } - - public WorldRender getWorld() { - return world; - } - - public LocalPlayer getLocalPlayer() { - return localPlayer; - } - - public boolean isReady() { - return localPlayer.hasEntity(); - } - - public Camera getCamera() { - return camera; - } - - public ServerCommsChannel getComms() { - return comms; - } - - public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) { - if (entity == null) { - getCamera().setAnchor(null); - return; - } - - getCamera().setAnchor(new EntityAnchor( - getWorld().getEntityRenderable(entity) - )); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client; + +import ru.windcorp.progressia.client.comms.DefaultClientCommsListener; +import ru.windcorp.progressia.client.comms.ServerCommsChannel; +import ru.windcorp.progressia.client.graphics.world.Camera; +import ru.windcorp.progressia.client.graphics.world.EntityAnchor; +import ru.windcorp.progressia.client.graphics.world.LocalPlayer; +import ru.windcorp.progressia.client.world.WorldRender; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public class Client { + + private final WorldRender world; + private final LocalPlayer localPlayer = new LocalPlayer(this); + + private final Camera camera = new Camera((float) Math.toRadians(70)); + + private final ServerCommsChannel comms; + + public Client(WorldData world, ServerCommsChannel comms) { + this.world = new WorldRender(world, this); + this.comms = comms; + + comms.addListener(new DefaultClientCommsListener(this)); + } + + public WorldRender getWorld() { + return world; + } + + public LocalPlayer getLocalPlayer() { + return localPlayer; + } + + public boolean isReady() { + return localPlayer.hasEntity(); + } + + public Camera getCamera() { + return camera; + } + + public ServerCommsChannel getComms() { + return comms; + } + + public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) { + if (entity == null) { + getCamera().setAnchor(null); + return; + } + + getCamera().setAnchor( + new EntityAnchor( + getWorld().getEntityRenderable(entity) + ) + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java index c942b4c..e9ad7d3 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientProxy.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientProxy.java @@ -1,60 +1,64 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client; - -import ru.windcorp.progressia.Proxy; -import ru.windcorp.progressia.client.audio.AudioSystem; -import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; -import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue; -import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram; -import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader; -import ru.windcorp.progressia.client.graphics.font.Typefaces; -import ru.windcorp.progressia.client.graphics.texture.Atlases; -import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; -import ru.windcorp.progressia.client.localization.Localizer; -import ru.windcorp.progressia.common.resource.ResourceManager; -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.server.ServerState; -import ru.windcorp.progressia.test.TestContent; - -public class ClientProxy implements Proxy { - - @Override - public void initialize() { - GraphicsBackend.initialize(); - try { - RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init); - RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init); - RenderTaskQueue.waitAndInvoke(() -> Typefaces.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))); - } catch (InterruptedException e) { - throw CrashReports.report(e, "ClientProxy failed"); - } - - Localizer.getInstance().setLanguage("en-US"); - - TestContent.registerContent(); - - Atlases.loadAllAtlases(); - - AudioSystem.initialize(); - - ServerState.startServer(); - ClientState.connectToLocalServer(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client; + +import ru.windcorp.progressia.Proxy; +import ru.windcorp.progressia.client.audio.AudioSystem; +import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend; +import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue; +import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram; +import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader; +import ru.windcorp.progressia.client.graphics.font.Typefaces; +import ru.windcorp.progressia.client.graphics.texture.Atlases; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.localization.Localizer; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.server.ServerState; +import ru.windcorp.progressia.test.TestContent; + +public class ClientProxy implements Proxy { + + @Override + public void initialize() { + GraphicsBackend.initialize(); + try { + RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init); + RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init); + RenderTaskQueue.waitAndInvoke( + () -> Typefaces + .setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz"))) + ); + } catch (InterruptedException e) { + throw CrashReports.report(e, "ClientProxy failed"); + } + + Localizer.getInstance().setLanguage("en-US"); + + TestContent.registerContent(); + + Atlases.loadAllAtlases(); + + AudioSystem.initialize(); + + ServerState.startServer(); + ClientState.connectToLocalServer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/ClientState.java b/src/main/java/ru/windcorp/progressia/client/ClientState.java index f37016d..75f0f07 100644 --- a/src/main/java/ru/windcorp/progressia/client/ClientState.java +++ b/src/main/java/ru/windcorp/progressia/client/ClientState.java @@ -1,46 +1,65 @@ -package ru.windcorp.progressia.client; - -import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; -import ru.windcorp.progressia.client.graphics.GUI; -import ru.windcorp.progressia.client.graphics.world.LayerWorld; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.server.ServerState; -import ru.windcorp.progressia.test.LayerAbout; -import ru.windcorp.progressia.test.LayerTestUI; -import ru.windcorp.progressia.test.TestContent; - -public class ClientState { - - private static Client instance; - - public static Client getInstance() { - return instance; - } - - public static void setInstance(Client instance) { - ClientState.instance = instance; - } - - public static void connectToLocalServer() { - - WorldData world = new WorldData(); - - LocalServerCommsChannel channel = new LocalServerCommsChannel( - ServerState.getInstance() - ); - - Client client = new Client(world, channel); - - channel.connect(TestContent.PLAYER_LOGIN); - - setInstance(client); - - GUI.addBottomLayer(new LayerWorld(client)); - GUI.addTopLayer(new LayerTestUI()); - GUI.addTopLayer(new LayerAbout()); - - } - - private ClientState() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client; + +import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; +import ru.windcorp.progressia.client.graphics.GUI; +import ru.windcorp.progressia.client.graphics.world.LayerWorld; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.ServerState; +import ru.windcorp.progressia.test.LayerAbout; +import ru.windcorp.progressia.test.LayerTestUI; +import ru.windcorp.progressia.test.TestContent; + +public class ClientState { + + private static Client instance; + + public static Client getInstance() { + return instance; + } + + public static void setInstance(Client instance) { + ClientState.instance = instance; + } + + public static void connectToLocalServer() { + + WorldData world = new WorldData(); + + LocalServerCommsChannel channel = new LocalServerCommsChannel( + ServerState.getInstance() + ); + + Client client = new Client(world, channel); + + channel.connect(TestContent.PLAYER_LOGIN); + + setInstance(client); + + GUI.addBottomLayer(new LayerWorld(client)); + GUI.addTopLayer(new LayerTestUI()); + GUI.addTopLayer(new LayerAbout()); + + } + + private ClientState() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java index f44cb9b..bb0482d 100644 --- a/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java +++ b/src/main/java/ru/windcorp/progressia/client/ProgressiaClientMain.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client; - -import ru.windcorp.progressia.ProgressiaLauncher; - -public class ProgressiaClientMain { - - public static void main(String[] args) { - ProgressiaLauncher.launch(args, new ClientProxy()); - } - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client; + +import ru.windcorp.progressia.ProgressiaLauncher; + +public class ProgressiaClientMain { + + public static void main(String[] args) { + ProgressiaLauncher.launch(args, new ClientProxy()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java index c17f385..848e66c 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioFormat.java @@ -1,5 +1,23 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio; public enum AudioFormat { - MONO, STEREO + MONO, STEREO } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java index 3cea2b6..0078b56 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioManager.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio; import org.lwjgl.openal.*; @@ -26,8 +44,8 @@ public class AudioManager { public static void initAL() { String defaultDeviceName = alcGetString( - 0, - ALC_DEFAULT_DEVICE_SPECIFIER + 0, + ALC_DEFAULT_DEVICE_SPECIFIER ); device = alcOpenDevice(defaultDeviceName); @@ -57,27 +75,30 @@ public class AudioManager { lastSoundIndex = 0; } speaker = soundSpeakers.get(lastSoundIndex); - } while (speaker.getState() - .equals(Speaker.State.PLAYING_LOOP)); + } while ( + speaker.getState() + .equals(Speaker.State.PLAYING_LOOP) + ); return speaker; } - private static SoundType findSoundType(String soundID) throws Exception { + private static SoundType findSoundType(String soundID) throws Exception { for (SoundType s : soundsBuffer) { if (s.getId().equals(soundID)) { return s; } } - throw new Exception("ERROR: The selected sound is not loaded or" + - " not exists"); + throw new Exception( + "ERROR: The selected sound is not loaded or" + + " not exists" + ); } public static Speaker initSpeaker(String soundID) { Speaker speaker = getLastSpeaker(); try { findSoundType(soundID).initSpeaker(speaker); - } catch (Exception ex) - { + } catch (Exception ex) { throw new RuntimeException(); } return speaker; @@ -86,8 +107,7 @@ public class AudioManager { public static Speaker initMusicSpeaker(String soundID) { try { findSoundType(soundID).initSpeaker(musicSpeaker); - } catch (Exception ex) - { + } catch (Exception ex) { throw new RuntimeException(); } return musicSpeaker; @@ -103,8 +123,7 @@ public class AudioManager { public static void loadSound(String path, String id, AudioFormat format) { if (format == AudioFormat.MONO) { soundsBuffer.add(AudioReader.readAsMono(path, id)); - } else - { + } else { soundsBuffer.add(AudioReader.readAsStereo(path, id)); } } @@ -128,8 +147,7 @@ public class AudioManager { return deviceCapabilities; } - public static void createBuffers() - { + public static void createBuffers() { for (int i = 0; i < SOUNDS_NUM; ++i) { soundSpeakers.add(new Speaker()); } @@ -141,4 +159,4 @@ public class AudioManager { return alGetString(AL11.AL_VERSION); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java index 4834275..d41f6d4 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/AudioSystem.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio; public class AudioSystem { @@ -9,8 +27,10 @@ public class AudioSystem { } static void loadAudioData() { - AudioManager.loadSound("assets/sounds/block_destroy_clap.ogg", - "Progressia:BlockDestroy", - AudioFormat.MONO); + AudioManager.loadSound( + "assets/sounds/block_destroy_clap.ogg", + "Progressia:BlockDestroy", + AudioFormat.MONO + ); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/client/audio/Music.java b/src/main/java/ru/windcorp/progressia/client/audio/Music.java index 9c1d12d..9be9cc3 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/Music.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/Music.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio; import glm.vec._3.Vec3; @@ -5,66 +23,68 @@ import ru.windcorp.progressia.client.audio.backend.Speaker; import ru.windcorp.progressia.common.util.namespaces.Namespaced; public class Music extends Namespaced { - private Vec3 position = new Vec3(); - private Vec3 velocity = new Vec3(); - private float pitch = 1.0f; - private float gain = 1.0f; + private Vec3 position = new Vec3(); + private Vec3 velocity = new Vec3(); + private float pitch = 1.0f; + private float gain = 1.0f; + public Music(String id) { + super(id); + } - public Music(String id) - { - super(id); - } + public Music( + String id, + Vec3 position, + Vec3 velocity, + float pitch, + float gain + ) { + this(id); + this.position = position; + this.velocity = velocity; + this.pitch = pitch; + this.gain = gain; + } - public Music(String id, - Vec3 position, - Vec3 velocity, - float pitch, - float gain) - { - this(id); - this.position = position; - this.velocity = velocity; - this.pitch = pitch; - this.gain = gain; - } + public void play(boolean loop) { + Speaker speaker = AudioManager.initMusicSpeaker(this.getId()); + speaker.setGain(gain); + speaker.setPitch(pitch); + speaker.setPosition(position); + speaker.setVelocity(velocity); - public void play(boolean loop) - { - Speaker speaker = AudioManager.initMusicSpeaker(this.getId()); - speaker.setGain(gain); - speaker.setPitch(pitch); - speaker.setPosition(position); - speaker.setVelocity(velocity); + if (loop) { + speaker.playLoop(); + } else { + speaker.play(); + } + } - if (loop) { - speaker.playLoop(); - } else { - speaker.play(); - } - } + public void setGain(float gain) { + this.gain = gain; + } - public void setGain(float gain) { - this.gain = gain; - } + public void setPitch(float pitch) { + this.pitch = pitch; + } - public void setPitch(float pitch) { this.pitch = pitch; } + public void setVelocity(Vec3 velocity) { + this.velocity = velocity; + } - public void setVelocity(Vec3 velocity) { - this.velocity = velocity; - } + public Vec3 getPosition() { + return position; + } - public Vec3 getPosition() { return position; } + public float getGain() { + return gain; + } - public float getGain() { - return gain; - } + public Vec3 getVelocity() { + return velocity; + } - public Vec3 getVelocity() { - return velocity; - } - - public float getPitch() { - return pitch; - } + public float getPitch() { + return pitch; + } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/SoundEffect.java b/src/main/java/ru/windcorp/progressia/client/audio/SoundEffect.java index 1f77e7a..d79c8b2 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/SoundEffect.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/SoundEffect.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio; import glm.vec._3.Vec3; @@ -5,74 +23,74 @@ import ru.windcorp.progressia.client.audio.backend.Speaker; import ru.windcorp.progressia.common.util.namespaces.Namespaced; public class SoundEffect - extends Namespaced { + extends Namespaced { - private Vec3 position = new Vec3(); - private Vec3 velocity = new Vec3(); - private float pitch = 1.0f; - private float gain = 1.0f; + private Vec3 position = new Vec3(); + private Vec3 velocity = new Vec3(); + private float pitch = 1.0f; + private float gain = 1.0f; + public SoundEffect(String id) { + super(id); + } - public SoundEffect(String id) - { - super(id); - } + public SoundEffect( + String id, + Vec3 position, + Vec3 velocity, + float pitch, + float gain + ) { + this(id); + this.position = position; + this.velocity = velocity; + this.pitch = pitch; + this.gain = gain; + } - public SoundEffect(String id, - Vec3 position, - Vec3 velocity, - float pitch, - float gain) - { - this(id); - this.position = position; - this.velocity = velocity; - this.pitch = pitch; - this.gain = gain; - } + public void play(boolean loop) { + Speaker speaker = AudioManager.initSpeaker(this.getId()); + speaker.setGain(gain); + speaker.setPitch(pitch); + speaker.setPosition(position); + speaker.setVelocity(velocity); - public void play(boolean loop) - { - Speaker speaker = AudioManager.initSpeaker(this.getId()); - speaker.setGain(gain); - speaker.setPitch(pitch); - speaker.setPosition(position); - speaker.setVelocity(velocity); + if (loop) { + speaker.playLoop(); + } else { + speaker.play(); + } + } - if (loop) { - speaker.playLoop(); - } else { - speaker.play(); - } - } + public void setGain(float gain) { + this.gain = gain; + } - public void setGain(float gain) { - this.gain = gain; - } + public void setPitch(float pitch) { + this.pitch = pitch; + } - public void setPitch(float pitch) { this.pitch = pitch; } + public void setPosition(Vec3 position) { + this.position = position; + } - public void setPosition(Vec3 position) { - this.position = position; - } + public void setVelocity(Vec3 velocity) { + this.velocity = velocity; + } - public void setVelocity(Vec3 velocity) { - this.velocity = velocity; - } + public Vec3 getPosition() { + return position; + } - public Vec3 getPosition() { - return position; - } + public float getGain() { + return gain; + } - public float getGain() { - return gain; - } + public Vec3 getVelocity() { + return velocity; + } - public Vec3 getVelocity() { - return velocity; - } - - public float getPitch() { - return pitch; - } + public float getPitch() { + return pitch; + } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java index 2ea235b..2cbd1e2 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/AudioReader.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio.backend; import org.lwjgl.BufferUtils; @@ -11,7 +29,8 @@ import static org.lwjgl.openal.AL10.*; public class AudioReader { - private AudioReader() {} + private AudioReader() { + } // TODO fix converting from mono-stereo private static SoundType readAsSpecified(String path, String id, int format) { @@ -22,27 +41,31 @@ public class AudioReader { ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer); - return new SoundType(id, rawAudio, format, - rateBuffer.get(0)); + return new SoundType( + id, + rawAudio, + format, + rateBuffer.get(0) + ); } public static SoundType readAsMono(String path, String id) { return readAsSpecified(path, id, AL_FORMAT_MONO16); } - public static SoundType readAsStereo(String path,String id) { + public static SoundType readAsStereo(String path, String id) { return readAsSpecified(path, id, AL_FORMAT_STEREO16); } private static ShortBuffer decodeVorbis( - Resource dataToDecode, - IntBuffer channelsBuffer, - IntBuffer rateBuffer + Resource dataToDecode, + IntBuffer channelsBuffer, + IntBuffer rateBuffer ) { return stb_vorbis_decode_memory( - dataToDecode.readAsBytes(), - channelsBuffer, - rateBuffer + dataToDecode.readAsBytes(), + channelsBuffer, + rateBuffer ); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java index ee6cc30..8f6fe35 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/Listener.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio.backend; import glm.vec._3.Vec3; @@ -12,7 +30,8 @@ public class Listener { private static final Listener INSTANCE = new Listener(); - private Listener() {} + private Listener() { + } public static Listener getInstance() { return INSTANCE; @@ -37,7 +56,7 @@ public class Listener { if (wasInWorld) { velocity.set(camera.getLastAnchorPosition()).sub(position).div( - (float) GraphicsInterface.getFrameLength() + (float) GraphicsInterface.getFrameLength() ); } else { // If !wasInWorld, previous position is nonsence. Assume 0. @@ -72,9 +91,17 @@ public class Listener { private void applyParams() { alListener3f(AL_POSITION, position.x, position.y, position.z); alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); - alListenerfv(AL_ORIENTATION, new float[] { - oriAt.x, oriAt.y, oriAt.z, oriUp.x, oriUp.y, oriUp.z - }); + alListenerfv( + AL_ORIENTATION, + new float[] { + oriAt.x, + oriAt.y, + oriAt.z, + oriUp.x, + oriUp.y, + oriUp.z + } + ); } } diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java index f382dd2..92bd133 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/SoundType.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio.backend; import ru.windcorp.progressia.common.util.namespaces.Namespaced; @@ -12,8 +30,12 @@ public class SoundType extends Namespaced { private int format; private int audioBuffer; - public SoundType(String id, ShortBuffer rawAudio, - int format, int sampleRate) { + public SoundType( + String id, + ShortBuffer rawAudio, + int format, + int sampleRate + ) { super(id); this.rawAudio = rawAudio; this.sampleRate = sampleRate; diff --git a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java index 8685632..ea6b5ed 100644 --- a/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java +++ b/src/main/java/ru/windcorp/progressia/client/audio/backend/Speaker.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.audio.backend; import glm.vec._3.Vec3; @@ -5,147 +23,145 @@ import static org.lwjgl.openal.AL11.*; public class Speaker { - public enum State { - NOT_PLAYING, - PLAYING, - PLAYING_LOOP - } + public enum State { + NOT_PLAYING, + PLAYING, + PLAYING_LOOP + } - // Buffers - private int audioData; - private int sourceData; + // Buffers + private int audioData; + private int sourceData; - // Characteristics - private Vec3 position = new Vec3(); - private Vec3 velocity = new Vec3(); - private float pitch = 1.0f; - private float gain = 1.0f; - private State state = State.NOT_PLAYING; + // Characteristics + private Vec3 position = new Vec3(); + private Vec3 velocity = new Vec3(); + private float pitch = 1.0f; + private float gain = 1.0f; + private State state = State.NOT_PLAYING; - public Speaker() { - sourceData = alGenSources(); - } + public Speaker() { + sourceData = alGenSources(); + } - public Speaker(int audioData) { - this(); - setAudioData(audioData); - } + public Speaker(int audioData) { + this(); + setAudioData(audioData); + } - public Speaker( - int audioData, - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { - setAudioData(audioData); - setPosition(position); - setVelocity(velocity); - setPitch(pitch); - setGain(gain); - } + public Speaker( + int audioData, + Vec3 position, + Vec3 velocity, + float pitch, + float gain + ) { + setAudioData(audioData); + setPosition(position); + setVelocity(velocity); + setPitch(pitch); + setGain(gain); + } - public Speaker( - Vec3 position, - Vec3 velocity, - float pitch, - float gain - ) { - setPosition(position); - setVelocity(velocity); - setPitch(pitch); - setGain(gain); - } + public Speaker( + Vec3 position, + Vec3 velocity, + float pitch, + float gain + ) { + setPosition(position); + setVelocity(velocity); + setPitch(pitch); + setGain(gain); + } - public void play() { - alSourcePlay(sourceData); - state = State.PLAYING; - } + public void play() { + alSourcePlay(sourceData); + state = State.PLAYING; + } - public void playLoop() { - alSourcei(sourceData, AL_LOOPING, AL_TRUE); - alSourcePlay(sourceData); - state = State.PLAYING_LOOP; - } + public void playLoop() { + alSourcei(sourceData, AL_LOOPING, AL_TRUE); + alSourcePlay(sourceData); + state = State.PLAYING_LOOP; + } - public void stop() { - alSourceStop(sourceData); - if (state == State.PLAYING_LOOP) { - alSourcei(sourceData, AL_LOOPING, AL_FALSE); - } - state = State.NOT_PLAYING; - } + public void stop() { + alSourceStop(sourceData); + if (state == State.PLAYING_LOOP) { + alSourcei(sourceData, AL_LOOPING, AL_FALSE); + } + state = State.NOT_PLAYING; + } - public void pause() { - alSourcePause(sourceData); - state = State.NOT_PLAYING; - } + public void pause() { + alSourcePause(sourceData); + state = State.NOT_PLAYING; + } - public boolean isPlaying() { - final int speakerState = alGetSourcei(sourceData, AL_SOURCE_STATE); - if (speakerState == AL_PLAYING) { - return true; - } - else { - state = State.NOT_PLAYING; - return false; - } - } + public boolean isPlaying() { + final int speakerState = alGetSourcei(sourceData, AL_SOURCE_STATE); + if (speakerState == AL_PLAYING) { + return true; + } else { + state = State.NOT_PLAYING; + return false; + } + } - // GETTERS & SETTERS + // GETTERS & SETTERS - public int getAudioData() { - return audioData; - } + public int getAudioData() { + return audioData; + } - public int getSourceData() { - return sourceData; - } + public int getSourceData() { + return sourceData; + } - public void setAudioData(int audioData) { - this.audioData = audioData; - alSourcei(this.sourceData, AL_BUFFER, audioData); - } + public void setAudioData(int audioData) { + this.audioData = audioData; + alSourcei(this.sourceData, AL_BUFFER, audioData); + } - public void setPosition(Vec3 position) { - this.position = position; - alSource3f(sourceData, AL_POSITION, position.x, position.y, position.z); - } + public void setPosition(Vec3 position) { + this.position = position; + alSource3f(sourceData, AL_POSITION, position.x, position.y, position.z); + } - public Vec3 getPosition() { - return position; - } + public Vec3 getPosition() { + return position; + } - public void setVelocity(Vec3 velocity) { - alSource3f(sourceData, AL_VELOCITY, velocity.x, velocity.y, velocity.z); - this.velocity = velocity; - } + public void setVelocity(Vec3 velocity) { + alSource3f(sourceData, AL_VELOCITY, velocity.x, velocity.y, velocity.z); + this.velocity = velocity; + } - public Vec3 getVelocity() { - return velocity; - } + public Vec3 getVelocity() { + return velocity; + } - public void setPitch(float pitch) { - alSourcef(sourceData, AL_PITCH, pitch); - this.pitch = pitch; - } + public void setPitch(float pitch) { + alSourcef(sourceData, AL_PITCH, pitch); + this.pitch = pitch; + } - public float getPitch() { - return pitch; - } + public float getPitch() { + return pitch; + } - public void setGain(float gain) { - alSourcef(sourceData, AL_GAIN, gain); - this.gain = gain; - } + public void setGain(float gain) { + alSourcef(sourceData, AL_GAIN, gain); + this.gain = gain; + } - public float getGain() { - return gain; - } + public float getGain() { + return gain; + } - public State getState() - { - return state; - } + public State getState() { + return state; + } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java b/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java index f34c5bf..dad05fd 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/DefaultClientCommsListener.java @@ -1,46 +1,64 @@ -package ru.windcorp.progressia.client.comms; - -import java.io.IOException; - -import ru.windcorp.progressia.client.Client; -import ru.windcorp.progressia.common.comms.CommsListener; -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; -import ru.windcorp.progressia.common.world.PacketAffectWorld; - -// TODO refactor with no mercy -public class DefaultClientCommsListener implements CommsListener { - - private final Client client; - - public DefaultClientCommsListener(Client client) { - this.client = client; - } - - @Override - public void onPacketReceived(Packet packet) { - if (packet instanceof PacketAffectWorld) { - ((PacketAffectWorld) packet).apply( - getClient().getWorld().getData() - ); - } else if (packet instanceof PacketSetLocalPlayer) { - setLocalPlayer((PacketSetLocalPlayer) packet); - } - } - - private void setLocalPlayer(PacketSetLocalPlayer packet) { - getClient().getLocalPlayer().setEntityId(packet.getEntityId()); - } - - @Override - public void onIOError(IOException reason) { - throw CrashReports.report(reason, "An IOException has occurred in communications"); - // TODO implement - } - - public Client getClient() { - return client; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms; + +import java.io.IOException; + +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.common.comms.CommsListener; +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; +import ru.windcorp.progressia.common.world.PacketAffectWorld; + +// TODO refactor with no mercy +public class DefaultClientCommsListener implements CommsListener { + + private final Client client; + + public DefaultClientCommsListener(Client client) { + this.client = client; + } + + @Override + public void onPacketReceived(Packet packet) { + if (packet instanceof PacketAffectWorld) { + ((PacketAffectWorld) packet).apply( + getClient().getWorld().getData() + ); + } else if (packet instanceof PacketSetLocalPlayer) { + setLocalPlayer((PacketSetLocalPlayer) packet); + } + } + + private void setLocalPlayer(PacketSetLocalPlayer packet) { + getClient().getLocalPlayer().setEntityId(packet.getEntityId()); + } + + @Override + public void onIOError(IOException reason) { + throw CrashReports.report(reason, "An IOException has occurred in communications"); + // TODO implement + } + + public Client getClient() { + return client; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java b/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java index e78d8e0..3a0a1b1 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/ServerCommsChannel.java @@ -1,7 +1,25 @@ -package ru.windcorp.progressia.client.comms; - -import ru.windcorp.progressia.common.comms.CommsChannel; - -public abstract class ServerCommsChannel extends CommsChannel { - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms; + +import ru.windcorp.progressia.common.comms.CommsChannel; + +public abstract class ServerCommsChannel extends CommsChannel { + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java index 3c1ca37..88e9fa3 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTrigger.java @@ -1,11 +1,29 @@ -package ru.windcorp.progressia.client.comms.controls; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; - -public abstract class ControlTrigger extends Namespaced { - - public ControlTrigger(String id) { - super(id); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +public abstract class ControlTrigger extends Namespaced { + + public ControlTrigger(String id) { + super(id); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java index eeec0f0..b2f8de4 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerInputBased.java @@ -1,14 +1,32 @@ -package ru.windcorp.progressia.client.comms.controls; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.common.comms.controls.PacketControl; - -public abstract class ControlTriggerInputBased extends ControlTrigger { - - public ControlTriggerInputBased(String id) { - super(id); - } - - public abstract PacketControl onInputEvent(InputEvent event); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.common.comms.controls.PacketControl; + +public abstract class ControlTriggerInputBased extends ControlTrigger { + + public ControlTriggerInputBased(String id) { + super(id); + } + + public abstract PacketControl onInputEvent(InputEvent event); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java index d2a0d69..22004b8 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerLambda.java @@ -1,48 +1,67 @@ -package ru.windcorp.progressia.client.comms.controls; - -import java.util.function.BiConsumer; -import java.util.function.Predicate; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.common.comms.controls.ControlData; -import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry; -import ru.windcorp.progressia.common.comms.controls.PacketControl; -import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil; - -public class ControlTriggerLambda extends ControlTriggerInputBased { - - private final String packetId; - private final Predicate predicate; - private final BiConsumer dataWriter; - - public ControlTriggerLambda( - String id, - Predicate predicate, - BiConsumer dataWriter - ) { - super(id); - - this.packetId = NamespacedUtil.getId( - NamespacedUtil.getNamespace(id), - "ControlKeyPress" + NamespacedUtil.getName(id) - ); - - this.predicate = predicate; - this.dataWriter = dataWriter; - } - - @Override - public PacketControl onInputEvent(InputEvent event) { - if (!predicate.test(event)) return null; - - PacketControl packet = new PacketControl( - packetId, - ControlDataRegistry.getInstance().create(getId()) - ); - - dataWriter.accept(event, packet.getControl()); - - return packet; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.common.comms.controls.ControlData; +import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry; +import ru.windcorp.progressia.common.comms.controls.PacketControl; +import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil; + +public class ControlTriggerLambda extends ControlTriggerInputBased { + + private final String packetId; + private final Predicate predicate; + private final BiConsumer dataWriter; + + public ControlTriggerLambda( + String id, + Predicate predicate, + BiConsumer dataWriter + ) { + super(id); + + this.packetId = NamespacedUtil.getId( + NamespacedUtil.getNamespace(id), + "ControlKeyPress" + NamespacedUtil.getName(id) + ); + + this.predicate = predicate; + this.dataWriter = dataWriter; + } + + @Override + public PacketControl onInputEvent(InputEvent event) { + if (!predicate.test(event)) + return null; + + PacketControl packet = new PacketControl( + packetId, + ControlDataRegistry.getInstance().create(getId()) + ); + + dataWriter.accept(event, packet.getControl()); + + return packet; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java index 65f5d43..a2ec71e 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggerRegistry.java @@ -1,14 +1,31 @@ -package ru.windcorp.progressia.client.comms.controls; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class ControlTriggerRegistry extends NamespacedInstanceRegistry { - - private static final ControlTriggerRegistry INSTANCE = - new ControlTriggerRegistry(); - - public static ControlTriggerRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class ControlTriggerRegistry extends NamespacedInstanceRegistry { + + private static final ControlTriggerRegistry INSTANCE = new ControlTriggerRegistry(); + + public static ControlTriggerRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java index 5930ee6..24ca620 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/ControlTriggers.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.comms.controls; import java.util.function.BiConsumer; @@ -8,145 +26,142 @@ import ru.windcorp.progressia.client.graphics.input.InputEvent; import ru.windcorp.progressia.common.comms.controls.ControlData; public class ControlTriggers { - + public static ControlTriggerInputBased of( - String id, - BiConsumer dataWriter, - Predicate predicate + String id, + BiConsumer dataWriter, + Predicate predicate ) { return new ControlTriggerLambda(id, predicate, dataWriter); } - + public static ControlTriggerInputBased of( - String id, - Consumer dataWriter, - Predicate predicate + String id, + Consumer dataWriter, + Predicate predicate ) { return of( - id, - (input, control) -> dataWriter.accept(control), - predicate - ); - } - - public static ControlTriggerInputBased of( - String id, - Predicate predicate - ) { - return of( - id, - (input, control) -> {}, - predicate - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - BiConsumer dataWriter, - Predicate... predicates - ) { - return of( - id, - createCheckedDataWriter(inputType, dataWriter), - createCheckedCompoundPredicate(inputType, predicates) - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - Consumer dataWriter, - Predicate... predicates - ) { - return of( - id, - inputType, - (input, control) -> dataWriter.accept(control), - predicates - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Class inputType, - Predicate... predicates - ) { - return of( - id, - (input, control) -> {}, - createCheckedCompoundPredicate(inputType, predicates) - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - BiConsumer dataWriter, - Predicate... predicates - ) { - return of( - id, - InputEvent.class, - dataWriter, - predicates - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Consumer dataWriter, - Predicate... predicates - ) { - return of( - id, - (input, control) -> dataWriter.accept(control), - predicates - ); - } - - @SafeVarargs - public static ControlTriggerInputBased of( - String id, - Predicate... predicates - ) { - return of( - id, - InputEvent.class, - (input, control) -> {}, - predicates + id, + (input, control) -> dataWriter.accept(control), + predicate ); } - private static - - BiConsumer - createCheckedDataWriter( - Class inputType, - BiConsumer dataWriter + public static ControlTriggerInputBased of( + String id, + Predicate predicate + ) { + return of( + id, + (input, control) -> { + }, + predicate + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + BiConsumer dataWriter, + Predicate... predicates + ) { + return of( + id, + createCheckedDataWriter(inputType, dataWriter), + createCheckedCompoundPredicate(inputType, predicates) + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + Consumer dataWriter, + Predicate... predicates + ) { + return of( + id, + inputType, + (input, control) -> dataWriter.accept(control), + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Class inputType, + Predicate... predicates + ) { + return of( + id, + (input, control) -> { + }, + createCheckedCompoundPredicate(inputType, predicates) + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + BiConsumer dataWriter, + Predicate... predicates + ) { + return of( + id, + InputEvent.class, + dataWriter, + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Consumer dataWriter, + Predicate... predicates + ) { + return of( + id, + (input, control) -> dataWriter.accept(control), + predicates + ); + } + + @SafeVarargs + public static ControlTriggerInputBased of( + String id, + Predicate... predicates + ) { + return of( + id, + InputEvent.class, + (input, control) -> { + }, + predicates + ); + } + + private static BiConsumer createCheckedDataWriter( + Class inputType, + BiConsumer dataWriter ) { return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control); } - - private static - - Predicate - createCheckedCompoundPredicate( - Class inputType, - Predicate[] predicates + + private static Predicate createCheckedCompoundPredicate( + Class inputType, + Predicate[] predicates ) { return new CompoundCastPredicate<>(inputType, predicates); } - + private static class CompoundCastPredicate implements Predicate { - + private final Class inputType; private final Predicate[] predicates; - + public CompoundCastPredicate(Class inputType, Predicate[] predicates) { this.inputType = inputType; this.predicates = predicates; @@ -157,20 +172,21 @@ public class ControlTriggers { if (!inputType.isInstance(inputEvent)) { return false; } - + I castEvent = inputType.cast(inputEvent); - + for (Predicate predicate : predicates) { if (!predicate.test(castEvent)) { return false; } } - + return true; } - + } - private ControlTriggers() {} + private ControlTriggers() { + } } diff --git a/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java b/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java index a072e39..28b9e1b 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/controls/InputBasedControls.java @@ -1,33 +1,51 @@ -package ru.windcorp.progressia.client.comms.controls; - -import ru.windcorp.progressia.client.Client; -import ru.windcorp.progressia.client.graphics.input.bus.Input; -import ru.windcorp.progressia.common.comms.packets.Packet; - -public class InputBasedControls { - - private final Client client; - - private final ControlTriggerInputBased[] controls; - - public InputBasedControls(Client client) { - this.client = client; - - this.controls = ControlTriggerRegistry.getInstance().values().stream() - .filter(ControlTriggerInputBased.class::isInstance) - .toArray(ControlTriggerInputBased[]::new); - } - - public void handleInput(Input input) { - for (ControlTriggerInputBased c : controls) { - Packet packet = c.onInputEvent(input.getEvent()); - - if (packet != null) { - input.consume(); - client.getComms().sendPacket(packet); - break; - } - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.controls; + +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.common.comms.packets.Packet; + +public class InputBasedControls { + + private final Client client; + + private final ControlTriggerInputBased[] controls; + + public InputBasedControls(Client client) { + this.client = client; + + this.controls = ControlTriggerRegistry.getInstance().values().stream() + .filter(ControlTriggerInputBased.class::isInstance) + .toArray(ControlTriggerInputBased[]::new); + } + + public void handleInput(Input input) { + for (ControlTriggerInputBased c : controls) { + Packet packet = c.onInputEvent(input.getEvent()); + + if (packet != null) { + input.consume(); + client.getComms().sendPacket(packet); + break; + } + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java index 56e1dd6..816fba8 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalClient.java @@ -1,41 +1,59 @@ -package ru.windcorp.progressia.client.comms.localhost; - -import java.io.IOException; - -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.server.comms.ClientPlayer; - -public class LocalClient extends ClientPlayer { - - private final LocalServerCommsChannel serverComms; - - private final String login; - - public LocalClient(int id, String login, LocalServerCommsChannel serverComms) { - super(id); - setState(State.CONNECTED); - - this.serverComms = serverComms; - this.login = login; - } - - @Override - public String getLogin() { - return this.login; - } - - @Override - protected void doSendPacket(Packet packet) throws IOException { - this.serverComms.relayPacketToClient(packet); - } - - public void relayPacketToServer(Packet packet) { - onPacketReceived(packet); - } - - @Override - public void disconnect() { - // Do nothing - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.localhost; + +import java.io.IOException; + +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.server.comms.ClientPlayer; + +public class LocalClient extends ClientPlayer { + + private final LocalServerCommsChannel serverComms; + + private final String login; + + public LocalClient(int id, String login, LocalServerCommsChannel serverComms) { + super(id); + setState(State.CONNECTED); + + this.serverComms = serverComms; + this.login = login; + } + + @Override + public String getLogin() { + return this.login; + } + + @Override + protected void doSendPacket(Packet packet) throws IOException { + this.serverComms.relayPacketToClient(packet); + } + + public void relayPacketToServer(Packet packet) { + onPacketReceived(packet); + } + + @Override + public void disconnect() { + // Do nothing + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java index 0cba8d4..194a2a1 100644 --- a/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/client/comms/localhost/LocalServerCommsChannel.java @@ -1,42 +1,60 @@ -package ru.windcorp.progressia.client.comms.localhost; - -import ru.windcorp.progressia.client.comms.ServerCommsChannel; -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.server.Server; - -public class LocalServerCommsChannel extends ServerCommsChannel { - - private LocalClient localClient; - private final Server server; - - public LocalServerCommsChannel(Server server) { - this.server = server; - } - - public void connect(String login) { - setState(State.CONNECTED); - - this.localClient = new LocalClient( - server.getClientManager().grabClientId(), - login, - this - ); - - server.getClientManager().addClient(localClient); - } - - @Override - protected void doSendPacket(Packet packet) { - localClient.relayPacketToServer(packet); - } - - public void relayPacketToClient(Packet packet) { - onPacketReceived(packet); - } - - @Override - public void disconnect() { - // Do nothing - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.comms.localhost; + +import ru.windcorp.progressia.client.comms.ServerCommsChannel; +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.server.Server; + +public class LocalServerCommsChannel extends ServerCommsChannel { + + private LocalClient localClient; + private final Server server; + + public LocalServerCommsChannel(Server server) { + this.server = server; + } + + public void connect(String login) { + setState(State.CONNECTED); + + this.localClient = new LocalClient( + server.getClientManager().grabClientId(), + login, + this + ); + + server.getClientManager().addClient(localClient); + } + + @Override + protected void doSendPacket(Packet packet) { + localClient.relayPacketToServer(packet); + } + + public void relayPacketToClient(Packet packet) { + onPacketReceived(packet); + } + + @Override + public void disconnect() { + // Do nothing + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java b/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java index a465391..78aa79b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/Colors.java @@ -1,61 +1,62 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics; - -import glm.vec._4.Vec4; - -public class Colors { - - public static final Vec4 - WHITE = toVector(0xFFFFFFFF), - BLACK = toVector(0xFF000000), - - GRAY_4 = toVector(0xFF444444), - GRAY = toVector(0xFF888888), - GRAY_A = toVector(0xFFAAAAAA), - - DEBUG_RED = toVector(0xFFFF0000), - DEBUG_GREEN = toVector(0xFF00FF00), - DEBUG_BLUE = toVector(0xFF0000FF), - DEBUG_CYAN = toVector(0xFF00FFFF), - DEBUG_MAGENTA = toVector(0xFFFF00FF), - DEBUG_YELLOW = toVector(0xFFFFFF00); - - public static Vec4 toVector(int argb) { - return toVector(argb, new Vec4()); - } - - public static Vec4 multiplyRGB(Vec4 color, float multiplier) { - return color.mul(multiplier, multiplier, multiplier, 1); - } - - public static Vec4 multiplyRGB(Vec4 color, float multiplier, Vec4 output) { - if (output == null) output = new Vec4(); - return color.mul(multiplier, multiplier, multiplier, 1, output); - } - - public static Vec4 toVector(int argb, Vec4 output) { - output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha - output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red - output.y = ((argb & 0x0000FF00) >>> 8) / (float) 0xFF; // Green - output.z = ((argb & 0x000000FF) ) / (float) 0xFF; // Blue - - return output; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics; + +import glm.vec._4.Vec4; + +public class Colors { + + public static final Vec4 WHITE = toVector(0xFFFFFFFF), + BLACK = toVector(0xFF000000), + + GRAY_4 = toVector(0xFF444444), + GRAY = toVector(0xFF888888), + GRAY_A = toVector(0xFFAAAAAA), + + DEBUG_RED = toVector(0xFFFF0000), + DEBUG_GREEN = toVector(0xFF00FF00), + DEBUG_BLUE = toVector(0xFF0000FF), + DEBUG_CYAN = toVector(0xFF00FFFF), + DEBUG_MAGENTA = toVector(0xFFFF00FF), + DEBUG_YELLOW = toVector(0xFFFFFF00); + + public static Vec4 toVector(int argb) { + return toVector(argb, new Vec4()); + } + + public static Vec4 multiplyRGB(Vec4 color, float multiplier) { + return color.mul(multiplier, multiplier, multiplier, 1); + } + + public static Vec4 multiplyRGB(Vec4 color, float multiplier, Vec4 output) { + if (output == null) + output = new Vec4(); + return color.mul(multiplier, multiplier, multiplier, 1, output); + } + + public static Vec4 toVector(int argb, Vec4 output) { + output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha + output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red + output.y = ((argb & 0x0000FF00) >>> 8) / (float) 0xFF; // Green + output.z = ((argb & 0x000000FF)) / (float) 0xFF; // Blue + + return output; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java index 00148dd..fc099d2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/GUI.java @@ -1,130 +1,133 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.google.common.eventbus.Subscribe; - -import ru.windcorp.progressia.client.graphics.input.CursorEvent; -import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent; -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.client.graphics.input.KeyEvent; -import ru.windcorp.progressia.client.graphics.input.WheelEvent; -import ru.windcorp.progressia.client.graphics.input.bus.Input; - -public class GUI { - - private static final List LAYERS = Collections.synchronizedList(new ArrayList<>()); - private static final List UNMODIFIABLE_LAYERS = Collections.unmodifiableList(LAYERS); - - @FunctionalInterface - private interface LayerStackModification { - void affect(List layers); - } - - private static final List MODIFICATION_QUEUE = Collections.synchronizedList(new ArrayList<>()); - - private static class ModifiableInput extends Input { - @Override - public void initialize(InputEvent event, Target target) { - super.initialize(event, target); - } - } - - private static final ModifiableInput THE_INPUT = new ModifiableInput(); - - private GUI() {} - - public static void addBottomLayer(Layer layer) { - modify(layers -> layers.add(layer)); - } - - public static void addTopLayer(Layer layer) { - modify(layers -> layers.add(0, layer)); - } - - public static void removeLayer(Layer layer) { - modify(layers -> layers.remove(layer)); - } - - private static void modify(LayerStackModification mod) { - MODIFICATION_QUEUE.add(mod); - } - - public static List getLayers() { - return UNMODIFIABLE_LAYERS; - } - - public static void render() { - synchronized (LAYERS) { - MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS)); - MODIFICATION_QUEUE.clear(); - - for (int i = LAYERS.size() - 1; i >= 0; --i) { - LAYERS.get(i).render(); - } - } - } - - public static void invalidateEverything() { - LAYERS.forEach(Layer::invalidate); - } - - private static void dispatchInputEvent(InputEvent event) { - Input.Target target; - - if (event instanceof KeyEvent) { - if (((KeyEvent) event).isMouse()) { - target = Input.Target.HOVERED; - } else { - target = Input.Target.FOCUSED; - } - } else if (event instanceof CursorEvent) { - target = Input.Target.HOVERED; - } else if (event instanceof WheelEvent) { - target = Input.Target.HOVERED; - } else if (event instanceof FrameResizeEvent) { - return; - } else { - target = Input.Target.ALL; - } - - THE_INPUT.initialize(event, target); - LAYERS.forEach(l -> l.handleInput(THE_INPUT)); - } - - public static Object getEventSubscriber() { - return new Object() { - - @Subscribe - public void onFrameResized(FrameResizeEvent event) { - GUI.invalidateEverything(); - } - - @Subscribe - public void onInput(InputEvent event) { - dispatchInputEvent(event); - } - - }; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.google.common.eventbus.Subscribe; + +import ru.windcorp.progressia.client.graphics.input.CursorEvent; +import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent; +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.graphics.input.WheelEvent; +import ru.windcorp.progressia.client.graphics.input.bus.Input; + +public class GUI { + + private static final List LAYERS = Collections.synchronizedList(new ArrayList<>()); + private static final List UNMODIFIABLE_LAYERS = Collections.unmodifiableList(LAYERS); + + @FunctionalInterface + private interface LayerStackModification { + void affect(List layers); + } + + private static final List MODIFICATION_QUEUE = Collections + .synchronizedList(new ArrayList<>()); + + private static class ModifiableInput extends Input { + @Override + public void initialize(InputEvent event, Target target) { + super.initialize(event, target); + } + } + + private static final ModifiableInput THE_INPUT = new ModifiableInput(); + + private GUI() { + } + + public static void addBottomLayer(Layer layer) { + modify(layers -> layers.add(layer)); + } + + public static void addTopLayer(Layer layer) { + modify(layers -> layers.add(0, layer)); + } + + public static void removeLayer(Layer layer) { + modify(layers -> layers.remove(layer)); + } + + private static void modify(LayerStackModification mod) { + MODIFICATION_QUEUE.add(mod); + } + + public static List getLayers() { + return UNMODIFIABLE_LAYERS; + } + + public static void render() { + synchronized (LAYERS) { + MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS)); + MODIFICATION_QUEUE.clear(); + + for (int i = LAYERS.size() - 1; i >= 0; --i) { + LAYERS.get(i).render(); + } + } + } + + public static void invalidateEverything() { + LAYERS.forEach(Layer::invalidate); + } + + private static void dispatchInputEvent(InputEvent event) { + Input.Target target; + + if (event instanceof KeyEvent) { + if (((KeyEvent) event).isMouse()) { + target = Input.Target.HOVERED; + } else { + target = Input.Target.FOCUSED; + } + } else if (event instanceof CursorEvent) { + target = Input.Target.HOVERED; + } else if (event instanceof WheelEvent) { + target = Input.Target.HOVERED; + } else if (event instanceof FrameResizeEvent) { + return; + } else { + target = Input.Target.ALL; + } + + THE_INPUT.initialize(event, target); + LAYERS.forEach(l -> l.handleInput(THE_INPUT)); + } + + public static Object getEventSubscriber() { + return new Object() { + + @Subscribe + public void onFrameResized(FrameResizeEvent event) { + GUI.invalidateEverything(); + } + + @Subscribe + public void onInput(InputEvent event) { + dispatchInputEvent(event); + } + + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java index 66a3c67..2dbef4a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/Layer.java @@ -1,81 +1,82 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics; - -import java.util.concurrent.atomic.AtomicBoolean; - -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.input.bus.Input; - -public abstract class Layer { - - private final String name; - - private boolean hasInitialized = false; - - private final AtomicBoolean isValid = new AtomicBoolean(false); - - public Layer(String name) { - this.name = name; - } - - @Override - public String toString() { - return "Layer " + name; - } - - void render() { - GraphicsInterface.startNextLayer(); - - validate(); - - if (!hasInitialized) { - initialize(); - hasInitialized = true; - } - - doRender(); - } - - void validate() { - if (isValid.compareAndSet(false, true)) { - doValidate(); - } - } - - public void invalidate() { - isValid.set(false); - } - - protected abstract void initialize(); - - protected abstract void doValidate(); - - protected abstract void doRender(); - - protected abstract void handleInput(Input input); - - protected int getWidth() { - return GraphicsInterface.getFrameWidth(); - } - - protected int getHeight() { - return GraphicsInterface.getFrameHeight(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics; + +import java.util.concurrent.atomic.AtomicBoolean; + +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; +import ru.windcorp.progressia.client.graphics.input.bus.Input; + +public abstract class Layer { + + private final String name; + + private boolean hasInitialized = false; + + private final AtomicBoolean isValid = new AtomicBoolean(false); + + public Layer(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Layer " + name; + } + + void render() { + GraphicsInterface.startNextLayer(); + + validate(); + + if (!hasInitialized) { + initialize(); + hasInitialized = true; + } + + doRender(); + } + + void validate() { + if (isValid.compareAndSet(false, true)) { + doValidate(); + } + } + + public void invalidate() { + isValid.set(false); + } + + protected abstract void initialize(); + + protected abstract void doValidate(); + + protected abstract void doRender(); + + protected abstract void handleInput(Input input); + + protected int getWidth() { + return GraphicsInterface.getFrameWidth(); + } + + protected int getHeight() { + return GraphicsInterface.getFrameHeight(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java index f289876..61645f4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/FaceCulling.java @@ -1,27 +1,46 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.backend; import java.util.ArrayDeque; import java.util.Deque; public class FaceCulling { - + private static final Deque STACK = new ArrayDeque<>(); - + public static void push(boolean useFaceCulling) { GraphicsBackend.setFaceCulling(useFaceCulling); STACK.push(Boolean.valueOf(useFaceCulling)); } - + public static void pop() { STACK.pop(); - + if (STACK.isEmpty()) { GraphicsBackend.setFaceCulling(false); } else { GraphicsBackend.setFaceCulling(STACK.getFirst()); } } - - private FaceCulling() {} + + private FaceCulling() { + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java index cc1df99..c464d34 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsBackend.java @@ -1,127 +1,131 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import static org.lwjgl.opengl.GL11.*; - -import glm.vec._2.i.Vec2i; - -import static org.lwjgl.glfw.GLFW.*; - -public class GraphicsBackend { - - private static RenderThread renderThread; - - private static long windowHandle; - - private static final Vec2i FRAME_SIZE = new Vec2i(); - - private static double frameLength = 1.0 / 60; // TODO do something about it - private static long framesRendered = 0; - private static double frameStart = Double.NaN; - - private static boolean faceCullingEnabled = false; - - private GraphicsBackend() {} - - public static void initialize() { - startRenderThread(); - } - - private static void startRenderThread() { - renderThread = new RenderThread(); - renderThread.start(); - } - - public static Thread getRenderThread() { - return renderThread; - } - - static void setWindowHandle(long windowHandle) { - GraphicsBackend.windowHandle = windowHandle; - } - - public static long getWindowHandle() { - return windowHandle; - } - - public static int getFrameWidth() { - return FRAME_SIZE.x; - } - - public static int getFrameHeight() { - return FRAME_SIZE.y; - } - - public static Vec2i getFrameSize() { - return FRAME_SIZE; - } - - static void onFrameResized(long window, int newWidth, int newHeight) { - if (window != windowHandle) return; - - InputHandler.handleFrameResize(newWidth, newHeight); - FRAME_SIZE.set(newWidth, newHeight); - - glViewport(0, 0, newWidth, newHeight); - } - - static void startFrame() { - double now = glfwGetTime(); - - if (Double.isNaN(frameStart)) { - frameStart = now; - } else { - frameLength = now - frameStart; - frameStart = now; - } - } - - static void endFrame() { - framesRendered++; - } - - public static double getFrameStart() { - return frameStart; - } - - public static double getFrameLength() { - return frameLength; - } - - public static long getFramesRendered() { - return framesRendered; - } - - public static void startNextLayer() { - glClear(GL_DEPTH_BUFFER_BIT); - } - - public static void setFaceCulling(boolean useFaceCulling) { - if (useFaceCulling == faceCullingEnabled) return; - - if (useFaceCulling) { - glEnable(GL_CULL_FACE); - } else { - glDisable(GL_CULL_FACE); - } - - faceCullingEnabled = useFaceCulling; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import static org.lwjgl.opengl.GL11.*; + +import glm.vec._2.i.Vec2i; + +import static org.lwjgl.glfw.GLFW.*; + +public class GraphicsBackend { + + private static RenderThread renderThread; + + private static long windowHandle; + + private static final Vec2i FRAME_SIZE = new Vec2i(); + + private static double frameLength = 1.0 / 60; // TODO do something about it + private static long framesRendered = 0; + private static double frameStart = Double.NaN; + + private static boolean faceCullingEnabled = false; + + private GraphicsBackend() { + } + + public static void initialize() { + startRenderThread(); + } + + private static void startRenderThread() { + renderThread = new RenderThread(); + renderThread.start(); + } + + public static Thread getRenderThread() { + return renderThread; + } + + static void setWindowHandle(long windowHandle) { + GraphicsBackend.windowHandle = windowHandle; + } + + public static long getWindowHandle() { + return windowHandle; + } + + public static int getFrameWidth() { + return FRAME_SIZE.x; + } + + public static int getFrameHeight() { + return FRAME_SIZE.y; + } + + public static Vec2i getFrameSize() { + return FRAME_SIZE; + } + + static void onFrameResized(long window, int newWidth, int newHeight) { + if (window != windowHandle) + return; + + InputHandler.handleFrameResize(newWidth, newHeight); + FRAME_SIZE.set(newWidth, newHeight); + + glViewport(0, 0, newWidth, newHeight); + } + + static void startFrame() { + double now = glfwGetTime(); + + if (Double.isNaN(frameStart)) { + frameStart = now; + } else { + frameLength = now - frameStart; + frameStart = now; + } + } + + static void endFrame() { + framesRendered++; + } + + public static double getFrameStart() { + return frameStart; + } + + public static double getFrameLength() { + return frameLength; + } + + public static long getFramesRendered() { + return framesRendered; + } + + public static void startNextLayer() { + glClear(GL_DEPTH_BUFFER_BIT); + } + + public static void setFaceCulling(boolean useFaceCulling) { + if (useFaceCulling == faceCullingEnabled) + return; + + if (useFaceCulling) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } + + faceCullingEnabled = useFaceCulling; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java index db409cc..9af984f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/GraphicsInterface.java @@ -1,74 +1,76 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import glm.vec._2.i.Vec2i; - -public class GraphicsInterface { - - private GraphicsInterface() {} - - public static Thread getRenderThread() { - return GraphicsBackend.getRenderThread(); - } - - public static boolean isRenderThread() { - return Thread.currentThread() == getRenderThread(); - } - - public static int getFrameWidth() { - return GraphicsBackend.getFrameWidth(); - } - - public static int getFrameHeight() { - return GraphicsBackend.getFrameHeight(); - } - - public static Vec2i getFrameSize() { - return GraphicsBackend.getFrameSize(); - } - - public static float getAspectRatio() { - return ((float) getFrameWidth()) / getFrameHeight(); - } - - public static double getTime() { - return GraphicsBackend.getFrameStart(); - } - - public static double getFrameLength() { - return GraphicsBackend.getFrameLength(); - } - - public static double getFPS() { - return 1 / GraphicsBackend.getFrameLength(); - } - - public static long getFramesRendered() { - return GraphicsBackend.getFramesRendered(); - } - - public static void subscribeToInputEvents(Object listener) { - InputHandler.register(listener); - } - - public static void startNextLayer() { - GraphicsBackend.startNextLayer(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import glm.vec._2.i.Vec2i; + +public class GraphicsInterface { + + private GraphicsInterface() { + } + + public static Thread getRenderThread() { + return GraphicsBackend.getRenderThread(); + } + + public static boolean isRenderThread() { + return Thread.currentThread() == getRenderThread(); + } + + public static int getFrameWidth() { + return GraphicsBackend.getFrameWidth(); + } + + public static int getFrameHeight() { + return GraphicsBackend.getFrameHeight(); + } + + public static Vec2i getFrameSize() { + return GraphicsBackend.getFrameSize(); + } + + public static float getAspectRatio() { + return ((float) getFrameWidth()) / getFrameHeight(); + } + + public static double getTime() { + return GraphicsBackend.getFrameStart(); + } + + public static double getFrameLength() { + return GraphicsBackend.getFrameLength(); + } + + public static double getFPS() { + return 1 / GraphicsBackend.getFrameLength(); + } + + public static long getFramesRendered() { + return GraphicsBackend.getFramesRendered(); + } + + public static void subscribeToInputEvents(Object listener) { + InputHandler.register(listener); + } + + public static void startNextLayer() { + GraphicsBackend.startNextLayer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java index 47e03c3..34d936c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputHandler.java @@ -1,182 +1,183 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import org.lwjgl.glfw.GLFW; - -import com.google.common.eventbus.EventBus; - -import ru.windcorp.progressia.client.graphics.input.*; -import ru.windcorp.progressia.common.util.crash.ReportingEventBus; - -public class InputHandler { - - private static final EventBus INPUT_EVENT_BUS = ReportingEventBus.create("Input"); - - // KeyEvent - - private static class ModifiableKeyEvent extends KeyEvent { - - protected ModifiableKeyEvent() { - super(0, 0, 0, 0, Double.NaN); - } - - public void initialize(int key, int scancode, int action, int mods) { - this.setTime(GraphicsInterface.getTime()); - this.key = key; - this.scancode = scancode; - this.action = action; - this.mods = mods; - } - - } - - private static final ModifiableKeyEvent THE_KEY_EVENT = - new ModifiableKeyEvent(); - - static void handleKeyInput( - long window, - int key, - int scancode, - int action, - int mods - ) { - if (GraphicsBackend.getWindowHandle() != window) return; - THE_KEY_EVENT.initialize(key, scancode, action, mods); - dispatch(THE_KEY_EVENT); - - switch (action) { - case GLFW.GLFW_PRESS: - InputTracker.setKeyState(key, true); - break; - case GLFW.GLFW_RELEASE: - InputTracker.setKeyState(key, false); - break; - } - } - - static void handleMouseButtonInput( - long window, - int key, - int action, - int mods - ) { - handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods); - } - - // CursorMoveEvent - - private static class ModifiableCursorMoveEvent extends CursorMoveEvent { - - protected ModifiableCursorMoveEvent() { - super(0, 0, Double.NaN); - } - - public void initialize(double x, double y) { - this.setTime(GraphicsInterface.getTime()); - getNewPosition().set(x, y); - } - - } - - private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = - new ModifiableCursorMoveEvent(); - - static void handleMouseMoveInput( - long window, - double x, double y - ) { - if (GraphicsBackend.getWindowHandle() != window) return; - y = GraphicsInterface.getFrameHeight() - y; // Flip y axis - - InputTracker.initializeCursorPosition(x, y); - - THE_CURSOR_MOVE_EVENT.initialize(x, y); - dispatch(THE_CURSOR_MOVE_EVENT); - - InputTracker.getCursorPosition().set(x, y); - } - - // ScrollEvent - - private static class ModifiableWheelScrollEvent extends WheelScrollEvent { - - public ModifiableWheelScrollEvent() { - super(0, 0, Double.NaN); - } - - public void initialize(double xOffset, double yOffset) { - this.setTime(GraphicsInterface.getTime()); - this.getOffset().set(xOffset, yOffset); - } - - } - - private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = - new ModifiableWheelScrollEvent(); - - static void handleWheelScroll( - long window, - double xoffset, - double yoffset - ) { - if (GraphicsBackend.getWindowHandle() != window) return; - THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset); - dispatch(THE_WHEEL_SCROLL_EVENT); - } - - // FrameResizeEvent - - private static class ModifiableFrameResizeEvent extends FrameResizeEvent { - - public ModifiableFrameResizeEvent() { - super(0, 0, Double.NaN); - } - - public void initialize(int width, int height) { - this.setTime(GraphicsInterface.getTime()); - this.getNewSize().set(width, height); - } - - } - - private static final ModifiableFrameResizeEvent THE_FRAME_RESIZE_EVENT = - new ModifiableFrameResizeEvent(); - - /* - * NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend - */ - static void handleFrameResize( - int width, - int height - ) { - THE_FRAME_RESIZE_EVENT.initialize(width, height); - dispatch(THE_FRAME_RESIZE_EVENT); - } - - // Misc - - private static void dispatch(InputEvent event) { - INPUT_EVENT_BUS.post(event); - } - - public static void register(Object listener) { - INPUT_EVENT_BUS.register(listener); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import org.lwjgl.glfw.GLFW; + +import com.google.common.eventbus.EventBus; + +import ru.windcorp.progressia.client.graphics.input.*; +import ru.windcorp.progressia.common.util.crash.ReportingEventBus; + +public class InputHandler { + + private static final EventBus INPUT_EVENT_BUS = ReportingEventBus.create("Input"); + + // KeyEvent + + private static class ModifiableKeyEvent extends KeyEvent { + + protected ModifiableKeyEvent() { + super(0, 0, 0, 0, Double.NaN); + } + + public void initialize(int key, int scancode, int action, int mods) { + this.setTime(GraphicsInterface.getTime()); + this.key = key; + this.scancode = scancode; + this.action = action; + this.mods = mods; + } + + } + + private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent(); + + static void handleKeyInput( + long window, + int key, + int scancode, + int action, + int mods + ) { + if (GraphicsBackend.getWindowHandle() != window) + return; + THE_KEY_EVENT.initialize(key, scancode, action, mods); + dispatch(THE_KEY_EVENT); + + switch (action) { + case GLFW.GLFW_PRESS: + InputTracker.setKeyState(key, true); + break; + case GLFW.GLFW_RELEASE: + InputTracker.setKeyState(key, false); + break; + } + } + + static void handleMouseButtonInput( + long window, + int key, + int action, + int mods + ) { + handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods); + } + + // CursorMoveEvent + + private static class ModifiableCursorMoveEvent extends CursorMoveEvent { + + protected ModifiableCursorMoveEvent() { + super(0, 0, Double.NaN); + } + + public void initialize(double x, double y) { + this.setTime(GraphicsInterface.getTime()); + getNewPosition().set(x, y); + } + + } + + private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = new ModifiableCursorMoveEvent(); + + static void handleMouseMoveInput( + long window, + double x, + double y + ) { + if (GraphicsBackend.getWindowHandle() != window) + return; + y = GraphicsInterface.getFrameHeight() - y; // Flip y axis + + InputTracker.initializeCursorPosition(x, y); + + THE_CURSOR_MOVE_EVENT.initialize(x, y); + dispatch(THE_CURSOR_MOVE_EVENT); + + InputTracker.getCursorPosition().set(x, y); + } + + // ScrollEvent + + private static class ModifiableWheelScrollEvent extends WheelScrollEvent { + + public ModifiableWheelScrollEvent() { + super(0, 0, Double.NaN); + } + + public void initialize(double xOffset, double yOffset) { + this.setTime(GraphicsInterface.getTime()); + this.getOffset().set(xOffset, yOffset); + } + + } + + private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent(); + + static void handleWheelScroll( + long window, + double xoffset, + double yoffset + ) { + if (GraphicsBackend.getWindowHandle() != window) + return; + THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset); + dispatch(THE_WHEEL_SCROLL_EVENT); + } + + // FrameResizeEvent + + private static class ModifiableFrameResizeEvent extends FrameResizeEvent { + + public ModifiableFrameResizeEvent() { + super(0, 0, Double.NaN); + } + + public void initialize(int width, int height) { + this.setTime(GraphicsInterface.getTime()); + this.getNewSize().set(width, height); + } + + } + + private static final ModifiableFrameResizeEvent THE_FRAME_RESIZE_EVENT = new ModifiableFrameResizeEvent(); + + /* + * NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend + */ + static void handleFrameResize( + int width, + int height + ) { + THE_FRAME_RESIZE_EVENT.initialize(width, height); + dispatch(THE_FRAME_RESIZE_EVENT); + } + + // Misc + + private static void dispatch(InputEvent event) { + INPUT_EVENT_BUS.post(event); + } + + public static void register(Object listener) { + INPUT_EVENT_BUS.register(listener); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java index 5537df9..29dec99 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/InputTracker.java @@ -1,72 +1,75 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import glm.vec._2.d.Vec2d; -import gnu.trove.set.TIntSet; -import gnu.trove.set.hash.TIntHashSet; - -public class InputTracker { - - private static final Vec2d CURSOR_POSITION = new Vec2d( - Double.NaN, Double.NaN - ); - - private static final TIntSet PRESSED_KEYS = new TIntHashSet(256); - - private InputTracker() {} - - public static double getCursorX() { - return CURSOR_POSITION.x; - } - - public static double getCursorY() { - return CURSOR_POSITION.y; - } - - public static Vec2d getCursorPosition() { - return CURSOR_POSITION; - } - - static void initializeCursorPosition(double x, double y) { - if (Double.isNaN(CURSOR_POSITION.x)) { - CURSOR_POSITION.set(x, y); - } - } - - public static boolean isKeyPressed(int glfwCode) { - return PRESSED_KEYS.contains(glfwCode); - } - - static void setKeyState(int glfwCode, boolean isPressed) { - if (isPressed) { - PRESSED_KEYS.add(glfwCode); - } else { - PRESSED_KEYS.remove(glfwCode); - } - } - - public static TIntSet getPressedKeys() { - return PRESSED_KEYS; - } - - static void releaseEverything() { - PRESSED_KEYS.clear(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import glm.vec._2.d.Vec2d; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; + +public class InputTracker { + + private static final Vec2d CURSOR_POSITION = new Vec2d( + Double.NaN, + Double.NaN + ); + + private static final TIntSet PRESSED_KEYS = new TIntHashSet(256); + + private InputTracker() { + } + + public static double getCursorX() { + return CURSOR_POSITION.x; + } + + public static double getCursorY() { + return CURSOR_POSITION.y; + } + + public static Vec2d getCursorPosition() { + return CURSOR_POSITION; + } + + static void initializeCursorPosition(double x, double y) { + if (Double.isNaN(CURSOR_POSITION.x)) { + CURSOR_POSITION.set(x, y); + } + } + + public static boolean isKeyPressed(int glfwCode) { + return PRESSED_KEYS.contains(glfwCode); + } + + static void setKeyState(int glfwCode, boolean isPressed) { + if (isPressed) { + PRESSED_KEYS.add(glfwCode); + } else { + PRESSED_KEYS.remove(glfwCode); + } + } + + public static TIntSet getPressedKeys() { + return PRESSED_KEYS; + } + + static void releaseEverything() { + PRESSED_KEYS.clear(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java index 30f72b4..af95b19 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/LWJGLInitializer.java @@ -1,107 +1,113 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.system.MemoryUtil.*; - -import org.lwjgl.opengl.GL; - -import ru.windcorp.progressia.client.graphics.GUI; - -class LWJGLInitializer { - - private LWJGLInitializer() {} - - public static void initialize() { - checkEnvironment(); - initializeGLFW(); - createWindow(); - positionWindow(); - createWindowIcons(); - initializeOpenGL(); - setupWindowCallbacks(); - - glfwShowWindow(GraphicsBackend.getWindowHandle()); - } - - private static void checkEnvironment() { - // TODO Auto-generated method stub - } - - private static void initializeGLFW() { - // TODO Do GLFW error handling: check glfwInit, setup error callback - glfwInit(); - } - - private static void createWindow() { - glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); - glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); - glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE); - - long handle = glfwCreateWindow(900, 900, "ProgressiaTest", NULL, NULL); - - // TODO Check that handle != NULL - - GraphicsBackend.setWindowHandle(handle); - - glfwSetInputMode(handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - glfwMakeContextCurrent(handle); - glfwSwapInterval(0); - } - - private static void positionWindow() { - // TODO Auto-generated method stub - - } - - private static void createWindowIcons() { - // TODO Auto-generated method stub - - } - - private static void initializeOpenGL() { - GL.createCapabilities(); - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - RenderTaskQueue.schedule(OpenGLObjectTracker::deleteEnqueuedObjects); - } - - private static void setupWindowCallbacks() { - long handle = GraphicsBackend.getWindowHandle(); - - glfwSetFramebufferSizeCallback(handle, - GraphicsBackend::onFrameResized); - - glfwSetKeyCallback(handle, InputHandler::handleKeyInput); - glfwSetMouseButtonCallback(handle, - InputHandler::handleMouseButtonInput); - - glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput); - - glfwSetScrollCallback(handle, InputHandler::handleWheelScroll); - - GraphicsInterface.subscribeToInputEvents(GUI.getEventSubscriber()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.glfw.GLFW.*; +import static org.lwjgl.system.MemoryUtil.*; + +import org.lwjgl.opengl.GL; + +import ru.windcorp.progressia.client.graphics.GUI; + +class LWJGLInitializer { + + private LWJGLInitializer() { + } + + public static void initialize() { + checkEnvironment(); + initializeGLFW(); + createWindow(); + positionWindow(); + createWindowIcons(); + initializeOpenGL(); + setupWindowCallbacks(); + + glfwShowWindow(GraphicsBackend.getWindowHandle()); + } + + private static void checkEnvironment() { + // TODO Auto-generated method stub + } + + private static void initializeGLFW() { + // TODO Do GLFW error handling: check glfwInit, setup error callback + glfwInit(); + } + + private static void createWindow() { + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); + glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); + glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE); + + long handle = glfwCreateWindow(900, 900, "ProgressiaTest", NULL, NULL); + + // TODO Check that handle != NULL + + GraphicsBackend.setWindowHandle(handle); + + glfwSetInputMode(handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwMakeContextCurrent(handle); + glfwSwapInterval(0); + } + + private static void positionWindow() { + // TODO Auto-generated method stub + + } + + private static void createWindowIcons() { + // TODO Auto-generated method stub + + } + + private static void initializeOpenGL() { + GL.createCapabilities(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + RenderTaskQueue.schedule(OpenGLObjectTracker::deleteEnqueuedObjects); + } + + private static void setupWindowCallbacks() { + long handle = GraphicsBackend.getWindowHandle(); + + glfwSetFramebufferSizeCallback( + handle, + GraphicsBackend::onFrameResized + ); + + glfwSetKeyCallback(handle, InputHandler::handleKeyInput); + glfwSetMouseButtonCallback( + handle, + InputHandler::handleMouseButtonInput + ); + + glfwSetCursorPosCallback(handle, InputHandler::handleMouseMoveInput); + + glfwSetScrollCallback(handle, InputHandler::handleWheelScroll); + + GraphicsInterface.subscribeToInputEvents(GUI.getEventSubscriber()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java index 1910625..c467d45 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/OpenGLObjectTracker.java @@ -1,92 +1,101 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import java.lang.ref.PhantomReference; -import java.lang.ref.ReferenceQueue; -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.IntConsumer; - -public class OpenGLObjectTracker { - - public interface OpenGLDeletable { - int getHandle(); - } - - private static final Collection> TO_DELETE = new ArrayList<>(); - private static final ReferenceQueue DELETE_QUEUE = new ReferenceQueue<>(); - - public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) { - GLPhantomReference glRef = - new GLPhantomReference<>(object, DELETE_QUEUE, object.getHandle(), glDeleter); - TO_DELETE.add(glRef); - } - - public static void deleteAllObjects() { - for (GLPhantomReference glRef - : TO_DELETE - ) { - glRef.clear(); - } - } - - public static void deleteEnqueuedObjects() { - while (true) { - GLPhantomReference glRef; - glRef = (GLPhantomReference) DELETE_QUEUE.poll(); - if (glRef == null) { - break; - } else { - glRef.delete(); - } - } - } - - private static class GLPhantomReference extends PhantomReference { - - private final int referentGLhandle; - private final IntConsumer GLDeleter; - - /** - * Creates a new phantom reference that refers to the given object and - * is registered with the given queue. - * - *

It is possible to create a phantom reference with a {@code null} - * queue, but such a reference is completely useless: Its {@code get} - * method will always return {@code null} and, since it does not have a queue, - * it will never be enqueued. - * - * @param referent the object the new phantom reference will refer to - * @param q the queue with which the reference is to be registered, - * or {@code null} if registration is not required - */ - public GLPhantomReference(T referent, - ReferenceQueue q, - int referentGLhandle, - IntConsumer GLDeleter) { - super(referent, q); - this.referentGLhandle = referentGLhandle; - this.GLDeleter = GLDeleter; - } - - public void delete() { - GLDeleter.accept(referentGLhandle); - } - } -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.IntConsumer; + +public class OpenGLObjectTracker { + + public interface OpenGLDeletable { + int getHandle(); + } + + private static final Collection> TO_DELETE = new ArrayList<>(); + private static final ReferenceQueue DELETE_QUEUE = new ReferenceQueue<>(); + + public synchronized static void register(OpenGLDeletable object, IntConsumer glDeleter) { + GLPhantomReference glRef = new GLPhantomReference<>( + object, + DELETE_QUEUE, + object.getHandle(), + glDeleter + ); + TO_DELETE.add(glRef); + } + + public static void deleteAllObjects() { + for ( + GLPhantomReference glRef : TO_DELETE + ) { + glRef.clear(); + } + } + + public static void deleteEnqueuedObjects() { + while (true) { + GLPhantomReference glRef; + glRef = (GLPhantomReference) DELETE_QUEUE.poll(); + if (glRef == null) { + break; + } else { + glRef.delete(); + } + } + } + + private static class GLPhantomReference extends PhantomReference { + + private final int referentGLhandle; + private final IntConsumer GLDeleter; + + /** + * Creates a new phantom reference that refers to the given object and + * is registered with the given queue. + *

+ * It is possible to create a phantom reference with a {@code null} + * queue, but such a reference is completely useless: Its {@code get} + * method will always return {@code null} and, since it does not have a + * queue, + * it will never be enqueued. + * + * @param referent the object the new phantom reference will refer to + * @param q the queue with which the reference is to be + * registered, + * or {@code null} if registration is not required + */ + public GLPhantomReference( + T referent, + ReferenceQueue q, + int referentGLhandle, + IntConsumer GLDeleter + ) { + super(referent, q); + this.referentGLhandle = referentGLhandle; + this.GLDeleter = GLDeleter; + } + + public void delete() { + GLDeleter.accept(referentGLhandle); + } + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java index 190f128..0a1d722 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderTaskQueue.java @@ -1,54 +1,56 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import ru.windcorp.jputil.functions.ThrowingRunnable; -import ru.windcorp.progressia.common.util.TaskQueue; - -public class RenderTaskQueue { - - private static final TaskQueue HANDLER = - new TaskQueue(GraphicsInterface::isRenderThread); - - public static void schedule(Runnable task) { - HANDLER.schedule(task); - } - - public static void removeScheduled(Runnable task) { - HANDLER.removeScheduled(task); - } - - public static void invokeLater(Runnable task) { - HANDLER.invokeLater(task); - } - - public static void invokeNow(Runnable task) { - HANDLER.invokeNow(task); - } - - public static void waitAndInvoke( - ThrowingRunnable task - ) throws InterruptedException, E { - HANDLER.waitAndInvoke(task); - } - - public static void runTasks() { - HANDLER.runTasks(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import ru.windcorp.jputil.functions.ThrowingRunnable; +import ru.windcorp.progressia.common.util.TaskQueue; + +public class RenderTaskQueue { + + private static final TaskQueue HANDLER = new TaskQueue(GraphicsInterface::isRenderThread); + + public static void schedule(Runnable task) { + HANDLER.schedule(task); + } + + public static void removeScheduled(Runnable task) { + HANDLER.removeScheduled(task); + } + + public static void invokeLater(Runnable task) { + HANDLER.invokeLater(task); + } + + public static void invokeNow(Runnable task) { + HANDLER.invokeNow(task); + } + + public static void waitAndInvoke( + ThrowingRunnable task + ) + throws InterruptedException, + E { + HANDLER.waitAndInvoke(task); + } + + public static void runTasks() { + HANDLER.runTasks(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java index 93c1c8d..47d4306 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/RenderThread.java @@ -1,79 +1,80 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import static org.lwjgl.glfw.GLFW.*; -import static org.lwjgl.opengl.GL11.*; - -import ru.windcorp.progressia.client.audio.AudioManager; -import ru.windcorp.progressia.client.graphics.GUI; - -class RenderThread extends Thread { - - public RenderThread() { - super("Render"); - } - - @Override - public void run() { - LWJGLInitializer.initialize(); - mainLoop(); - freeResources(); - } - - private void mainLoop() { - while (shouldRun()) { - GraphicsBackend.startFrame(); - RenderTaskQueue.runTasks(); - render(); - waitForFrame(); - GraphicsBackend.endFrame(); - } - - System.exit(0); - } - - private void render() { - clear(); - doRender(); - glfwPollEvents(); - } - - private void clear() { - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - private void doRender() { - GUI.render(); - AudioManager.update(); - } - - private void waitForFrame() { - glfwSwapBuffers(GraphicsBackend.getWindowHandle()); - } - - private void freeResources() { - OpenGLObjectTracker.deleteAllObjects(); - } - - private boolean shouldRun() { - return !glfwWindowShouldClose(GraphicsBackend.getWindowHandle()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import static org.lwjgl.glfw.GLFW.*; +import static org.lwjgl.opengl.GL11.*; + +import ru.windcorp.progressia.client.audio.AudioManager; +import ru.windcorp.progressia.client.graphics.GUI; + +class RenderThread extends Thread { + + public RenderThread() { + super("Render"); + } + + @Override + public void run() { + LWJGLInitializer.initialize(); + mainLoop(); + freeResources(); + } + + private void mainLoop() { + while (shouldRun()) { + GraphicsBackend.startFrame(); + RenderTaskQueue.runTasks(); + render(); + waitForFrame(); + GraphicsBackend.endFrame(); + } + + System.exit(0); + } + + private void render() { + clear(); + doRender(); + glfwPollEvents(); + } + + private void clear() { + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + private void doRender() { + GUI.render(); + AudioManager.update(); + } + + private void waitForFrame() { + glfwSwapBuffers(GraphicsBackend.getWindowHandle()); + } + + private void freeResources() { + OpenGLObjectTracker.deleteAllObjects(); + } + + private boolean shouldRun() { + return !glfwWindowShouldClose(GraphicsBackend.getWindowHandle()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java index 099f14c..8a526c1 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/Usage.java @@ -1,38 +1,39 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import static org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW; -import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; -import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW; - -public enum Usage { // TODO add _COPY and _READ, pref. as another enum - STATIC(GL_STATIC_DRAW), - DYNAMIC(GL_DYNAMIC_DRAW), - STREAM(GL_STREAM_DRAW); - - private final int glCode; - - private Usage(int glCode) { - this.glCode = glCode; - } - - public int getGlCode() { - return glCode; - } -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import static org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW; +import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW; +import static org.lwjgl.opengl.GL15.GL_STREAM_DRAW; + +public enum Usage { // TODO add _COPY and _READ, pref. as another enum + STATIC(GL_STATIC_DRAW), + DYNAMIC(GL_DYNAMIC_DRAW), + STREAM(GL_STREAM_DRAW); + + private final int glCode; + + private Usage(int glCode) { + this.glCode = glCode; + } + + public int getGlCode() { + return glCode; + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java index ce301b7..7fe23f7 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/VertexBufferObject.java @@ -1,199 +1,200 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend; - -import static org.lwjgl.opengl.GL20.*; - -import java.nio.*; - -import org.lwjgl.opengl.GL20; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; - -public class VertexBufferObject implements OpenGLDeletable { - - public static enum BindTarget { - ARRAY(GL_ARRAY_BUFFER), - ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER); - - private final int glCode; - - private BindTarget(int glCode) { - this.glCode = glCode; - } - - public int getGlCode() { - return glCode; - } - } - - private final int handle; - - private long length = 0; - private final Usage usage; - - public VertexBufferObject(Usage usage) { - handle = glGenBuffers(); - OpenGLObjectTracker.register(this, GL20::glDeleteBuffers); - - this.usage = usage; - } - - public void setData(ByteBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining(); - } - - public void setData(double[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.length * Double.BYTES; - } - - public void setData(DoubleBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining() * Double.BYTES; - } - - public void setData(float[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.length * Float.BYTES; - } - - public void setData(FloatBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining() * Float.BYTES; - } - - public void setData(int[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.length * Integer.BYTES; - } - - public void setData(IntBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining() * Integer.BYTES; - } - - public void setData(long[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.length * Long.BYTES; - } - - public void setData(LongBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining() * Long.BYTES; - } - - public void setData(short[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.length * Short.BYTES; - } - - public void setData(ShortBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); - length = data.remaining() * Short.BYTES; - } - - public void initData(long length) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferData(GL_ARRAY_BUFFER, length, usage.getGlCode()); - this.length = length; - } - - public void setData(int offset, ByteBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, double[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, DoubleBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, float[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, FloatBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, int[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, IntBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, long[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, LongBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, short[] data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void setData(int offset, ShortBuffer data) { - glBindBuffer(GL_ARRAY_BUFFER, handle); - glBufferSubData(GL_ARRAY_BUFFER, offset, data); - } - - public void bind(BindTarget target) { - glBindBuffer(target.getGlCode(), handle); - } - - public long getLength() { - return length; - } - - public Usage getUsage() { - return usage; - } - - @Override - public int getHandle() { - return handle; - } -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend; + +import static org.lwjgl.opengl.GL20.*; + +import java.nio.*; + +import org.lwjgl.opengl.GL20; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; + +public class VertexBufferObject implements OpenGLDeletable { + + public static enum BindTarget { + ARRAY(GL_ARRAY_BUFFER), + ELEMENT_ARRAY(GL_ELEMENT_ARRAY_BUFFER); + + private final int glCode; + + private BindTarget(int glCode) { + this.glCode = glCode; + } + + public int getGlCode() { + return glCode; + } + } + + private final int handle; + + private long length = 0; + private final Usage usage; + + public VertexBufferObject(Usage usage) { + handle = glGenBuffers(); + OpenGLObjectTracker.register(this, GL20::glDeleteBuffers); + + this.usage = usage; + } + + public void setData(ByteBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining(); + } + + public void setData(double[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.length * Double.BYTES; + } + + public void setData(DoubleBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining() * Double.BYTES; + } + + public void setData(float[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.length * Float.BYTES; + } + + public void setData(FloatBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining() * Float.BYTES; + } + + public void setData(int[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.length * Integer.BYTES; + } + + public void setData(IntBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining() * Integer.BYTES; + } + + public void setData(long[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.length * Long.BYTES; + } + + public void setData(LongBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining() * Long.BYTES; + } + + public void setData(short[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.length * Short.BYTES; + } + + public void setData(ShortBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, data, usage.getGlCode()); + length = data.remaining() * Short.BYTES; + } + + public void initData(long length) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferData(GL_ARRAY_BUFFER, length, usage.getGlCode()); + this.length = length; + } + + public void setData(int offset, ByteBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, double[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, DoubleBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, float[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, FloatBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, int[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, IntBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, long[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, LongBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, short[] data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void setData(int offset, ShortBuffer data) { + glBindBuffer(GL_ARRAY_BUFFER, handle); + glBufferSubData(GL_ARRAY_BUFFER, offset, data); + } + + public void bind(BindTarget target) { + glBindBuffer(target.getGlCode(), handle); + } + + public long getLength() { + return length; + } + + public Usage getUsage() { + return usage; + } + + @Override + public int getHandle() { + return handle; + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java index 9030228..63fb4c9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/CombinedShader.java @@ -1,93 +1,95 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders; - -import ru.windcorp.progressia.common.resource.Resource; - -public class CombinedShader extends Shader { - - public CombinedShader(String... resources) { - super(getTypeOf(resources), combine(resources)); - } - - private static ShaderType getTypeOf(String[] resources) { - ShaderType first = ShaderType.guessByResourceName(resources[0]); - - for (int i = 1; i < resources.length; ++i) { - if (ShaderType.guessByResourceName(resources[i]) != first) { - throw new IllegalArgumentException( - "Deduced shader types of " - + resources[0] - + " and " - + resources[i] - + " differ" - ); - } - } - - return first; - } - - private static String combine(String[] resources) { - StringBuilder accumulator = new StringBuilder("#version 120\n"); - - for (String resourceName : resources) { - Resource resource = getShaderResource(resourceName); - - accumulator.append("\n// START " + resourceName); - accumulator.append(stripVersionAnnotations(resource)); - accumulator.append('\n'); - } - - return accumulator.toString(); - } - - private static String stripVersionAnnotations(Resource resource) { - String contents = resource.readAsString(); - - int versionIndex; - for (versionIndex = 0; versionIndex < contents.length(); ++versionIndex) - { - if (!Character.isWhitespace(contents.codePointAt(versionIndex))) - break; - } - - if (versionIndex < contents.length()) { - if (contents.codePointAt(versionIndex) == '#') { - final String versionAnnotation = "#version "; - - if (contents.regionMatches( - versionIndex, - versionAnnotation, - 0, - versionAnnotation.length() - )) { - contents = contents.substring( - versionIndex - + versionAnnotation.length() - + "120".length() - ); - } - - } - } - - return contents; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders; + +import ru.windcorp.progressia.common.resource.Resource; + +public class CombinedShader extends Shader { + + public CombinedShader(String... resources) { + super(getTypeOf(resources), combine(resources)); + } + + private static ShaderType getTypeOf(String[] resources) { + ShaderType first = ShaderType.guessByResourceName(resources[0]); + + for (int i = 1; i < resources.length; ++i) { + if (ShaderType.guessByResourceName(resources[i]) != first) { + throw new IllegalArgumentException( + "Deduced shader types of " + + resources[0] + + " and " + + resources[i] + + " differ" + ); + } + } + + return first; + } + + private static String combine(String[] resources) { + StringBuilder accumulator = new StringBuilder("#version 120\n"); + + for (String resourceName : resources) { + Resource resource = getShaderResource(resourceName); + + accumulator.append("\n// START " + resourceName); + accumulator.append(stripVersionAnnotations(resource)); + accumulator.append('\n'); + } + + return accumulator.toString(); + } + + private static String stripVersionAnnotations(Resource resource) { + String contents = resource.readAsString(); + + int versionIndex; + for (versionIndex = 0; versionIndex < contents.length(); ++versionIndex) { + if (!Character.isWhitespace(contents.codePointAt(versionIndex))) + break; + } + + if (versionIndex < contents.length()) { + if (contents.codePointAt(versionIndex) == '#') { + final String versionAnnotation = "#version "; + + if ( + contents.regionMatches( + versionIndex, + versionAnnotation, + 0, + versionAnnotation.length() + ) + ) { + contents = contents.substring( + versionIndex + + versionAnnotation.length() + + "120".length() + ); + } + + } + } + + return contents; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java index 2a62cd8..98d512e 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Program.java @@ -1,63 +1,66 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL20.*; - -import org.lwjgl.opengl.GL20; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; -import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.Attribute; -import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Program implements OpenGLDeletable { - - private int handle; - - public Program(Shader vertexShader, Shader fragmentShader) { - handle = glCreateProgram(); - OpenGLObjectTracker.register(this, GL20::glDeleteProgram); - - glAttachShader(handle, vertexShader.getHandle()); - glAttachShader(handle, fragmentShader.getHandle()); - - glLinkProgram(handle); - - if (glGetProgrami(handle, GL_LINK_STATUS) == GL_FALSE) { - throw CrashReports.report(null, "Bad program:\n%s", glGetProgramInfoLog(handle)); - } - } - - public Attribute getAttribute(String name) { - return new Attribute(glGetAttribLocation(handle, name), this); - } - - public Uniform getUniform(String name) { - return new Uniform(glGetUniformLocation(handle, name), this); - } - - public void use() { - glUseProgram(handle); - } - - @Override - public int getHandle() { return handle; } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL20.*; + +import org.lwjgl.opengl.GL20; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; +import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.Attribute; +import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Program implements OpenGLDeletable { + + private int handle; + + public Program(Shader vertexShader, Shader fragmentShader) { + handle = glCreateProgram(); + OpenGLObjectTracker.register(this, GL20::glDeleteProgram); + + glAttachShader(handle, vertexShader.getHandle()); + glAttachShader(handle, fragmentShader.getHandle()); + + glLinkProgram(handle); + + if (glGetProgrami(handle, GL_LINK_STATUS) == GL_FALSE) { + throw CrashReports.report(null, "Bad program:\n%s", glGetProgramInfoLog(handle)); + } + } + + public Attribute getAttribute(String name) { + return new Attribute(glGetAttribLocation(handle, name), this); + } + + public Uniform getUniform(String name) { + return new Uniform(glGetUniformLocation(handle, name), this); + } + + public void use() { + glUseProgram(handle); + } + + @Override + public int getHandle() { + return handle; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java index a34c30a..714fd1a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/Shader.java @@ -1,103 +1,108 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL20.*; - -import java.util.Locale; - -import org.lwjgl.opengl.GL20; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; -import ru.windcorp.progressia.common.resource.Resource; -import ru.windcorp.progressia.common.resource.ResourceManager; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Shader implements OpenGLDeletable { - - public static enum ShaderType { - VERTEX(GL_VERTEX_SHADER), FRAGMENT(GL_FRAGMENT_SHADER); - - private final int glCode; - - private ShaderType(int glCode) { - this.glCode = glCode; - } - - public int getGlCode() { - return glCode; - } - - public static ShaderType guessByResourceName(String resource) { - resource = resource.toLowerCase(Locale.ENGLISH); - - if (resource.contains("vertex")) return VERTEX; - if (resource.contains("fragment")) return FRAGMENT; - if (resource.contains("vsh")) return VERTEX; - if (resource.contains("fsh")) return FRAGMENT; - - throw new IllegalArgumentException( - "Cannot deduce shader type from resource name \"" + - resource + "\"" - ); - } - } - - private static final String SHADER_ASSETS_PREFIX = "assets/shaders/"; - - protected static Resource getShaderResource(String name) { - return ResourceManager.getResource(SHADER_ASSETS_PREFIX + name); - } - - private final int handle; - private final ShaderType type; - - public Shader(ShaderType type, String source) { - handle = glCreateShader(type.getGlCode()); - OpenGLObjectTracker.register(this, GL20::glDeleteShader); - - this.type = type; - - glShaderSource(handle, source); - glCompileShader(handle); - - if (glGetShaderi(handle, GL_COMPILE_STATUS) == GL_FALSE) { - System.out.println("***************** ERROR ******************"); - System.out.println(source); - throw CrashReports.report(null, "Bad shader:\n %s", glGetShaderInfoLog(handle)); - } - } - - public Shader(String resource) { - this( - ShaderType.guessByResourceName(resource), - getShaderResource(resource).readAsString() - ); - } - - @Override - public int getHandle() { - return handle; - } - - public ShaderType getType() { - return type; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL20.*; + +import java.util.Locale; + +import org.lwjgl.opengl.GL20; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; +import ru.windcorp.progressia.common.resource.Resource; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Shader implements OpenGLDeletable { + + public static enum ShaderType { + VERTEX(GL_VERTEX_SHADER), FRAGMENT(GL_FRAGMENT_SHADER); + + private final int glCode; + + private ShaderType(int glCode) { + this.glCode = glCode; + } + + public int getGlCode() { + return glCode; + } + + public static ShaderType guessByResourceName(String resource) { + resource = resource.toLowerCase(Locale.ENGLISH); + + if (resource.contains("vertex")) + return VERTEX; + if (resource.contains("fragment")) + return FRAGMENT; + if (resource.contains("vsh")) + return VERTEX; + if (resource.contains("fsh")) + return FRAGMENT; + + throw new IllegalArgumentException( + "Cannot deduce shader type from resource name \"" + + resource + "\"" + ); + } + } + + private static final String SHADER_ASSETS_PREFIX = "assets/shaders/"; + + protected static Resource getShaderResource(String name) { + return ResourceManager.getResource(SHADER_ASSETS_PREFIX + name); + } + + private final int handle; + private final ShaderType type; + + public Shader(ShaderType type, String source) { + handle = glCreateShader(type.getGlCode()); + OpenGLObjectTracker.register(this, GL20::glDeleteShader); + + this.type = type; + + glShaderSource(handle, source); + glCompileShader(handle); + + if (glGetShaderi(handle, GL_COMPILE_STATUS) == GL_FALSE) { + System.out.println("***************** ERROR ******************"); + System.out.println(source); + throw CrashReports.report(null, "Bad shader:\n %s", glGetShaderInfoLog(handle)); + } + } + + public Shader(String resource) { + this( + ShaderType.guessByResourceName(resource), + getShaderResource(resource).readAsString() + ); + } + + @Override + public int getHandle() { + return handle; + } + + public ShaderType getType() { + return type; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java index 09060dd..d56210a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/Attribute.java @@ -1,49 +1,50 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; - -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Attribute { - - protected final int handle; - private final Program program; - - public Attribute(int handle, Program program) { - if (handle < 0) { - throw CrashReports.report(null, "Bad handle: %d", handle); - } - - this.handle = handle; - this.program = program; - } - - public int getHandle() { - return handle; - } - - public Program getProgram() { - return program; - } - - public AttributeVertexArray asVertexArray() { - return new AttributeVertexArray(handle, program); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; + +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Attribute { + + protected final int handle; + private final Program program; + + public Attribute(int handle, Program program) { + if (handle < 0) { + throw CrashReports.report(null, "Bad handle: %d", handle); + } + + this.handle = handle; + this.program = program; + } + + public int getHandle() { + return handle; + } + + public Program getProgram() { + return program; + } + + public AttributeVertexArray asVertexArray() { + return new AttributeVertexArray(handle, program); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java index cfae284..2ca192d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/attributes/AttributeVertexArray.java @@ -1,114 +1,154 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL20.*; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; - -import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class AttributeVertexArray extends Attribute { - - private boolean isEnabled = false; - - public AttributeVertexArray(int handle, Program program) { - super(handle, program); - } - - public void enable() { - if (!isEnabled) { - glEnableVertexAttribArray(handle); - isEnabled = true; - } - } - - public void disable() { - if (isEnabled) { - glDisableVertexAttribArray(handle); - isEnabled = false; - } - } - - public void set( - int size, boolean normalized, int stride, - ByteBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, GL_BYTE, normalized, stride, pointer - ); - } - - public void set( - int size, boolean normalized, int stride, - FloatBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, GL_FLOAT, normalized, stride, pointer - ); - } - - public void set( - int size, boolean normalized, int stride, - IntBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, GL_INT, normalized, stride, pointer - ); - } - - public void set( - int size, boolean normalized, int stride, - ShortBuffer pointer - ) { - glVertexAttribPointer( - handle, - size, GL_SHORT, normalized, stride, pointer - ); - } - - public void set( - int size, int type, boolean normalized, int stride, - long pointer - ) { - glVertexAttribPointer( - handle, - size, type, normalized, stride, pointer - ); - } - - public void set( - int size, int type, boolean normalized, int stride, - VertexBufferObject vbo, long offset - ) { - glBindBuffer(GL_ARRAY_BUFFER, vbo.getHandle()); - glVertexAttribPointer( - handle, - size, type, normalized, stride, offset - ); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.attributes; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL20.*; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; + +import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class AttributeVertexArray extends Attribute { + + private boolean isEnabled = false; + + public AttributeVertexArray(int handle, Program program) { + super(handle, program); + } + + public void enable() { + if (!isEnabled) { + glEnableVertexAttribArray(handle); + isEnabled = true; + } + } + + public void disable() { + if (isEnabled) { + glDisableVertexAttribArray(handle); + isEnabled = false; + } + } + + public void set( + int size, + boolean normalized, + int stride, + ByteBuffer pointer + ) { + glVertexAttribPointer( + handle, + size, + GL_BYTE, + normalized, + stride, + pointer + ); + } + + public void set( + int size, + boolean normalized, + int stride, + FloatBuffer pointer + ) { + glVertexAttribPointer( + handle, + size, + GL_FLOAT, + normalized, + stride, + pointer + ); + } + + public void set( + int size, + boolean normalized, + int stride, + IntBuffer pointer + ) { + glVertexAttribPointer( + handle, + size, + GL_INT, + normalized, + stride, + pointer + ); + } + + public void set( + int size, + boolean normalized, + int stride, + ShortBuffer pointer + ) { + glVertexAttribPointer( + handle, + size, + GL_SHORT, + normalized, + stride, + pointer + ); + } + + public void set( + int size, + int type, + boolean normalized, + int stride, + long pointer + ) { + glVertexAttribPointer( + handle, + size, + type, + normalized, + stride, + pointer + ); + } + + public void set( + int size, + int type, + boolean normalized, + int stride, + VertexBufferObject vbo, + long offset + ) { + glBindBuffer(GL_ARRAY_BUFFER, vbo.getHandle()); + glVertexAttribPointer( + handle, + size, + type, + normalized, + stride, + offset + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java index 3a28983..8de5f1c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform.java @@ -1,89 +1,90 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Uniform { - - protected final int handle; - private final Program program; - - public Uniform(int handle, Program program) { - if (handle < 0) { - throw CrashReports.report(null, "Bad handle: %d", handle); - } - - this.handle = handle; - this.program = program; - } - - public int getHandle() { - return handle; - } - - public Program getProgram() { - return program; - } - - public Uniform1Float as1Float() { - return new Uniform1Float(handle, program); - } - - public Uniform1Int as1Int() { - return new Uniform1Int(handle, program); - } - - public Uniform2Float as2Float() { - return new Uniform2Float(handle, program); - } - - public Uniform2Int as2Int() { - return new Uniform2Int(handle, program); - } - - public Uniform3Float as3Float() { - return new Uniform3Float(handle, program); - } - - public Uniform3Int as3Int() { - return new Uniform3Int(handle, program); - } - - public Uniform4Float as4Float() { - return new Uniform4Float(handle, program); - } - - public Uniform4Int as4Int() { - return new Uniform4Int(handle, program); - } - - public Uniform2Matrix as2Matrix() { - return new Uniform2Matrix(handle, program); - } - - public Uniform3Matrix as3Matrix() { - return new Uniform3Matrix(handle, program); - } - - public Uniform4Matrix as4Matrix() { - return new Uniform4Matrix(handle, program); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Uniform { + + protected final int handle; + private final Program program; + + public Uniform(int handle, Program program) { + if (handle < 0) { + throw CrashReports.report(null, "Bad handle: %d", handle); + } + + this.handle = handle; + this.program = program; + } + + public int getHandle() { + return handle; + } + + public Program getProgram() { + return program; + } + + public Uniform1Float as1Float() { + return new Uniform1Float(handle, program); + } + + public Uniform1Int as1Int() { + return new Uniform1Int(handle, program); + } + + public Uniform2Float as2Float() { + return new Uniform2Float(handle, program); + } + + public Uniform2Int as2Int() { + return new Uniform2Int(handle, program); + } + + public Uniform3Float as3Float() { + return new Uniform3Float(handle, program); + } + + public Uniform3Int as3Int() { + return new Uniform3Int(handle, program); + } + + public Uniform4Float as4Float() { + return new Uniform4Float(handle, program); + } + + public Uniform4Int as4Int() { + return new Uniform4Int(handle, program); + } + + public Uniform2Matrix as2Matrix() { + return new Uniform2Matrix(handle, program); + } + + public Uniform3Matrix as3Matrix() { + return new Uniform3Matrix(handle, program); + } + + public Uniform4Matrix as4Matrix() { + return new Uniform4Matrix(handle, program); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java index 39332ed..6e2a62b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Float.java @@ -1,43 +1,44 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform1Float extends Uniform { - - public Uniform1Float(int handle, Program program) { - super(handle, program); - } - - public void set(float value) { - glUniform1f(handle, value); - } - - public void set(float[] value) { - glUniform1fv(handle, value); - } - - public void set(FloatBuffer value) { - glUniform1fv(handle, value); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform1Float extends Uniform { + + public Uniform1Float(int handle, Program program) { + super(handle, program); + } + + public void set(float value) { + glUniform1f(handle, value); + } + + public void set(float[] value) { + glUniform1fv(handle, value); + } + + public void set(FloatBuffer value) { + glUniform1fv(handle, value); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java index d9f9402..79d14a0 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform1Int.java @@ -1,43 +1,44 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.IntBuffer; - -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform1Int extends Uniform { - - public Uniform1Int(int handle, Program program) { - super(handle, program); - } - - public void set(int value) { - glUniform1i(handle, value); - } - - public void set(int[] value) { - glUniform1iv(handle, value); - } - - public void set(IntBuffer value) { - glUniform1iv(handle, value); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.IntBuffer; + +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform1Int extends Uniform { + + public Uniform1Int(int handle, Program program) { + super(handle, program); + } + + public void set(int value) { + glUniform1i(handle, value); + } + + public void set(int[] value) { + glUniform1iv(handle, value); + } + + public void set(IntBuffer value) { + glUniform1iv(handle, value); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java index 39be705..166f47b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Float.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import glm.vec._2.Vec2; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform2Float extends Uniform { - - public Uniform2Float(int handle, Program program) { - super(handle, program); - } - - public void set(float x, float y) { - glUniform2f(handle, x, y); - } - - public void set(float[] value) { - glUniform2fv(handle, value); - } - - public void set(FloatBuffer value) { - glUniform2fv(handle, value); - } - - public void set(Vec2 value) { - glUniform2f(handle, value.x, value.y); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import glm.vec._2.Vec2; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform2Float extends Uniform { + + public Uniform2Float(int handle, Program program) { + super(handle, program); + } + + public void set(float x, float y) { + glUniform2f(handle, x, y); + } + + public void set(float[] value) { + glUniform2fv(handle, value); + } + + public void set(FloatBuffer value) { + glUniform2fv(handle, value); + } + + public void set(Vec2 value) { + glUniform2f(handle, value.x, value.y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java index 1e0ab7f..d8dde9b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Int.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.IntBuffer; - -import glm.vec._2.i.Vec2i; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform2Int extends Uniform { - - public Uniform2Int(int handle, Program program) { - super(handle, program); - } - - public void set(int x, int y) { - glUniform2i(handle, x, y); - } - - public void set(int[] value) { - glUniform2iv(handle, value); - } - - public void set(IntBuffer value) { - glUniform2iv(handle, value); - } - - public void set(Vec2i value) { - glUniform2i(handle, value.x, value.y); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.IntBuffer; + +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform2Int extends Uniform { + + public Uniform2Int(int handle, Program program) { + super(handle, program); + } + + public void set(int x, int y) { + glUniform2i(handle, x, y); + } + + public void set(int[] value) { + glUniform2iv(handle, value); + } + + public void set(IntBuffer value) { + glUniform2iv(handle, value); + } + + public void set(Vec2i value) { + glUniform2i(handle, value.x, value.y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java index 5635b4f..6bbc3a9 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform2Matrix.java @@ -1,39 +1,40 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform2Matrix extends Uniform { - - public Uniform2Matrix(int handle, Program program) { - super(handle, program); - } - - public void set(float[] value) { - glUniformMatrix2fv(handle, false, value); - } - - public void set(FloatBuffer value) { - glUniformMatrix2fv(handle, false, value); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform2Matrix extends Uniform { + + public Uniform2Matrix(int handle, Program program) { + super(handle, program); + } + + public void set(float[] value) { + glUniformMatrix2fv(handle, false, value); + } + + public void set(FloatBuffer value) { + glUniformMatrix2fv(handle, false, value); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java index b2f5132..21ea95b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Float.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform3Float extends Uniform { - - public Uniform3Float(int handle, Program program) { - super(handle, program); - } - - public void set(float x, float y, float z) { - glUniform3f(handle, x, y, z); - } - - public void set(float[] value) { - glUniform3fv(handle, value); - } - - public void set(FloatBuffer value) { - glUniform3fv(handle, value); - } - - public void set(Vec3 value) { - glUniform3f(handle, value.x, value.y, value.z); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform3Float extends Uniform { + + public Uniform3Float(int handle, Program program) { + super(handle, program); + } + + public void set(float x, float y, float z) { + glUniform3f(handle, x, y, z); + } + + public void set(float[] value) { + glUniform3fv(handle, value); + } + + public void set(FloatBuffer value) { + glUniform3fv(handle, value); + } + + public void set(Vec3 value) { + glUniform3f(handle, value.x, value.y, value.z); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java index 2113324..1eb4690 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Int.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.IntBuffer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform3Int extends Uniform { - - public Uniform3Int(int handle, Program program) { - super(handle, program); - } - - public void set(int x, int y, int z) { - glUniform3i(handle, x, y, z); - } - - public void set(int[] value) { - glUniform3iv(handle, value); - } - - public void set(IntBuffer value) { - glUniform3iv(handle, value); - } - - public void set(Vec3i value) { - glUniform3i(handle, value.x, value.y, value.z); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.IntBuffer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform3Int extends Uniform { + + public Uniform3Int(int handle, Program program) { + super(handle, program); + } + + public void set(int x, int y, int z) { + glUniform3i(handle, x, y, z); + } + + public void set(int[] value) { + glUniform3iv(handle, value); + } + + public void set(IntBuffer value) { + glUniform3iv(handle, value); + } + + public void set(Vec3i value) { + glUniform3i(handle, value.x, value.y, value.z); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java index 97d29fd..255fe2a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform3Matrix.java @@ -1,46 +1,47 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import glm.mat._3.Mat3; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform3Matrix extends Uniform { - - public Uniform3Matrix(int handle, Program program) { - super(handle, program); - } - - public void set(float[] value) { - glUniformMatrix3fv(handle, false, value); - } - - public void set(FloatBuffer value) { - glUniformMatrix3fv(handle, false, value); - } - - private static final float[] BUFFER = new float[3 * 3]; - - public void set(Mat3 value) { - glUniformMatrix3fv(handle, false, value.toFa(BUFFER)); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import glm.mat._3.Mat3; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform3Matrix extends Uniform { + + public Uniform3Matrix(int handle, Program program) { + super(handle, program); + } + + public void set(float[] value) { + glUniformMatrix3fv(handle, false, value); + } + + public void set(FloatBuffer value) { + glUniformMatrix3fv(handle, false, value); + } + + private static final float[] BUFFER = new float[3 * 3]; + + public void set(Mat3 value) { + glUniformMatrix3fv(handle, false, value.toFa(BUFFER)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java index 389be80..daaab36 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Float.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform4Float extends Uniform { - - public Uniform4Float(int handle, Program program) { - super(handle, program); - } - - public void set(float x, float y, float z, float w) { - glUniform4f(handle, x, y, z, w); - } - - public void set(float[] value) { - glUniform4fv(handle, value); - } - - public void set(FloatBuffer value) { - glUniform4fv(handle, value); - } - - public void set(Vec4 value) { - glUniform4f(handle, value.x, value.y, value.z, value.w); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform4Float extends Uniform { + + public Uniform4Float(int handle, Program program) { + super(handle, program); + } + + public void set(float x, float y, float z, float w) { + glUniform4f(handle, x, y, z, w); + } + + public void set(float[] value) { + glUniform4fv(handle, value); + } + + public void set(FloatBuffer value) { + glUniform4fv(handle, value); + } + + public void set(Vec4 value) { + glUniform4f(handle, value.x, value.y, value.z, value.w); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java index 2f55876..6c2e760 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Int.java @@ -1,48 +1,49 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.IntBuffer; - -import glm.vec._4.i.Vec4i; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform4Int extends Uniform { - - public Uniform4Int(int handle, Program program) { - super(handle, program); - } - - public void set(int x, int y, int z, int w) { - glUniform4i(handle, x, y, z, w); - } - - public void set(int[] value) { - glUniform4iv(handle, value); - } - - public void set(IntBuffer value) { - glUniform4iv(handle, value); - } - - public void set(Vec4i value) { - glUniform4i(handle, value.x, value.y, value.z, value.w); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.IntBuffer; + +import glm.vec._4.i.Vec4i; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform4Int extends Uniform { + + public Uniform4Int(int handle, Program program) { + super(handle, program); + } + + public void set(int x, int y, int z, int w) { + glUniform4i(handle, x, y, z, w); + } + + public void set(int[] value) { + glUniform4iv(handle, value); + } + + public void set(IntBuffer value) { + glUniform4iv(handle, value); + } + + public void set(Vec4i value) { + glUniform4i(handle, value.x, value.y, value.z, value.w); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java index 74214f8..e8281bd 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/backend/shaders/uniforms/Uniform4Matrix.java @@ -1,46 +1,47 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; - -import static org.lwjgl.opengl.GL20.*; -import java.nio.FloatBuffer; - -import glm.mat._4.Mat4; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; - -public class Uniform4Matrix extends Uniform { - - public Uniform4Matrix(int handle, Program program) { - super(handle, program); - } - - public void set(float[] value) { - glUniformMatrix4fv(handle, false, value); - } - - public void set(FloatBuffer value) { - glUniformMatrix4fv(handle, false, value); - } - - private static final float[] BUFFER = new float[4 * 4]; - - public void set(Mat4 value) { - glUniformMatrix4fv(handle, false, value.toFa(BUFFER)); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.backend.shaders.uniforms; + +import static org.lwjgl.opengl.GL20.*; +import java.nio.FloatBuffer; + +import glm.mat._4.Mat4; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; + +public class Uniform4Matrix extends Uniform { + + public Uniform4Matrix(int handle, Program program) { + super(handle, program); + } + + public void set(float[] value) { + glUniformMatrix4fv(handle, false, value); + } + + public void set(FloatBuffer value) { + glUniformMatrix4fv(handle, false, value); + } + + private static final float[] BUFFER = new float[4 * 4]; + + public void set(Mat4 value) { + glUniformMatrix4fv(handle, false, value.toFa(BUFFER)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java index f53aab0..83f9d6f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatLayer.java @@ -1,63 +1,63 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import ru.windcorp.progressia.client.graphics.Layer; -import ru.windcorp.progressia.client.graphics.backend.FaceCulling; - -public abstract class AssembledFlatLayer extends Layer { - - private final AssembledFlatRenderHelper helper = - new AssembledFlatRenderHelper(); - - private final RenderTarget target = new RenderTarget(); - - private RenderTarget.Clip[] clips = null; - - public AssembledFlatLayer(String name) { - super(name); - } - - @Override - protected void initialize() { - // TODO Auto-generated method stub - - } - - @Override - protected void doValidate() { - assemble(target); - clips = target.assemble(); - } - - protected abstract void assemble(RenderTarget target); - - @Override - protected void doRender() { - FaceCulling.push(false); - - for (RenderTarget.Clip clip : clips) { - clip.render(helper); - } - - helper.reset(); - - FaceCulling.pop(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import ru.windcorp.progressia.client.graphics.Layer; +import ru.windcorp.progressia.client.graphics.backend.FaceCulling; + +public abstract class AssembledFlatLayer extends Layer { + + private final AssembledFlatRenderHelper helper = new AssembledFlatRenderHelper(); + + private final RenderTarget target = new RenderTarget(); + + private RenderTarget.Clip[] clips = null; + + public AssembledFlatLayer(String name) { + super(name); + } + + @Override + protected void initialize() { + // TODO Auto-generated method stub + + } + + @Override + protected void doValidate() { + assemble(target); + clips = target.assemble(); + } + + protected abstract void assemble(RenderTarget target); + + @Override + protected void doRender() { + FaceCulling.push(false); + + for (RenderTarget.Clip clip : clips) { + clip.render(helper); + } + + helper.reset(); + + FaceCulling.pop(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java index 0799c02..5696ac2 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/AssembledFlatRenderHelper.java @@ -1,35 +1,36 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -public class AssembledFlatRenderHelper extends FlatRenderHelper { - - private FloatBuffer masks; - - @Override - protected FloatBuffer getMasks() { - return masks; - } - - public void setMasks(FloatBuffer masks) { - this.masks = masks; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +public class AssembledFlatRenderHelper extends FlatRenderHelper { + + private FloatBuffer masks; + + @Override + protected FloatBuffer getMasks() { + return masks; + } + + public void setMasks(FloatBuffer masks) { + this.masks = masks; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java index 3f8264e..4ec676a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/DefaultFlatRenderHelper.java @@ -1,68 +1,69 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -import glm.mat._4.Mat4; - -public class DefaultFlatRenderHelper extends FlatRenderHelper { - - private final TransformedMask transformer = new TransformedMask(); - - protected final MaskStack maskStack = new MaskStack(); - - protected final boolean[] hasMask = new boolean[TRANSFORM_STACK_SIZE]; - - public void pushMask(Mask mask, Mat4 transform) { - pushMask(transformer.set(mask, transform), transform); - } - - public void pushMask(TransformedMask mask, Mat4 transform) { - hasMask[transformStack.getSize()] = true; - pushTransform().mul(transform); - maskStack.pushMask(mask); - } - - @Override - public Mat4 pushTransform() { - hasMask[transformStack.getSize()] = false; - return super.pushTransform(); - } - - @Override - public void popTransform() { - super.popTransform(); - - if (hasMask[transformStack.getSize()]) { - maskStack.popMask(); - } - } - - @Override - public void reset() { - super.reset(); - maskStack.clear(); - } - - @Override - protected FloatBuffer getMasks() { - return maskStack.getBuffer(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +import glm.mat._4.Mat4; + +public class DefaultFlatRenderHelper extends FlatRenderHelper { + + private final TransformedMask transformer = new TransformedMask(); + + protected final MaskStack maskStack = new MaskStack(); + + protected final boolean[] hasMask = new boolean[TRANSFORM_STACK_SIZE]; + + public void pushMask(Mask mask, Mat4 transform) { + pushMask(transformer.set(mask, transform), transform); + } + + public void pushMask(TransformedMask mask, Mat4 transform) { + hasMask[transformStack.getSize()] = true; + pushTransform().mul(transform); + maskStack.pushMask(mask); + } + + @Override + public Mat4 pushTransform() { + hasMask[transformStack.getSize()] = false; + return super.pushTransform(); + } + + @Override + public void popTransform() { + super.popTransform(); + + if (hasMask[transformStack.getSize()]) { + maskStack.popMask(); + } + } + + @Override + public void reset() { + super.reset(); + maskStack.clear(); + } + + @Override + protected FloatBuffer getMasks() { + return maskStack.getBuffer(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java index 82cf3b5..2b615ec 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatGraphics.java @@ -1,24 +1,23 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -public class FlatGraphics { - - - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +public class FlatGraphics { + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java index 8c0e0ac..704c579 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderHelper.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -import glm.mat._4.Mat4; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; - -public abstract class FlatRenderHelper extends ShapeRenderHelper { - - protected static final float MAX_DEPTH = 1 << 16; - - protected final Mat4 finalTransform = new Mat4(); - - protected abstract FloatBuffer getMasks(); - - @Override - public Mat4 getFinalTransform() { - float width = GraphicsInterface.getFrameWidth(); - float height = GraphicsInterface.getFrameHeight(); - - return finalTransform.identity().translate(-1, -1, 0) - .scale(2 / width, 2 / height, 1 / MAX_DEPTH) - .mul(getTransform()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +import glm.mat._4.Mat4; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; + +public abstract class FlatRenderHelper extends ShapeRenderHelper { + + protected static final float MAX_DEPTH = 1 << 16; + + protected final Mat4 finalTransform = new Mat4(); + + protected abstract FloatBuffer getMasks(); + + @Override + public Mat4 getFinalTransform() { + float width = GraphicsInterface.getFrameWidth(); + float height = GraphicsInterface.getFrameHeight(); + + return finalTransform.identity().translate(-1, -1, 0) + .scale(2 / width, 2 / height, 1 / MAX_DEPTH) + .mul(getTransform()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java index 846013f..774e6f3 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/FlatRenderProgram.java @@ -1,107 +1,105 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -import com.google.common.collect.ObjectArrays; - -import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform1Int; -import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform2Float; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; - -public class FlatRenderProgram extends ShapeRenderProgram { - - private static FlatRenderProgram def = null; - - public static void init() { - def = new FlatRenderProgram( - new String[] {"FlatDefault.vertex.glsl"}, - new String[] {"FlatDefault.fragment.glsl"} - ); - } - - public static FlatRenderProgram getDefault() { - return def; - } - - public static final int MASK_STACK_SIZE = 16; // As in Flat.fragment.glsl - - private static final String FLAT_VERTEX_SHADER_RESOURCE = - "Flat.vertex.glsl"; - private static final String FLAT_FRAGMENT_SHADER_RESOURCE = - "Flat.fragment.glsl"; - - private static final String - MASK_COUNT_UNIFORM_NAME = "maskCount", - MASKS_UNIFORM_NAME = "masks"; - - private final Uniform1Int maskCountUniform; - private final Uniform2Float masksUniform; - - public FlatRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - attachVertexShader(vertexShaderResources), - attachFragmentShader(fragmentShaderResources) - ); - - this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int(); - this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float(); - } - - private static String[] attachVertexShader(String[] others) { - return ObjectArrays.concat(FLAT_VERTEX_SHADER_RESOURCE, others); - } - - private static String[] attachFragmentShader(String[] others) { - return ObjectArrays.concat(FLAT_FRAGMENT_SHADER_RESOURCE, others); - } - - @Override - public void render(ShapeRenderHelper helper, Shape shape) { - super.render(helper, shape); - } - - @Override - protected void configure(ShapeRenderHelper argHelper) { - super.configure(argHelper); - FlatRenderHelper helper = ((FlatRenderHelper) argHelper); - - configureMasks(helper.getMasks()); - } - - private void configureMasks(FloatBuffer masks) { - int pos = masks.position(); - int limit = masks.limit(); - int size = pos / TransformedMask.SIZE_IN_FLOATS; - - maskCountUniform.set(size); - - masks.flip(); - masksUniform.set(masks); - - masks.limit(limit); - masks.position(pos); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +import com.google.common.collect.ObjectArrays; + +import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform1Int; +import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.Uniform2Float; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; + +public class FlatRenderProgram extends ShapeRenderProgram { + + private static FlatRenderProgram def = null; + + public static void init() { + def = new FlatRenderProgram( + new String[] { "FlatDefault.vertex.glsl" }, + new String[] { "FlatDefault.fragment.glsl" } + ); + } + + public static FlatRenderProgram getDefault() { + return def; + } + + public static final int MASK_STACK_SIZE = 16; // As in Flat.fragment.glsl + + private static final String FLAT_VERTEX_SHADER_RESOURCE = "Flat.vertex.glsl"; + private static final String FLAT_FRAGMENT_SHADER_RESOURCE = "Flat.fragment.glsl"; + + private static final String MASK_COUNT_UNIFORM_NAME = "maskCount", + MASKS_UNIFORM_NAME = "masks"; + + private final Uniform1Int maskCountUniform; + private final Uniform2Float masksUniform; + + public FlatRenderProgram( + String[] vertexShaderResources, + String[] fragmentShaderResources + ) { + super( + attachVertexShader(vertexShaderResources), + attachFragmentShader(fragmentShaderResources) + ); + + this.maskCountUniform = getUniform(MASK_COUNT_UNIFORM_NAME).as1Int(); + this.masksUniform = getUniform(MASKS_UNIFORM_NAME).as2Float(); + } + + private static String[] attachVertexShader(String[] others) { + return ObjectArrays.concat(FLAT_VERTEX_SHADER_RESOURCE, others); + } + + private static String[] attachFragmentShader(String[] others) { + return ObjectArrays.concat(FLAT_FRAGMENT_SHADER_RESOURCE, others); + } + + @Override + public void render(ShapeRenderHelper helper, Shape shape) { + super.render(helper, shape); + } + + @Override + protected void configure(ShapeRenderHelper argHelper) { + super.configure(argHelper); + FlatRenderHelper helper = ((FlatRenderHelper) argHelper); + + configureMasks(helper.getMasks()); + } + + private void configureMasks(FloatBuffer masks) { + int pos = masks.position(); + int limit = masks.limit(); + int size = pos / TransformedMask.SIZE_IN_FLOATS; + + maskCountUniform.set(size); + + masks.flip(); + masksUniform.set(masks); + + masks.limit(limit); + masks.position(pos); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java index a832972..e13400a 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/Mask.java @@ -1,93 +1,95 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -public class Mask { - - private int startX; - private int startY; - private int endX; - private int endY; - - public Mask(int startX, int startY, int endX, int endY) { - this.startX = startX; - this.startY = startY; - this.endX = endX; - this.endY = endY; - } - - public Mask() {} - - public int getStartX() { - return startX; - } - - public void setStartX(int startX) { - this.startX = startX; - } - - public int getStartY() { - return startY; - } - - public void setStartY(int startY) { - this.startY = startY; - } - - public int getEndX() { - return endX; - } - - public void setEndX(int endX) { - this.endX = endX; - } - - public int getEndY() { - return endY; - } - - public void setEndY(int endY) { - this.endY = endY; - } - - public int getWidth() { - return getEndX() - getStartX(); - } - - public int getHeight() { - return getEndY() - getStartY(); - } - - public void set(int startX, int startY, int endX, int endY) { - this.startX = startX; - this.startY = startY; - this.endX = endX; - this.endY = endY; - } - - public void set(Mask copyFrom) { - set(copyFrom.startX, copyFrom.startY, copyFrom.endX, copyFrom.endY); - } - - @Override - public String toString() { - return "(" + getStartX() + "; " + getStartY() + - ") -> (" + getEndX() + "; " + getEndY() + ")"; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +public class Mask { + + private int startX; + private int startY; + private int endX; + private int endY; + + public Mask(int startX, int startY, int endX, int endY) { + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + public Mask() { + } + + public int getStartX() { + return startX; + } + + public void setStartX(int startX) { + this.startX = startX; + } + + public int getStartY() { + return startY; + } + + public void setStartY(int startY) { + this.startY = startY; + } + + public int getEndX() { + return endX; + } + + public void setEndX(int endX) { + this.endX = endX; + } + + public int getEndY() { + return endY; + } + + public void setEndY(int endY) { + this.endY = endY; + } + + public int getWidth() { + return getEndX() - getStartX(); + } + + public int getHeight() { + return getEndY() - getStartY(); + } + + public void set(int startX, int startY, int endX, int endY) { + this.startX = startX; + this.startY = startY; + this.endX = endX; + this.endY = endY; + } + + public void set(Mask copyFrom) { + set(copyFrom.startX, copyFrom.startY, copyFrom.endX, copyFrom.endY); + } + + @Override + public String toString() { + return "(" + getStartX() + "; " + getStartY() + + ") -> (" + getEndX() + "; " + getEndY() + ")"; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java index d8cb9cc..f114058 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/MaskStack.java @@ -1,46 +1,47 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -import org.lwjgl.BufferUtils; - -public class MaskStack { - - private final FloatBuffer buffer = BufferUtils.createFloatBuffer( - FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS - ); - - public void pushMask(TransformedMask mask) { - mask.writeToBuffer(buffer); - } - - public void popMask() { - buffer.position(buffer.position() - TransformedMask.SIZE_IN_FLOATS); - } - - public void clear() { - buffer.clear(); - } - - FloatBuffer getBuffer() { - return buffer; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +import org.lwjgl.BufferUtils; + +public class MaskStack { + + private final FloatBuffer buffer = BufferUtils.createFloatBuffer( + FlatRenderProgram.MASK_STACK_SIZE * TransformedMask.SIZE_IN_FLOATS + ); + + public void pushMask(TransformedMask mask) { + mask.writeToBuffer(buffer); + } + + public void popMask() { + buffer.position(buffer.position() - TransformedMask.SIZE_IN_FLOATS); + } + + public void clear() { + buffer.clear(); + } + + FloatBuffer getBuffer() { + return buffer; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java index 8847a3a..1fea54e 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/RenderTarget.java @@ -1,278 +1,331 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; - -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.texture.Texture; - -public class RenderTarget { - - private static final Mat4 IDENTITY = new Mat4().identity(); - - public static class Clip { - - private final MaskStack masks = new MaskStack(); - private final Mat4 transform; - private final Renderable renderable; - - public Clip( - Iterable masks, - Mat4 transform, - Renderable renderable - ) { - for (TransformedMask mask : masks) { - this.masks.pushMask(mask); - } - - this.transform = transform == null ? IDENTITY : transform; - this.renderable = Objects.requireNonNull(renderable, "renderable"); - } - - public Mat4 getTransform() { - return transform; - } - - public Renderable getRenderable() { - return renderable; - } - - public void render(AssembledFlatRenderHelper helper) { - helper.setMasks(masks.getBuffer()); - helper.pushTransform().mul(getTransform()); - - try { - getRenderable().render(helper); - } finally { - helper.popTransform(); - helper.setMasks(null); - } - } - - } - - private final List assembled = new ArrayList<>(); - - private final Deque maskStack = new LinkedList<>(); - private final Deque transformStack = new LinkedList<>(); - private final List currentClipFaces = new ArrayList<>(); - - private int depth = 0; - - public RenderTarget() { - reset(); - } - - protected void assembleCurrentClipFromFaces() { - if (!currentClipFaces.isEmpty()) { - Face[] faces = currentClipFaces.toArray( - new Face[currentClipFaces.size()] - ); - currentClipFaces.clear(); - - Shape shape = new Shape( - Usage.STATIC, FlatRenderProgram.getDefault(), faces - ); - - assembled.add(new Clip( - maskStack, getTransform(), shape - )); - } - } - - public Clip[] assemble() { - assembleCurrentClipFromFaces(); - - Clip[] result = assembled.toArray( - new Clip[assembled.size()] - ); - - reset(); - - return result; - } - - private void reset() { - maskStack.clear(); - transformStack.clear(); - currentClipFaces.clear(); - assembled.clear(); - - transformStack.add(new Mat4().identity()); - depth = 0; - } - - public void pushMaskStartEnd(int startX, int startY, int endX, int endY) { - assembleCurrentClipFromFaces(); - - pushTransform(new Mat4().identity().translate(startX, startY, 0)); - - maskStack.push( - new TransformedMask( - new Mask(startX, startY, endX, endY), - getTransform() - ) - ); - } - - public void pushMask(Mask mask) { - pushMaskStartEnd( - mask.getStartX(), mask.getStartY(), - mask.getEndX(), mask.getEndY() - ); - } - - public void pushMaskStartSize(int x, int y, int width, int height) { - pushMaskStartEnd(x, y, x + width, y + height); - } - - public void popMask() { - assembleCurrentClipFromFaces(); - maskStack.pop(); - popTransform(); - } - - public TransformedMask getMask() { - return maskStack.getFirst(); - } - - public void pushTransform(Mat4 transform) { - assembleCurrentClipFromFaces(); - transformStack.push(getTransform().mul(transform, transform)); - } - - public void popTransform() { - assembleCurrentClipFromFaces(); - transformStack.pop(); - } - - public Mat4 getTransform() { - return transformStack.getFirst(); - } - - public void addCustomRenderer(Renderable renderable) { - assembleCurrentClipFromFaces(); - assembled.add(new Clip( - maskStack, getTransform(), renderable - )); - } - - protected void addFaceToCurrentClip(Face face) { - currentClipFaces.add(face); - } - - public void drawTexture( - int x, int y, int width, int height, - Vec4 color, Texture texture - ) { - addFaceToCurrentClip( - createRectagleFace(x, y, width, height, color, texture) - ); - } - - public void drawTexture( - int x, int y, int width, int height, - int color, Texture texture - ) { - drawTexture(x, y, width, height, Colors.toVector(color), texture); - } - - public void drawTexture( - int x, int y, int width, int height, - Texture texture - ) { - drawTexture(x, y, width, height, Colors.WHITE, texture); - } - - public void fill( - int x, int y, int width, int height, - Vec4 color - ) { - drawTexture(x, y, width, height, color, null); - } - - public void fill( - int x, int y, int width, int height, - int color - ) { - fill(x, y, width, height, Colors.toVector(color)); - } - - public void fill(Vec4 color) { - fill( - Integer.MIN_VALUE / 2, Integer.MIN_VALUE / 2, - Integer.MAX_VALUE, Integer.MAX_VALUE, - color - ); - } - - public void fill(int color) { - fill(Colors.toVector(color)); - } - - public Face createRectagleFace( - int x, int y, int width, int height, Vec4 color, Texture texture - ) { - float depth = this.depth--; - - return Faces.createRectangle( - FlatRenderProgram.getDefault(), - texture, - color, - new Vec3(x, y, depth), - new Vec3(width, 0, 0), - new Vec3(0, height, 0), - false - ); - } - - public Face createRectagleFace( - int x, int y, int width, int height, int color, Texture texture - ) { - return createRectagleFace(x, y, width, height, Colors.toVector(color), texture); - } - - public Shape createRectagle( - int x, int y, int width, int height, Vec4 color, Texture texture - ) { - return new Shape( - Usage.STATIC, FlatRenderProgram.getDefault(), - createRectagleFace(x, y, width, height, color, texture) - ); - } - - public Shape createRectagle( - int x, int y, int width, int height, int color, Texture texture - ) { - return createRectagle(x, y, width, height, Colors.toVector(color), texture); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.texture.Texture; + +public class RenderTarget { + + private static final Mat4 IDENTITY = new Mat4().identity(); + + public static class Clip { + + private final MaskStack masks = new MaskStack(); + private final Mat4 transform; + private final Renderable renderable; + + public Clip( + Iterable masks, + Mat4 transform, + Renderable renderable + ) { + for (TransformedMask mask : masks) { + this.masks.pushMask(mask); + } + + this.transform = transform == null ? IDENTITY : transform; + this.renderable = Objects.requireNonNull(renderable, "renderable"); + } + + public Mat4 getTransform() { + return transform; + } + + public Renderable getRenderable() { + return renderable; + } + + public void render(AssembledFlatRenderHelper helper) { + helper.setMasks(masks.getBuffer()); + helper.pushTransform().mul(getTransform()); + + try { + getRenderable().render(helper); + } finally { + helper.popTransform(); + helper.setMasks(null); + } + } + + } + + private final List assembled = new ArrayList<>(); + + private final Deque maskStack = new LinkedList<>(); + private final Deque transformStack = new LinkedList<>(); + private final List currentClipFaces = new ArrayList<>(); + + private int depth = 0; + + public RenderTarget() { + reset(); + } + + protected void assembleCurrentClipFromFaces() { + if (!currentClipFaces.isEmpty()) { + Face[] faces = currentClipFaces.toArray( + new Face[currentClipFaces.size()] + ); + currentClipFaces.clear(); + + Shape shape = new Shape( + Usage.STATIC, + FlatRenderProgram.getDefault(), + faces + ); + + assembled.add( + new Clip( + maskStack, + getTransform(), + shape + ) + ); + } + } + + public Clip[] assemble() { + assembleCurrentClipFromFaces(); + + Clip[] result = assembled.toArray( + new Clip[assembled.size()] + ); + + reset(); + + return result; + } + + private void reset() { + maskStack.clear(); + transformStack.clear(); + currentClipFaces.clear(); + assembled.clear(); + + transformStack.add(new Mat4().identity()); + depth = 0; + } + + public void pushMaskStartEnd(int startX, int startY, int endX, int endY) { + assembleCurrentClipFromFaces(); + + pushTransform(new Mat4().identity().translate(startX, startY, 0)); + + maskStack.push( + new TransformedMask( + new Mask(startX, startY, endX, endY), + getTransform() + ) + ); + } + + public void pushMask(Mask mask) { + pushMaskStartEnd( + mask.getStartX(), + mask.getStartY(), + mask.getEndX(), + mask.getEndY() + ); + } + + public void pushMaskStartSize(int x, int y, int width, int height) { + pushMaskStartEnd(x, y, x + width, y + height); + } + + public void popMask() { + assembleCurrentClipFromFaces(); + maskStack.pop(); + popTransform(); + } + + public TransformedMask getMask() { + return maskStack.getFirst(); + } + + public void pushTransform(Mat4 transform) { + assembleCurrentClipFromFaces(); + transformStack.push(getTransform().mul(transform, transform)); + } + + public void popTransform() { + assembleCurrentClipFromFaces(); + transformStack.pop(); + } + + public Mat4 getTransform() { + return transformStack.getFirst(); + } + + public void addCustomRenderer(Renderable renderable) { + assembleCurrentClipFromFaces(); + assembled.add( + new Clip( + maskStack, + getTransform(), + renderable + ) + ); + } + + protected void addFaceToCurrentClip(Face face) { + currentClipFaces.add(face); + } + + public void drawTexture( + int x, + int y, + int width, + int height, + Vec4 color, + Texture texture + ) { + addFaceToCurrentClip( + createRectagleFace(x, y, width, height, color, texture) + ); + } + + public void drawTexture( + int x, + int y, + int width, + int height, + int color, + Texture texture + ) { + drawTexture(x, y, width, height, Colors.toVector(color), texture); + } + + public void drawTexture( + int x, + int y, + int width, + int height, + Texture texture + ) { + drawTexture(x, y, width, height, Colors.WHITE, texture); + } + + public void fill( + int x, + int y, + int width, + int height, + Vec4 color + ) { + drawTexture(x, y, width, height, color, null); + } + + public void fill( + int x, + int y, + int width, + int height, + int color + ) { + fill(x, y, width, height, Colors.toVector(color)); + } + + public void fill(Vec4 color) { + fill( + Integer.MIN_VALUE / 2, + Integer.MIN_VALUE / 2, + Integer.MAX_VALUE, + Integer.MAX_VALUE, + color + ); + } + + public void fill(int color) { + fill(Colors.toVector(color)); + } + + public Face createRectagleFace( + int x, + int y, + int width, + int height, + Vec4 color, + Texture texture + ) { + float depth = this.depth--; + + return Faces.createRectangle( + FlatRenderProgram.getDefault(), + texture, + color, + new Vec3(x, y, depth), + new Vec3(width, 0, 0), + new Vec3(0, height, 0), + false + ); + } + + public Face createRectagleFace( + int x, + int y, + int width, + int height, + int color, + Texture texture + ) { + return createRectagleFace(x, y, width, height, Colors.toVector(color), texture); + } + + public Shape createRectagle( + int x, + int y, + int width, + int height, + Vec4 color, + Texture texture + ) { + return new Shape( + Usage.STATIC, + FlatRenderProgram.getDefault(), + createRectagleFace(x, y, width, height, color, texture) + ); + } + + public Shape createRectagle( + int x, + int y, + int width, + int height, + int color, + Texture texture + ) { + return createRectagle(x, y, width, height, Colors.toVector(color), texture); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java b/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java index 31d24a1..5328cc8 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/flat/TransformedMask.java @@ -1,146 +1,155 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.flat; - -import java.nio.FloatBuffer; - -import glm.mat._4.Mat4; -import glm.vec._2.Vec2; -import glm.vec._4.Vec4; - -public class TransformedMask { - - public static final int SIZE_IN_FLOATS = 2 * 3 * 2; - - private final Vec2 origin = new Vec2(); - private final Vec2 width = new Vec2(); - private final Vec2 height = new Vec2(); - - private final Vec2 counterOrigin = new Vec2(); - private final Vec2 counterWidth = new Vec2(); - private final Vec2 counterHeight = new Vec2(); - - // Temporary values, objects cached for efficiency - private Vec4 startXstartY = null; - private Vec4 startXendY = null; - private Vec4 endXstartY = null; - private Vec4 endXendY = null; - - public TransformedMask( - Vec2 origin, Vec2 width, Vec2 height, - Vec2 counterOrigin, Vec2 counterWidth, Vec2 counterHeight - ) { - set(origin, width, height, counterOrigin, counterWidth, counterHeight); - } - - public TransformedMask(Mask mask, Mat4 transform) { - set(mask, transform); - } - - public TransformedMask() { - // Do nothing - } - - public TransformedMask set( - Vec2 origin, Vec2 width, Vec2 height, - Vec2 counterOrigin, Vec2 counterWidth, Vec2 counterHeight - ) { - this.origin.set(origin.x, origin.y); - this.width.set(width.x, width.y); - this.height.set(height.x, height.y); - this.counterOrigin.set(counterOrigin.x, counterOrigin.y); - this.counterWidth.set(counterWidth.x, counterWidth.y); - this.counterHeight.set(counterHeight.x, counterHeight.y); - - return this; - } - - public TransformedMask set(Mask mask, Mat4 transform) { - applyTransform(mask, transform); - setFields(); - return this; - } - - private void applyTransform(Mask mask, Mat4 transform) { - ensureTemporaryVariablesExist(); - - int relX = mask.getWidth(); - int relY = mask.getHeight(); - - startXstartY.set( 0, 0, 0, 1); - startXendY .set( 0, relY, 0, 1); - endXstartY .set(relX, 0, 0, 1); - endXendY .set(relX, relY, 0, 1); - - transform.mul(startXstartY); - transform.mul(startXendY); - transform.mul(endXstartY); - transform.mul(endXendY); - } - - private void ensureTemporaryVariablesExist() { - if (startXstartY == null) { - startXstartY = new Vec4(); - startXendY = new Vec4(); - endXstartY = new Vec4(); - endXendY = new Vec4(); - } - } - - private void setFields() { - origin.set( - startXstartY.x, - startXstartY.y - ); - - width.set( - endXstartY.x - startXstartY.x, - endXstartY.y - startXstartY.y - ); - - height.set( - startXendY.x - startXstartY.x, - startXendY.y - startXstartY.y - ); - - counterOrigin.set( - endXendY.x, - endXendY.y - ); - - counterWidth.set( - startXendY.x - endXendY.x, - startXendY.y - endXendY.y - ); - - counterHeight.set( - endXstartY.x - endXendY.x, - endXstartY.y - endXendY.y - ); - } - - public void writeToBuffer(FloatBuffer output) { - output.put(origin.x).put(origin.y); - output.put(width.x).put(width.y); - output.put(height.x).put(height.y); - output.put(counterOrigin.x).put(counterOrigin.y); - output.put(counterWidth.x).put(counterWidth.y); - output.put(counterHeight.x).put(counterHeight.y); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.flat; + +import java.nio.FloatBuffer; + +import glm.mat._4.Mat4; +import glm.vec._2.Vec2; +import glm.vec._4.Vec4; + +public class TransformedMask { + + public static final int SIZE_IN_FLOATS = 2 * 3 * 2; + + private final Vec2 origin = new Vec2(); + private final Vec2 width = new Vec2(); + private final Vec2 height = new Vec2(); + + private final Vec2 counterOrigin = new Vec2(); + private final Vec2 counterWidth = new Vec2(); + private final Vec2 counterHeight = new Vec2(); + + // Temporary values, objects cached for efficiency + private Vec4 startXstartY = null; + private Vec4 startXendY = null; + private Vec4 endXstartY = null; + private Vec4 endXendY = null; + + public TransformedMask( + Vec2 origin, + Vec2 width, + Vec2 height, + Vec2 counterOrigin, + Vec2 counterWidth, + Vec2 counterHeight + ) { + set(origin, width, height, counterOrigin, counterWidth, counterHeight); + } + + public TransformedMask(Mask mask, Mat4 transform) { + set(mask, transform); + } + + public TransformedMask() { + // Do nothing + } + + public TransformedMask set( + Vec2 origin, + Vec2 width, + Vec2 height, + Vec2 counterOrigin, + Vec2 counterWidth, + Vec2 counterHeight + ) { + this.origin.set(origin.x, origin.y); + this.width.set(width.x, width.y); + this.height.set(height.x, height.y); + this.counterOrigin.set(counterOrigin.x, counterOrigin.y); + this.counterWidth.set(counterWidth.x, counterWidth.y); + this.counterHeight.set(counterHeight.x, counterHeight.y); + + return this; + } + + public TransformedMask set(Mask mask, Mat4 transform) { + applyTransform(mask, transform); + setFields(); + return this; + } + + private void applyTransform(Mask mask, Mat4 transform) { + ensureTemporaryVariablesExist(); + + int relX = mask.getWidth(); + int relY = mask.getHeight(); + + startXstartY.set(0, 0, 0, 1); + startXendY.set(0, relY, 0, 1); + endXstartY.set(relX, 0, 0, 1); + endXendY.set(relX, relY, 0, 1); + + transform.mul(startXstartY); + transform.mul(startXendY); + transform.mul(endXstartY); + transform.mul(endXendY); + } + + private void ensureTemporaryVariablesExist() { + if (startXstartY == null) { + startXstartY = new Vec4(); + startXendY = new Vec4(); + endXstartY = new Vec4(); + endXendY = new Vec4(); + } + } + + private void setFields() { + origin.set( + startXstartY.x, + startXstartY.y + ); + + width.set( + endXstartY.x - startXstartY.x, + endXstartY.y - startXstartY.y + ); + + height.set( + startXendY.x - startXstartY.x, + startXendY.y - startXstartY.y + ); + + counterOrigin.set( + endXendY.x, + endXendY.y + ); + + counterWidth.set( + startXendY.x - endXendY.x, + startXendY.y - endXendY.y + ); + + counterHeight.set( + endXstartY.x - endXendY.x, + endXstartY.y - endXendY.y + ); + } + + public void writeToBuffer(FloatBuffer output) { + output.put(origin.x).put(origin.y); + output.put(width.x).put(width.y); + output.put(height.x).put(height.y); + output.put(counterOrigin.x).put(counterOrigin.y); + output.put(counterWidth.x).put(counterWidth.y); + output.put(counterHeight.x).put(counterHeight.y); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java index 744a997..591ff83 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Font.java @@ -1,151 +1,172 @@ -package ru.windcorp.progressia.client.graphics.font; - -import java.util.function.Supplier; - -import glm.vec._2.i.Vec2i; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.model.Renderable; - -public class Font { - - private final Typeface typeface; - - private final int style; - private final float align; - private final Vec4 color; - - public Font(Typeface typeface, int style, float align, Vec4 color) { - this.typeface = typeface; - this.style = style; - this.align = align; - this.color = color; - } - - public Font(Typeface typeface, int style, float align, int color) { - this(typeface, style, align, Colors.toVector(color)); - } - - public Font(Typeface typeface) { - this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE); - } - - public Font() { - this(Typefaces.getDefault()); - } - - public Typeface getTypeface() { - return typeface; - } - - public int getStyle() { - return style; - } - - public float getAlign() { - return align; - } - - public Vec4 getColor() { - return color; - } - - public Renderable assemble( - CharSequence chars, float maxWidth - ) { - return typeface.assembleStatic(chars, style, align, maxWidth, color); - } - - public Renderable assembleDynamic( - Supplier supplier, float maxWidth - ) { - return typeface.assembleDynamic(supplier, style, align, maxWidth, color); - } - - public int getWidth(CharSequence chars, float maxWidth) { - return typeface.getWidth(chars, style, align, maxWidth); - } - - public int getHeight(CharSequence chars, float maxWidth) { - return typeface.getHeight(chars, style, align, maxWidth); - } - - public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i result) { - return typeface.getSize(chars, style, align, maxWidth, result); - } - - public boolean supports(char c) { - return typeface.supports(c); - } - - /** - * Creates a new {@link Font} with the specified {@code style} exactly. This - * object's style is ignored. - * @param style the new style - * @return the new font - */ - public Font withStyle(int style) { - return new Font(getTypeface(), style, getAlign(), getColor()); - } - - public Font deriveBold() { - return withStyle(getStyle() | Typeface.Style.BOLD); - } - - public Font deriveItalic() { - return withStyle(getStyle() | Typeface.Style.ITALIC); - } - - public Font deriveUnderlined() { - return withStyle(getStyle() | Typeface.Style.UNDERLINED); - } - - public Font deriveStrikethru() { - return withStyle(getStyle() | Typeface.Style.STRIKETHRU); - } - - public Font deriveShadow() { - return withStyle(getStyle() | Typeface.Style.SHADOW); - } - - public Font deriveOutlined() { - return withStyle(getStyle() | Typeface.Style.OUTLINED); - } - - public Font deriveNotBold() { - return withStyle(getStyle() & ~Typeface.Style.BOLD); - } - - public Font deriveNotItalic() { - return withStyle(getStyle() & ~Typeface.Style.ITALIC); - } - - public Font deriveNotUnderlined() { - return withStyle(getStyle() & ~Typeface.Style.UNDERLINED); - } - - public Font deriveNotStrikethru() { - return withStyle(getStyle() & ~Typeface.Style.STRIKETHRU); - } - - public Font deriveNotShadow() { - return withStyle(getStyle() & ~Typeface.Style.SHADOW); - } - - public Font deriveNotOutlined() { - return withStyle(getStyle() & ~Typeface.Style.OUTLINED); - } - - public Font withAlign(float align) { - return new Font(getTypeface(), getStyle(), align, getColor()); - } - - public Font withColor(Vec4 color) { - return new Font(getTypeface(), getStyle(), getAlign(), color); - } - - public Font withColor(int color) { - return new Font(getTypeface(), getStyle(), getAlign(), color); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.font; + +import java.util.function.Supplier; + +import glm.vec._2.i.Vec2i; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.model.Renderable; + +public class Font { + + private final Typeface typeface; + + private final int style; + private final float align; + private final Vec4 color; + + public Font(Typeface typeface, int style, float align, Vec4 color) { + this.typeface = typeface; + this.style = style; + this.align = align; + this.color = color; + } + + public Font(Typeface typeface, int style, float align, int color) { + this(typeface, style, align, Colors.toVector(color)); + } + + public Font(Typeface typeface) { + this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE); + } + + public Font() { + this(Typefaces.getDefault()); + } + + public Typeface getTypeface() { + return typeface; + } + + public int getStyle() { + return style; + } + + public float getAlign() { + return align; + } + + public Vec4 getColor() { + return color; + } + + public Renderable assemble( + CharSequence chars, + float maxWidth + ) { + return typeface.assembleStatic(chars, style, align, maxWidth, color); + } + + public Renderable assembleDynamic( + Supplier supplier, + float maxWidth + ) { + return typeface.assembleDynamic(supplier, style, align, maxWidth, color); + } + + public int getWidth(CharSequence chars, float maxWidth) { + return typeface.getWidth(chars, style, align, maxWidth); + } + + public int getHeight(CharSequence chars, float maxWidth) { + return typeface.getHeight(chars, style, align, maxWidth); + } + + public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i result) { + return typeface.getSize(chars, style, align, maxWidth, result); + } + + public boolean supports(char c) { + return typeface.supports(c); + } + + /** + * Creates a new {@link Font} with the specified {@code style} exactly. This + * object's style is ignored. + * + * @param style the new style + * @return the new font + */ + public Font withStyle(int style) { + return new Font(getTypeface(), style, getAlign(), getColor()); + } + + public Font deriveBold() { + return withStyle(getStyle() | Typeface.Style.BOLD); + } + + public Font deriveItalic() { + return withStyle(getStyle() | Typeface.Style.ITALIC); + } + + public Font deriveUnderlined() { + return withStyle(getStyle() | Typeface.Style.UNDERLINED); + } + + public Font deriveStrikethru() { + return withStyle(getStyle() | Typeface.Style.STRIKETHRU); + } + + public Font deriveShadow() { + return withStyle(getStyle() | Typeface.Style.SHADOW); + } + + public Font deriveOutlined() { + return withStyle(getStyle() | Typeface.Style.OUTLINED); + } + + public Font deriveNotBold() { + return withStyle(getStyle() & ~Typeface.Style.BOLD); + } + + public Font deriveNotItalic() { + return withStyle(getStyle() & ~Typeface.Style.ITALIC); + } + + public Font deriveNotUnderlined() { + return withStyle(getStyle() & ~Typeface.Style.UNDERLINED); + } + + public Font deriveNotStrikethru() { + return withStyle(getStyle() & ~Typeface.Style.STRIKETHRU); + } + + public Font deriveNotShadow() { + return withStyle(getStyle() & ~Typeface.Style.SHADOW); + } + + public Font deriveNotOutlined() { + return withStyle(getStyle() & ~Typeface.Style.OUTLINED); + } + + public Font withAlign(float align) { + return new Font(getTypeface(), getStyle(), align, getColor()); + } + + public Font withColor(Vec4 color) { + return new Font(getTypeface(), getStyle(), getAlign(), color); + } + + public Font withColor(int color) { + return new Font(getTypeface(), getStyle(), getAlign(), color); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java index de413ec..f28975d 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifont.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.font; import gnu.trove.map.TCharObjectMap; @@ -8,10 +26,10 @@ import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; import ru.windcorp.progressia.client.graphics.texture.Texture; public class GNUUnifont extends SpriteTypeface { - + public static final int HEIGHT = 16; - public static final TIntSet WIDTHS = new TIntHashSet(new int[] {8, 16}); - + public static final TIntSet WIDTHS = new TIntHashSet(new int[] { 8, 16 }); + private final TCharObjectMap textures; public GNUUnifont(TCharObjectMap textures) { @@ -21,7 +39,8 @@ public class GNUUnifont extends SpriteTypeface { @Override public Texture getTexture(char c) { - if (!supports(c)) return textures.get('?'); + if (!supports(c)) + return textures.get('?'); return textures.get(c); } @@ -34,7 +53,7 @@ public class GNUUnifont extends SpriteTypeface { public boolean supports(char c) { return textures.containsKey(c); } - + @Override public float getItalicsSlant() { return 3 * super.getItalicsSlant(); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java index 8cf4575..9ead1db 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/GNUUnifontLoader.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.font; import java.io.BufferedReader; @@ -55,7 +73,7 @@ public class GNUUnifontLoader { public static GNUUnifont load(Resource resource) { try (BufferedReader reader = createReader(resource)) { return createStream(reader).map(GNUUnifontLoader::parse).map(GNUUnifontLoader::addToAtlas) - .collect(Collectors.collectingAndThen(createMapper(), GNUUnifont::new)); + .collect(Collectors.collectingAndThen(createMapper(), GNUUnifont::new)); } catch (IOException | UncheckedIOException e) { throw CrashReports.report(e, "Could not load GNUUnifont"); } @@ -63,7 +81,8 @@ public class GNUUnifontLoader { private static BufferedReader createReader(Resource resource) throws IOException { return new BufferedReader( - new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8)); + new InputStreamReader(new GZIPInputStream(resource.getInputStream()), StandardCharsets.UTF_8) + ); } private static Stream createStream(BufferedReader reader) { @@ -72,25 +91,30 @@ public class GNUUnifontLoader { private static ParsedGlyph parse(String declar) { try { - + int width = getWidth(declar); checkDeclaration(declar, width); - + char c = getChar(declar); - - TextureDataEditor editor = new TextureDataEditor(width, GNUUnifont.HEIGHT, width, GNUUnifont.HEIGHT, - TEXTURE_SETTINGS); - + + TextureDataEditor editor = new TextureDataEditor( + width, + GNUUnifont.HEIGHT, + width, + GNUUnifont.HEIGHT, + TEXTURE_SETTINGS + ); + for (int y = 0; y < GNUUnifont.HEIGHT; ++y) { for (int x = 0; x < width; ++x) { int bit = x + y * width; - + editor.setPixel(x, GNUUnifont.HEIGHT - y - 1, getBit(declar, bit) ? 0xFFFFFFFF : 0x00000000); } } - + return new ParsedGlyph(c, editor); - + } catch (IOException e) { throw CrashReports.report(e, "Could not load GNUUnifont: could not load character \"%s\"", declar); } @@ -126,11 +150,11 @@ public class GNUUnifontLoader { if (!GNUUnifont.WIDTHS.contains(width)) { throw new IOException("Width " + width + " is not supported (in declar \"" + declar + "\")"); } - + if ((declar.length() - PREFIX_LENGTH) % width != 0) { throw new IOException("Declar \"" + declar + "\" has invalid length"); } - + for (int i = 0; i < declar.length(); ++i) { if (i == BITS_PER_HEX_DIGIT) { if (declar.charAt(i) != ':') { @@ -138,9 +162,11 @@ public class GNUUnifontLoader { } } else { char c = declar.charAt(i); - + if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))) { - throw new IOException("Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F"); + throw new IOException( + "Illegal char in declar \"" + declar + "\" at index " + i + "; expected 0-9A-F" + ); } } } @@ -164,16 +190,18 @@ public class GNUUnifontLoader { } private static Collector> createMapper() { - return Collector.of(TCharObjectHashMap::new, + return Collector.of( + TCharObjectHashMap::new, - (map, glyph) -> map.put(glyph.c, glyph.texture), + (map, glyph) -> map.put(glyph.c, glyph.texture), - (a, b) -> { - a.putAll(b); - return a; - }, + (a, b) -> { + a.putAll(b); + return a; + }, - Characteristics.UNORDERED); + Characteristics.UNORDERED + ); } private GNUUnifontLoader() { diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java index ab552ab..7920799 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/SpriteTypeface.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.font; import java.util.ArrayList; @@ -31,9 +49,9 @@ public abstract class SpriteTypeface extends Typeface { private final int height; private final int thickness; private final Vec3 shadowOffset; - + private final TCharObjectMap charShapes = new TCharObjectHashMap<>(); - + public SpriteTypeface(String name, int height, int thinkness) { super(name); this.height = height; @@ -42,123 +60,142 @@ public abstract class SpriteTypeface extends Typeface { } public abstract Texture getTexture(char c); - + public int getWidth(char c) { return getTexture(c).getSprite().getWidth(); } - + public int getHeight() { return height; } - + @Override public int getLineHeight() { return getHeight(); } - + public int getThickness() { return thickness; } - + public int getInterlineBuffer() { return getThickness(); } - + public float getItalicsSlant() { return getThickness() / (float) getHeight(); } - + public float getBoldOffset() { return getThickness(); } - + public float getDecorativeLineThickness() { return getThickness(); } - + public Vec3 getShadowOffset() { return shadowOffset; } - + public float getShadowColorMultiplier() { return 0.5f; } - + public abstract ShapeRenderProgram getProgram(); @Override public Vec2i getSize( - CharSequence chars, int style, - float align, float maxWidth, - Vec2i output + CharSequence chars, + int style, + float align, + float maxWidth, + Vec2i output ) { - if (output == null) output = new Vec2i(); - + if (output == null) + output = new Vec2i(); + int resultWidth = 0; int currentWidth = Style.isBold(style) ? getThickness() : 0; int height = getHeight(); - + for (int i = 0; i < chars.length(); ++i) { char c = chars.charAt(i); - + if (c == '\n' || currentWidth + getWidth(c) > maxWidth) { height += getHeight() + getInterlineBuffer(); - if (resultWidth < currentWidth) resultWidth = currentWidth; + if (resultWidth < currentWidth) + resultWidth = currentWidth; currentWidth = Style.isBold(style) ? getThickness() : 0; } - + if (c != '\n') { currentWidth += getWidth(c); } } - - if (resultWidth < currentWidth) resultWidth = currentWidth; - + + if (resultWidth < currentWidth) + resultWidth = currentWidth; + return output.set(resultWidth, height); } private Shape createCharShape(char c) { return new Shape( - Usage.STATIC, getProgram(), - Faces.createRectangle( - getProgram(), - getTexture(c), - Colors.WHITE, - Vectors.ZERO_3, - new Vec3(getWidth(c), 0, 0), - new Vec3(0, getHeight(), 0), - false - ) + Usage.STATIC, + getProgram(), + Faces.createRectangle( + getProgram(), + getTexture(c), + Colors.WHITE, + Vectors.ZERO_3, + new Vec3(getWidth(c), 0, 0), + new Vec3(0, getHeight(), 0), + false + ) ); } - + private class DynamicText implements Renderable, Drawer { - + private final Supplier supplier; private final int style; private final float align; private final float maxWidth; private final Vec4 color; - - private final Renderable unitLine = new Shape(Usage.STATIC, getProgram(), Faces.createRectangle( - getProgram(), null, Vectors.UNIT_4, Vectors.ZERO_3, new Vec3(1, 0, 0), new Vec3(0, 1, 0), false - )); - + + private final Renderable unitLine = new Shape( + Usage.STATIC, + getProgram(), + Faces.createRectangle( + getProgram(), + null, + Vectors.UNIT_4, + Vectors.ZERO_3, + new Vec3(1, 0, 0), + new Vec3(0, 1, 0), + false + ) + ); + private class DynamicWorkspace extends Workspace { private ShapeRenderHelper renderer; - + @Override public void reset() { super.reset(); renderer = null; } } - + private final DynamicWorkspace workspace = new DynamicWorkspace(); public DynamicText( - Supplier supplier, - int style, float align, float maxWidth, Vec4 color + Supplier supplier, + int style, + float align, + float maxWidth, + Vec4 color ) { this.supplier = supplier; this.style = style; @@ -170,12 +207,12 @@ public abstract class SpriteTypeface extends Typeface { @Override public void render(ShapeRenderHelper renderer) { CharSequence text = supplier.get(); - + renderer.pushTransform().translate(0, +getInterlineBuffer(), 0); - + workspace.renderer = renderer; draw(text, this, workspace, style, align, maxWidth, color); - + renderer.popTransform(); } @@ -187,11 +224,11 @@ public abstract class SpriteTypeface extends Typeface { } return shape; } - + /* * Drawer methods */ - + @Override public void drawChar(char c, Vec4 color, Mat4 transform) { workspace.renderer.pushTransform().mul(transform); @@ -200,7 +237,7 @@ public abstract class SpriteTypeface extends Typeface { workspace.renderer.popColorMultiplier(); workspace.renderer.popTransform(); } - + @Override public void drawRectangle(Vec2 size, Vec4 color, Mat4 transform) { workspace.renderer.pushTransform().mul(transform).scale(size.x, size.y, 1); @@ -211,23 +248,23 @@ public abstract class SpriteTypeface extends Typeface { } } - + /* * Assembly */ - + private class StaticDrawer implements Drawer { - + private class SDWorkspace extends SpriteTypeface.Workspace { - + private final Collection faces = new ArrayList<>(); - + private final Vec3 origin = new Vec3(); private final Vec3 width = new Vec3(); private final Vec3 height = new Vec3(); - + } - + public final SDWorkspace workspace = new SDWorkspace(); @Override @@ -235,7 +272,7 @@ public abstract class SpriteTypeface extends Typeface { workspace.origin.set(0, 0, 0); workspace.width.set(getWidth(c), 0, 0); workspace.height.set(0, getHeight(), 0); - + drawFace(getTexture(c), color, transform); } @@ -244,310 +281,343 @@ public abstract class SpriteTypeface extends Typeface { workspace.origin.set(0, 0, 0); workspace.width.set(size.x, 0, 0); workspace.height.set(0, size.y, 0); - + drawFace(null, color, transform); } - + private void drawFace(Texture texture, Vec4 color, Mat4 transform) { - + workspace.width.add(workspace.origin); workspace.height.add(workspace.origin); - + VectorUtil.applyMat4(workspace.origin, transform); VectorUtil.applyMat4(workspace.width, transform); VectorUtil.applyMat4(workspace.height, transform); - + workspace.width.sub(workspace.origin); workspace.height.sub(workspace.origin); - - workspace.faces.add(Faces.createRectangle( + + workspace.faces.add( + Faces.createRectangle( getProgram(), - texture, color, - workspace.origin, workspace.width, workspace.height, + texture, + color, + workspace.origin, + workspace.width, + workspace.height, false - )); - } - - public Renderable assemble() { - return new Shape( - Usage.STATIC, getProgram(), - workspace.faces.toArray(new Face[workspace.faces.size()]) + ) ); } - + + public Renderable assemble() { + return new Shape( + Usage.STATIC, + getProgram(), + workspace.faces.toArray(new Face[workspace.faces.size()]) + ); + } + } - + @Override public Renderable assembleStatic(CharSequence text, int style, float align, float maxWidth, Vec4 color) { StaticDrawer drawer = new StaticDrawer(); draw(text, drawer, drawer.workspace, style, align, maxWidth, color); return drawer.assemble(); } - + @Override - public Renderable assembleDynamic(Supplier supplier, int style, float align, float maxWidth, Vec4 color) { + public Renderable assembleDynamic( + Supplier supplier, + int style, + float align, + float maxWidth, + Vec4 color + ) { return new DynamicText(supplier, style, align, maxWidth, color); } - + /* * Drawing algorithm */ - + protected static class Workspace { private CharSequence text; private int fromIndex; private int toIndex; - + private final Vec2i totalSize = new Vec2i(); - + private float currentWidth; - + private float align; private float maxWidth; - + private final TIntStack styles = new TIntArrayStack(16); private final StashingStack colors = new StashingStack<>(16, Vec4::new); - + private final Vec2 pos = new Vec2(); - + private final StashingStack transforms = new StashingStack<>(16, Mat4::new); - + public Workspace() { reset(); } - + private int pushStyle(int diff) { int current = styles.peek(); - + if ((diff & 0x10000000) != 0) { current &= diff; } else { current |= diff; } - + styles.push(current); return current; } - + private Vec4 pushColor() { - if (colors.isEmpty()) return colors.push(); - + if (colors.isEmpty()) + return colors.push(); + Vec4 previous = colors.peek(); return colors.push().set(previous); } - + private Mat4 pushTransform() { - if (transforms.isEmpty()) return transforms.push(); - + if (transforms.isEmpty()) + return transforms.push(); + Mat4 previous = transforms.peek(); return transforms.push().set(previous); } - + private Mat4 pushDrawerTransform() { Mat4 previous = transforms.peek(); return transforms.push().identity().translate(pos.x, pos.y, 0).mul(previous); } - + public void reset() { text = null; fromIndex = 0; toIndex = 0; align = Float.NaN; maxWidth = -1; - + totalSize.set(0, 0); - + styles.clear(); colors.removeAll(); - + pos.set(0, 0); - + transforms.removeAll(); transforms.push().identity(); } } - + protected interface Drawer { void drawChar(char c, Vec4 color, Mat4 transform); + void drawRectangle(Vec2 size, Vec4 color, Mat4 transform); } - + protected void draw( - CharSequence text, Drawer drawer, Workspace workspace, - int style, float align, float maxWidth, Vec4 color + CharSequence text, + Drawer drawer, + Workspace workspace, + int style, + float align, + float maxWidth, + Vec4 color ) { workspace.text = text; workspace.toIndex = text.length(); workspace.align = align; workspace.maxWidth = maxWidth; - + getSize(text, style, align, maxWidth, workspace.totalSize); - + workspace.styles.push(style); workspace.colors.push().set(color); - + drawSpan(drawer, workspace); workspace.reset(); } - + private void drawSpan(Drawer drawer, Workspace workspace) { workspace.currentWidth = getBoldOffset(); workspace.pos.y = workspace.totalSize.y - getHeight(); - + int from = workspace.fromIndex; int to = workspace.toIndex; - + for (int i = from; i < to; ++i) { char c = workspace.text.charAt(i); float charWidth = getWidth(c); - + if (c == '\n' || workspace.currentWidth + charWidth > workspace.maxWidth) { - + workspace.pos.x = getStartX(workspace); workspace.toIndex = i; drawLine(drawer, workspace); - + workspace.pos.y -= getHeight() + getInterlineBuffer(); workspace.currentWidth = getThickness(); - + workspace.fromIndex = i; - if (c == '\n') workspace.fromIndex++; // Skip c + if (c == '\n') + workspace.fromIndex++; // Skip c } - - if (c != '\n') workspace.currentWidth += charWidth; + + if (c != '\n') + workspace.currentWidth += charWidth; } workspace.pos.x = getStartX(workspace); workspace.toIndex = to; drawLine(drawer, workspace); - + workspace.currentWidth = Float.NaN; workspace.fromIndex = from; } - + private float getStartX(Workspace w) { return w.align * (w.totalSize.x - w.currentWidth); } - + private static final float[][] OUTLINE_DIRECTIONS = new float[][] { - {0, 1}, {1, 0}, {-1, 0}, {0, -1} + { 0, 1 }, + { 1, 0 }, + { -1, 0 }, + { 0, -1 } }; - + private void drawLine(Drawer drawer, Workspace workspace) { int style = workspace.styles.peek(); - - // workspace.pos.x will be restored to this value iff drawLine is invoked multiple times + + // workspace.pos.x will be restored to this value iff drawLine is + // invoked multiple times float xToRestore = workspace.pos.x; - + if (style == Style.PLAIN) { - + drawPlainLine(drawer, workspace); - + } else if (Style.isOutlined(style)) { workspace.pushStyle(~Style.OUTLINED); - - drawLine(drawer, workspace); // TODO figure out why placing this line after drawing outline reverses order of display (should be the opposite) + + drawLine(drawer, workspace); // TODO figure out why placing this + // line after drawing outline + // reverses order of display (should + // be the opposite) workspace.pos.x = xToRestore; - + Colors.multiplyRGB(workspace.pushColor(), getShadowColorMultiplier()); - + for (int i = 0; i < OUTLINE_DIRECTIONS.length; ++i) { float[] direction = OUTLINE_DIRECTIONS[i]; - + workspace.pushTransform().translate(direction[0] * getThickness(), direction[1] * getThickness(), 0); drawLine(drawer, workspace); workspace.transforms.pop(); - - if (i != OUTLINE_DIRECTIONS.length - 1) workspace.pos.x = xToRestore; + + if (i != OUTLINE_DIRECTIONS.length - 1) + workspace.pos.x = xToRestore; } - + workspace.colors.pop(); - + workspace.styles.pop(); - + } else if (Style.hasShadow(style)) { workspace.pushStyle(~Style.SHADOW); - - drawLine(drawer, workspace); // TODO figure out why placing this line after drawing shadow reverses order of display (should be the opposite) + + drawLine(drawer, workspace); // TODO figure out why placing this + // line after drawing shadow + // reverses order of display (should + // be the opposite) workspace.pos.x = xToRestore; - + Colors.multiplyRGB(workspace.pushColor(), getShadowColorMultiplier()); workspace.pushTransform().translate(getShadowOffset()); drawLine(drawer, workspace); workspace.colors.pop(); workspace.transforms.pop(); - + workspace.styles.pop(); - + } else if (Style.isBold(style)) { - + workspace.pushStyle(~Style.BOLD); - + workspace.pushTransform().translate(getBoldOffset(), 0, 0); drawLine(drawer, workspace); workspace.pos.x = xToRestore; workspace.transforms.pop(); - + drawLine(drawer, workspace); - + workspace.styles.pop(); - + } else if (Style.isItalic(style)) { - + workspace.pushStyle(~Style.ITALIC); // Push shear of Oy along Ox workspace.pushTransform().m10 = getItalicsSlant(); - + drawLine(drawer, workspace); - + workspace.transforms.pop(); workspace.styles.pop(); - + } else if (Style.isStrikethru(style)) { - + workspace.pushStyle(~Style.STRIKETHRU); drawDecorativeLine(drawer, workspace, (getHeight() - getThickness()) / 2f); drawLine(drawer, workspace); workspace.styles.pop(); - + } else if (Style.isUnderlined(style)) { - + workspace.pushStyle(~Style.UNDERLINED); drawDecorativeLine(drawer, workspace, 0); drawLine(drawer, workspace); workspace.styles.pop(); - + } else { throw new IllegalArgumentException( - "Style contains unknown flags " + Integer.toBinaryString((style & ~( - Style.BOLD | Style.ITALIC | Style.SHADOW | Style.STRIKETHRU | Style.UNDERLINED - ))) + "Style contains unknown flags " + Integer.toBinaryString( + (style & ~(Style.BOLD | Style.ITALIC | Style.SHADOW | Style.STRIKETHRU | Style.UNDERLINED)) + ) ); } } private void drawDecorativeLine(Drawer drawer, Workspace workspace, float height) { Vec2 size = Vectors.grab2(); - + size.x = workspace.currentWidth; size.y = getDecorativeLineThickness(); - + drawer.drawRectangle(size, workspace.colors.getHead(), workspace.pushDrawerTransform().translate(0, height, 0)); workspace.transforms.pop(); - + Vectors.release(size); } private void drawPlainLine(Drawer drawer, Workspace workspace) { for (int index = workspace.fromIndex; index < workspace.toIndex; ++index) { char c = workspace.text.charAt(index); - + drawer.drawChar(c, workspace.colors.getHead(), workspace.pushDrawerTransform()); workspace.transforms.pop(); - + workspace.pos.x += getWidth(c); } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java index 2bb7379..3be5ebb 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typeface.java @@ -1,97 +1,126 @@ -package ru.windcorp.progressia.client.graphics.font; - -import java.util.function.Supplier; - -import glm.vec._2.i.Vec2i; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.util.Named; -import ru.windcorp.progressia.common.util.Vectors; - -public abstract class Typeface extends Named { - - public static class Style { - public static final int - BOLD = 1 << 0, - ITALIC = 1 << 1, - UNDERLINED = 1 << 2, - STRIKETHRU = 1 << 3, - SHADOW = 1 << 4, - OUTLINED = 1 << 5; - - public static final int PLAIN = 0; - - public static boolean isBold(int style) { - return (style & BOLD) != 0; - } - - public static boolean isItalic(int style) { - return (style & ITALIC) != 0; - } - - public static boolean isUnderlined(int style) { - return (style & UNDERLINED) != 0; - } - - public static boolean isStrikethru(int style) { - return (style & STRIKETHRU) != 0; - } - - public static boolean hasShadow(int style) { - return (style & SHADOW) != 0; - } - - public static boolean isOutlined(int style) { - return (style & OUTLINED) != 0; - } - } - - public static final float ALIGN_LEFT = 0; - public static final float ALIGN_RIGHT = 1; - public static final float ALIGN_CENTER = 0.5f; - - public Typeface(String name) { - super(name); - } - - public abstract Renderable assembleStatic( - CharSequence chars, - int style, float align, float maxWidth, Vec4 color - ); - - public abstract Renderable assembleDynamic( - Supplier supplier, - int style, float align, float maxWidth, Vec4 color - ); - - public int getWidth( - CharSequence chars, int style, - float align, float maxWidth - ) { - Vec2i v = Vectors.grab2i(); - v = getSize(chars, style, align, maxWidth, v); - Vectors.release(v); - return v.x; - } - - public int getHeight( - CharSequence chars, int style, - float align, float maxWidth - ) { - Vec2i v = Vectors.grab2i(); - v = getSize(chars, style, align, maxWidth, v); - Vectors.release(v); - return v.y; - } - - public abstract int getLineHeight(); - - public abstract Vec2i getSize( - CharSequence chars, int style, - float align, float maxWidth, - Vec2i result - ); - - public abstract boolean supports(char c); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.font; + +import java.util.function.Supplier; + +import glm.vec._2.i.Vec2i; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.common.util.Named; +import ru.windcorp.progressia.common.util.Vectors; + +public abstract class Typeface extends Named { + + public static class Style { + public static final int BOLD = 1 << 0, + ITALIC = 1 << 1, + UNDERLINED = 1 << 2, + STRIKETHRU = 1 << 3, + SHADOW = 1 << 4, + OUTLINED = 1 << 5; + + public static final int PLAIN = 0; + + public static boolean isBold(int style) { + return (style & BOLD) != 0; + } + + public static boolean isItalic(int style) { + return (style & ITALIC) != 0; + } + + public static boolean isUnderlined(int style) { + return (style & UNDERLINED) != 0; + } + + public static boolean isStrikethru(int style) { + return (style & STRIKETHRU) != 0; + } + + public static boolean hasShadow(int style) { + return (style & SHADOW) != 0; + } + + public static boolean isOutlined(int style) { + return (style & OUTLINED) != 0; + } + } + + public static final float ALIGN_LEFT = 0; + public static final float ALIGN_RIGHT = 1; + public static final float ALIGN_CENTER = 0.5f; + + public Typeface(String name) { + super(name); + } + + public abstract Renderable assembleStatic( + CharSequence chars, + int style, + float align, + float maxWidth, + Vec4 color + ); + + public abstract Renderable assembleDynamic( + Supplier supplier, + int style, + float align, + float maxWidth, + Vec4 color + ); + + public int getWidth( + CharSequence chars, + int style, + float align, + float maxWidth + ) { + Vec2i v = Vectors.grab2i(); + v = getSize(chars, style, align, maxWidth, v); + Vectors.release(v); + return v.x; + } + + public int getHeight( + CharSequence chars, + int style, + float align, + float maxWidth + ) { + Vec2i v = Vectors.grab2i(); + v = getSize(chars, style, align, maxWidth, v); + Vectors.release(v); + return v.y; + } + + public abstract int getLineHeight(); + + public abstract Vec2i getSize( + CharSequence chars, + int style, + float align, + float maxWidth, + Vec2i result + ); + + public abstract boolean supports(char c); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java index e4d6076..ed9c7c4 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/font/Typefaces.java @@ -1,15 +1,33 @@ -package ru.windcorp.progressia.client.graphics.font; - -public class Typefaces { - - private static Typeface def = null; - - public static Typeface getDefault() { - return def; - } - - public static void setDefault(Typeface def) { - Typefaces.def = def; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.font; + +public class Typefaces { + + private static Typeface def = null; + + public static Typeface getDefault() { + return def; + } + + public static void setDefault(Typeface def) { + Typefaces.def = def; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java index e1034be..4a131d8 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Component.java @@ -1,661 +1,665 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.lwjgl.glfw.GLFW; - -import com.google.common.eventbus.EventBus; - -import glm.vec._2.i.Vec2i; -import ru.windcorp.progressia.client.graphics.backend.InputTracker; -import ru.windcorp.progressia.client.graphics.flat.RenderTarget; -import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent; -import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent; -import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent; -import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; -import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent; -import ru.windcorp.progressia.client.graphics.input.InputEvent; -import ru.windcorp.progressia.client.graphics.input.KeyEvent; -import ru.windcorp.progressia.client.graphics.input.bus.Input; -import ru.windcorp.progressia.client.graphics.input.bus.InputBus; -import ru.windcorp.progressia.client.graphics.input.bus.InputListener; -import ru.windcorp.progressia.common.util.Named; -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.util.crash.ReportingEventBus; - -public class Component extends Named { - - private final List children = Collections.synchronizedList(new CopyOnWriteArrayList<>()); - - private Component parent = null; - - private EventBus eventBus = null; - private InputBus inputBus = null; - - private int x, y; - private int width, height; - - private boolean valid = false; - - private Vec2i preferredSize = null; - - private Object layoutHint = null; - private Layout layout = null; - - private boolean isFocusable = false; - private boolean isFocused = false; - - private boolean isHovered = false; - - public Component(String name) { - super(name); - } - - public Component getParent() { - return parent; - } - - protected void setParent(Component parent) { - if (this.parent != parent) { - Component previousParent = this.parent; - this.parent = parent; - - dispatchEvent(new ParentChangedEvent(this, previousParent, parent)); - } - } - - public List getChildren() { - return children; - } - - public Component getChild(int index) { - synchronized (getChildren()) { - if (index < 0 || index >= getChildren().size()) - return null; - return getChildren().get(index); - } - } - - public int getChildIndex(Component child) { - return getChildren().indexOf(child); - } - - public int getOwnIndex() { - Component parent = getParent(); - if (parent != null) { - return parent.getChildIndex(this); - } - - return -1; - } - - public void moveChild(Component child, int newIndex) { - if (newIndex == -1) - newIndex = getChildren().size() - 1; - - if (getChildren().remove(child)) { - getChildren().add(newIndex, child); - invalidate(); - } - } - - public void moveSelf(int newIndex) { - Component parent = getParent(); - if (parent != null) { - parent.moveChild(this, newIndex); - } - } - - public Component addChild(Component child, int index) { - if (index == -1) - index = getChildren().size(); - - invalidate(); - getChildren().add(index, child); - child.setParent(this); - - dispatchEvent(new ChildAddedEvent(this, child)); - - return this; - } - - public Component addChild(Component child) { - return addChild(child, -1); - } - - public Component removeChild(Component child) { - if (!getChildren().contains(child)) { - return this; - } - - if (child.isFocused()) { - child.focusNext(); - } - - invalidate(); - getChildren().remove(child); - child.setParent(null); - - dispatchEvent(new ChildRemovedEvent(this, child)); - - return this; - } - - public synchronized int getX() { - return x; - } - - public synchronized int getY() { - return y; - } - - public synchronized Component setPosition(int x, int y) { - invalidate(); - this.x = x; - this.y = y; - return this; - } - - public synchronized int getWidth() { - return width; - } - - public synchronized int getHeight() { - return height; - } - - public synchronized Component setSize(int width, int height) { - invalidate(); - this.width = width; - this.height = height; - return this; - } - - public Component setSize(Vec2i size) { - return setSize(size.x, size.y); - } - - public synchronized Component setBounds(int x, int y, int width, int height) { - setPosition(x, y); - setSize(width, height); - return this; - } - - public Component setBounds(int x, int y, Vec2i size) { - return setBounds(x, y, size.x, size.y); - } - - public boolean isValid() { - return valid; - } - - public synchronized void invalidate() { - valid = false; - getChildren().forEach(child -> child.invalidate()); - } - - public synchronized void validate() { - Component parent = getParent(); - invalidate(); - - if (parent == null) { - layoutSelf(); - } else { - parent.validate(); - } - } - - protected synchronized void layoutSelf() { - try { - if (getLayout() != null) { - getLayout().layout(this); - } - - getChildren().forEach(child -> { - child.layoutSelf(); - }); - - valid = true; - } catch (Exception e) { - throw CrashReports.report(e, "Could not layout Component %s", this); - } - } - - public synchronized Vec2i getPreferredSize() { - if (preferredSize != null) { - return preferredSize; - } - - if (getLayout() != null) { - try { - return getLayout().calculatePreferredSize(this); - } catch (Exception e) { - throw CrashReports.report(e, "Could not calculate preferred size for Component %s", this); - } - } - - return new Vec2i(0, 0); - } - - public synchronized Component setPreferredSize(Vec2i preferredSize) { - this.preferredSize = preferredSize; - return this; - } - - public Component setPreferredSize(int width, int height) { - return setPreferredSize(new Vec2i(width, height)); - } - - public Layout getLayout() { - return layout; - } - - public synchronized Component setLayout(Layout layout) { - invalidate(); - this.layout = layout; - return this; - } - - public Object getLayoutHint() { - return layoutHint; - } - - public Component setLayoutHint(Object hint) { - this.layoutHint = hint; - return this; - } - - public boolean isFocusable() { - return isFocusable; - } - - public Component setFocusable(boolean focusable) { - this.isFocusable = focusable; - return this; - } - - public boolean isFocused() { - return isFocused; - } - - protected synchronized void setFocused(boolean focus) { - if (focus != this.isFocused) { - dispatchEvent(new FocusEvent(this, focus)); - this.isFocused = focus; - } - } - - public Component takeFocus() { - if (isFocused()) { - return this; - } - - Component comp = this; - Component focused = null; - - while (comp != null) { - if ((focused = comp.findFocused()) != null) { - focused.setFocused(false); - setFocused(true); - return this; - } - - comp = comp.getParent(); - } - - setFocused(true); - return this; - } - - public void focusNext() { - Component component = this; - - while (true) { - - component = component.getNextFocusCandidate(true); - if (component == this) { - return; - } - - if (component.isFocusable()) { - setFocused(false); - component.setFocused(true); - return; - } - - } - } - - private Component getNextFocusCandidate(boolean canUseChildren) { - if (canUseChildren) - synchronized (getChildren()) { - if (!getChildren().isEmpty()) { - return getChild(0); - } - } - - Component parent = getParent(); - if (parent != null) { - synchronized (parent.getChildren()) { - int ownIndex = parent.getChildIndex(this); - if (ownIndex != parent.getChildren().size() - 1) { - return parent.getChild(ownIndex + 1); - } - } - - return parent.getNextFocusCandidate(false); - } - - return this; - } - - public void focusPrevious() { - Component component = this; - - while (true) { - - component = component.getPreviousFocusCandidate(); - if (component == this) { - return; - } - - if (component.isFocusable()) { - setFocused(false); - component.setFocused(true); - return; - } - - } - } - - private Component getPreviousFocusCandidate() { - Component parent = getParent(); - if (parent != null) { - synchronized (parent.getChildren()) { - int ownIndex = parent.getChildIndex(this); - if (ownIndex != 0) { - return parent.getChild(ownIndex - 1).getLastDeepChild(); - } - } - - return parent; - } - - return getLastDeepChild(); - } - - private Component getLastDeepChild() { - synchronized (getChildren()) { - if (!getChildren().isEmpty()) { - return getChild(getChildren().size() - 1).getLastDeepChild(); - } - - return this; - } - } - - public synchronized Component findFocused() { - if (isFocused()) { - return this; - } - - Component result; - - synchronized (getChildren()) { - for (Component c : getChildren()) { - result = c.findFocused(); - if (result != null) { - return result; - } - } - } - - return null; - } - - public boolean isHovered() { - return isHovered; - } - - protected void setHovered(boolean isHovered) { - if (this.isHovered != isHovered) { - this.isHovered = isHovered; - - if (!isHovered && !getChildren().isEmpty()) { - - getChildren().forEach(child -> { - if (child.isHovered()) { - child.setHovered(false); - return; - } - }); - } - - dispatchEvent(new HoverEvent(this, isHovered)); - } - } - - public void addListener(Object listener) { - if (eventBus == null) { - eventBus = ReportingEventBus.create(getName()); - } - - eventBus.register(listener); - } - - public void removeListener(Object listener) { - if (eventBus == null) - return; - eventBus.unregister(listener); - } - - public void dispatchEvent(Object event) { - if (eventBus == null) - return; - eventBus.post(event); - } - - public void addListener(Class type, boolean handlesConsumed, - InputListener listener) { - if (inputBus == null) { - inputBus = new InputBus(); - } - - inputBus.register(type, handlesConsumed, listener); - } - - public void addListener(Class type, InputListener listener) { - if (inputBus == null) { - inputBus = new InputBus(); - } - - inputBus.register(type, listener); - } - - public void removeListener(InputListener listener) { - if (inputBus != null) { - inputBus.unregister(listener); - } - } - - protected void handleInput(Input input) { - if (inputBus != null) { - inputBus.dispatch(input); - } - } - - public void dispatchInput(Input input) { - try { - switch (input.getTarget()) { - case FOCUSED: - dispatchInputToFocused(input); - break; - case HOVERED: - dispatchInputToHovered(input); - break; - case ALL: - default: - dispatchInputToAll(input); - break; - } - } catch (Exception e) { - throw CrashReports.report(e, "Could not dispatch input to Component %s", this); - } - } - - private void dispatchInputToFocused(Input input) { - Component c = findFocused(); - - if (c == null) - return; - if (attemptFocusTransfer(input, c)) - return; - - while (c != null) { - c.handleInput(input); - c = c.getParent(); - } - } - - private void dispatchInputToHovered(Input input) { - getChildren().forEach(child -> { - if (child.containsCursor()) { - child.setHovered(true); - - if (!input.isConsumed()) { - child.dispatchInput(input); - } - } else { - child.setHovered(false); - } - }); - - handleInput(input); - } - - private void dispatchInputToAll(Input input) { - getChildren().forEach(c -> c.dispatchInput(input)); - handleInput(input); - } - - private boolean attemptFocusTransfer(Input input, Component focused) { - if (input.isConsumed()) - return false; - if (!(input.getEvent() instanceof KeyEvent)) - return false; - - KeyEvent keyInput = (KeyEvent) input.getEvent(); - - if (keyInput.getKey() == GLFW.GLFW_KEY_TAB && !keyInput.isRelease()) { - input.consume(); - if (keyInput.hasShift()) { - focused.focusPrevious(); - } else { - focused.focusNext(); - } - return true; - } - - return false; - } - - public synchronized boolean contains(int x, int y) { - return x >= getX() && x < getX() + getWidth() && y >= getY() && y < getY() + getHeight(); - } - - public boolean containsCursor() { - return contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY()); - } - - public void requestReassembly() { - if (parent != null) { - parent.requestReassembly(); - } else { - handleReassemblyRequest(); - } - } - - protected void handleReassemblyRequest() { - // To be overridden - } - - protected synchronized final void assemble(RenderTarget target) { - if (width == 0 || height == 0) { - return; - } - - if (!isValid()) { - validate(); - } - - try { - assembleSelf(target); - } catch (Exception e) { - throw CrashReports.report(e, "Could not assemble Component %s", this); - } - - assembleChildren(target); - - try { - postAssembleSelf(target); - } catch (Exception e) { - throw CrashReports.report(e, "Post-assembly failed for Component %s", this); - } - } - - protected void assembleSelf(RenderTarget target) { - // To be overridden - } - - protected void postAssembleSelf(RenderTarget target) { - // To be overridden - } - - protected void assembleChildren(RenderTarget target) { - getChildren().forEach(child -> child.assemble(target)); - } - - // /** - // * Returns a component that displays this component in its center. - // * @return a {@link Aligner} initialized to center this component - // */ - // public Component center() { - // return new Aligner(this); - // } - // - // /** - // * Returns a component that aligns this component. - // * @return a {@link Aligner} initialized with this component - // */ - // public Component align(double x, double y) { - // return new Aligner(this, x, y); - // } - // - // /** - // * Returns a component that allows scrolling this component - // * @return a {@link Scroller} initialized with this component - // */ - // public Component scroller() { - // return new Scroller(this); - // } - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.lwjgl.glfw.GLFW; + +import com.google.common.eventbus.EventBus; + +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.backend.InputTracker; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent; +import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent; +import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent; +import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; +import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent; +import ru.windcorp.progressia.client.graphics.input.InputEvent; +import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.client.graphics.input.bus.InputBus; +import ru.windcorp.progressia.client.graphics.input.bus.InputListener; +import ru.windcorp.progressia.common.util.Named; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.util.crash.ReportingEventBus; + +public class Component extends Named { + + private final List children = Collections.synchronizedList(new CopyOnWriteArrayList<>()); + + private Component parent = null; + + private EventBus eventBus = null; + private InputBus inputBus = null; + + private int x, y; + private int width, height; + + private boolean valid = false; + + private Vec2i preferredSize = null; + + private Object layoutHint = null; + private Layout layout = null; + + private boolean isFocusable = false; + private boolean isFocused = false; + + private boolean isHovered = false; + + public Component(String name) { + super(name); + } + + public Component getParent() { + return parent; + } + + protected void setParent(Component parent) { + if (this.parent != parent) { + Component previousParent = this.parent; + this.parent = parent; + + dispatchEvent(new ParentChangedEvent(this, previousParent, parent)); + } + } + + public List getChildren() { + return children; + } + + public Component getChild(int index) { + synchronized (getChildren()) { + if (index < 0 || index >= getChildren().size()) + return null; + return getChildren().get(index); + } + } + + public int getChildIndex(Component child) { + return getChildren().indexOf(child); + } + + public int getOwnIndex() { + Component parent = getParent(); + if (parent != null) { + return parent.getChildIndex(this); + } + + return -1; + } + + public void moveChild(Component child, int newIndex) { + if (newIndex == -1) + newIndex = getChildren().size() - 1; + + if (getChildren().remove(child)) { + getChildren().add(newIndex, child); + invalidate(); + } + } + + public void moveSelf(int newIndex) { + Component parent = getParent(); + if (parent != null) { + parent.moveChild(this, newIndex); + } + } + + public Component addChild(Component child, int index) { + if (index == -1) + index = getChildren().size(); + + invalidate(); + getChildren().add(index, child); + child.setParent(this); + + dispatchEvent(new ChildAddedEvent(this, child)); + + return this; + } + + public Component addChild(Component child) { + return addChild(child, -1); + } + + public Component removeChild(Component child) { + if (!getChildren().contains(child)) { + return this; + } + + if (child.isFocused()) { + child.focusNext(); + } + + invalidate(); + getChildren().remove(child); + child.setParent(null); + + dispatchEvent(new ChildRemovedEvent(this, child)); + + return this; + } + + public synchronized int getX() { + return x; + } + + public synchronized int getY() { + return y; + } + + public synchronized Component setPosition(int x, int y) { + invalidate(); + this.x = x; + this.y = y; + return this; + } + + public synchronized int getWidth() { + return width; + } + + public synchronized int getHeight() { + return height; + } + + public synchronized Component setSize(int width, int height) { + invalidate(); + this.width = width; + this.height = height; + return this; + } + + public Component setSize(Vec2i size) { + return setSize(size.x, size.y); + } + + public synchronized Component setBounds(int x, int y, int width, int height) { + setPosition(x, y); + setSize(width, height); + return this; + } + + public Component setBounds(int x, int y, Vec2i size) { + return setBounds(x, y, size.x, size.y); + } + + public boolean isValid() { + return valid; + } + + public synchronized void invalidate() { + valid = false; + getChildren().forEach(child -> child.invalidate()); + } + + public synchronized void validate() { + Component parent = getParent(); + invalidate(); + + if (parent == null) { + layoutSelf(); + } else { + parent.validate(); + } + } + + protected synchronized void layoutSelf() { + try { + if (getLayout() != null) { + getLayout().layout(this); + } + + getChildren().forEach(child -> { + child.layoutSelf(); + }); + + valid = true; + } catch (Exception e) { + throw CrashReports.report(e, "Could not layout Component %s", this); + } + } + + public synchronized Vec2i getPreferredSize() { + if (preferredSize != null) { + return preferredSize; + } + + if (getLayout() != null) { + try { + return getLayout().calculatePreferredSize(this); + } catch (Exception e) { + throw CrashReports.report(e, "Could not calculate preferred size for Component %s", this); + } + } + + return new Vec2i(0, 0); + } + + public synchronized Component setPreferredSize(Vec2i preferredSize) { + this.preferredSize = preferredSize; + return this; + } + + public Component setPreferredSize(int width, int height) { + return setPreferredSize(new Vec2i(width, height)); + } + + public Layout getLayout() { + return layout; + } + + public synchronized Component setLayout(Layout layout) { + invalidate(); + this.layout = layout; + return this; + } + + public Object getLayoutHint() { + return layoutHint; + } + + public Component setLayoutHint(Object hint) { + this.layoutHint = hint; + return this; + } + + public boolean isFocusable() { + return isFocusable; + } + + public Component setFocusable(boolean focusable) { + this.isFocusable = focusable; + return this; + } + + public boolean isFocused() { + return isFocused; + } + + protected synchronized void setFocused(boolean focus) { + if (focus != this.isFocused) { + dispatchEvent(new FocusEvent(this, focus)); + this.isFocused = focus; + } + } + + public Component takeFocus() { + if (isFocused()) { + return this; + } + + Component comp = this; + Component focused = null; + + while (comp != null) { + if ((focused = comp.findFocused()) != null) { + focused.setFocused(false); + setFocused(true); + return this; + } + + comp = comp.getParent(); + } + + setFocused(true); + return this; + } + + public void focusNext() { + Component component = this; + + while (true) { + + component = component.getNextFocusCandidate(true); + if (component == this) { + return; + } + + if (component.isFocusable()) { + setFocused(false); + component.setFocused(true); + return; + } + + } + } + + private Component getNextFocusCandidate(boolean canUseChildren) { + if (canUseChildren) + synchronized (getChildren()) { + if (!getChildren().isEmpty()) { + return getChild(0); + } + } + + Component parent = getParent(); + if (parent != null) { + synchronized (parent.getChildren()) { + int ownIndex = parent.getChildIndex(this); + if (ownIndex != parent.getChildren().size() - 1) { + return parent.getChild(ownIndex + 1); + } + } + + return parent.getNextFocusCandidate(false); + } + + return this; + } + + public void focusPrevious() { + Component component = this; + + while (true) { + + component = component.getPreviousFocusCandidate(); + if (component == this) { + return; + } + + if (component.isFocusable()) { + setFocused(false); + component.setFocused(true); + return; + } + + } + } + + private Component getPreviousFocusCandidate() { + Component parent = getParent(); + if (parent != null) { + synchronized (parent.getChildren()) { + int ownIndex = parent.getChildIndex(this); + if (ownIndex != 0) { + return parent.getChild(ownIndex - 1).getLastDeepChild(); + } + } + + return parent; + } + + return getLastDeepChild(); + } + + private Component getLastDeepChild() { + synchronized (getChildren()) { + if (!getChildren().isEmpty()) { + return getChild(getChildren().size() - 1).getLastDeepChild(); + } + + return this; + } + } + + public synchronized Component findFocused() { + if (isFocused()) { + return this; + } + + Component result; + + synchronized (getChildren()) { + for (Component c : getChildren()) { + result = c.findFocused(); + if (result != null) { + return result; + } + } + } + + return null; + } + + public boolean isHovered() { + return isHovered; + } + + protected void setHovered(boolean isHovered) { + if (this.isHovered != isHovered) { + this.isHovered = isHovered; + + if (!isHovered && !getChildren().isEmpty()) { + + getChildren().forEach(child -> { + if (child.isHovered()) { + child.setHovered(false); + return; + } + }); + } + + dispatchEvent(new HoverEvent(this, isHovered)); + } + } + + public void addListener(Object listener) { + if (eventBus == null) { + eventBus = ReportingEventBus.create(getName()); + } + + eventBus.register(listener); + } + + public void removeListener(Object listener) { + if (eventBus == null) + return; + eventBus.unregister(listener); + } + + public void dispatchEvent(Object event) { + if (eventBus == null) + return; + eventBus.post(event); + } + + public void addListener( + Class type, + boolean handlesConsumed, + InputListener listener + ) { + if (inputBus == null) { + inputBus = new InputBus(); + } + + inputBus.register(type, handlesConsumed, listener); + } + + public void addListener(Class type, InputListener listener) { + if (inputBus == null) { + inputBus = new InputBus(); + } + + inputBus.register(type, listener); + } + + public void removeListener(InputListener listener) { + if (inputBus != null) { + inputBus.unregister(listener); + } + } + + protected void handleInput(Input input) { + if (inputBus != null) { + inputBus.dispatch(input); + } + } + + public void dispatchInput(Input input) { + try { + switch (input.getTarget()) { + case FOCUSED: + dispatchInputToFocused(input); + break; + case HOVERED: + dispatchInputToHovered(input); + break; + case ALL: + default: + dispatchInputToAll(input); + break; + } + } catch (Exception e) { + throw CrashReports.report(e, "Could not dispatch input to Component %s", this); + } + } + + private void dispatchInputToFocused(Input input) { + Component c = findFocused(); + + if (c == null) + return; + if (attemptFocusTransfer(input, c)) + return; + + while (c != null) { + c.handleInput(input); + c = c.getParent(); + } + } + + private void dispatchInputToHovered(Input input) { + getChildren().forEach(child -> { + if (child.containsCursor()) { + child.setHovered(true); + + if (!input.isConsumed()) { + child.dispatchInput(input); + } + } else { + child.setHovered(false); + } + }); + + handleInput(input); + } + + private void dispatchInputToAll(Input input) { + getChildren().forEach(c -> c.dispatchInput(input)); + handleInput(input); + } + + private boolean attemptFocusTransfer(Input input, Component focused) { + if (input.isConsumed()) + return false; + if (!(input.getEvent() instanceof KeyEvent)) + return false; + + KeyEvent keyInput = (KeyEvent) input.getEvent(); + + if (keyInput.getKey() == GLFW.GLFW_KEY_TAB && !keyInput.isRelease()) { + input.consume(); + if (keyInput.hasShift()) { + focused.focusPrevious(); + } else { + focused.focusNext(); + } + return true; + } + + return false; + } + + public synchronized boolean contains(int x, int y) { + return x >= getX() && x < getX() + getWidth() && y >= getY() && y < getY() + getHeight(); + } + + public boolean containsCursor() { + return contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY()); + } + + public void requestReassembly() { + if (parent != null) { + parent.requestReassembly(); + } else { + handleReassemblyRequest(); + } + } + + protected void handleReassemblyRequest() { + // To be overridden + } + + protected synchronized final void assemble(RenderTarget target) { + if (width == 0 || height == 0) { + return; + } + + if (!isValid()) { + validate(); + } + + try { + assembleSelf(target); + } catch (Exception e) { + throw CrashReports.report(e, "Could not assemble Component %s", this); + } + + assembleChildren(target); + + try { + postAssembleSelf(target); + } catch (Exception e) { + throw CrashReports.report(e, "Post-assembly failed for Component %s", this); + } + } + + protected void assembleSelf(RenderTarget target) { + // To be overridden + } + + protected void postAssembleSelf(RenderTarget target) { + // To be overridden + } + + protected void assembleChildren(RenderTarget target) { + getChildren().forEach(child -> child.assemble(target)); + } + + // /** + // * Returns a component that displays this component in its center. + // * @return a {@link Aligner} initialized to center this component + // */ + // public Component center() { + // return new Aligner(this); + // } + // + // /** + // * Returns a component that aligns this component. + // * @return a {@link Aligner} initialized with this component + // */ + // public Component align(double x, double y) { + // return new Aligner(this, x, y); + // } + // + // /** + // * Returns a component that allows scrolling this component + // * @return a {@link Scroller} initialized with this component + // */ + // public Component scroller() { + // return new Scroller(this); + // } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java index 02c61dc..bddad7b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/DynamicLabel.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.gui; import glm.mat._4.Mat4; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java index 90aa557..2e0981c 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/GUILayer.java @@ -1,60 +1,61 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui; - -import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; -import ru.windcorp.progressia.client.graphics.flat.RenderTarget; -import ru.windcorp.progressia.client.graphics.input.bus.Input; - -public abstract class GUILayer extends AssembledFlatLayer { - - private final Component root = new Component("Root") { - @Override - protected void handleReassemblyRequest() { - GUILayer.this.invalidate(); - } - }; - - public GUILayer(String name, Layout layout) { - super(name); - getRoot().setLayout(layout); - } - - public Component getRoot() { - return root; - } - - @Override - protected void assemble(RenderTarget target) { - getRoot().setBounds(0, 0, getWidth(), getHeight()); - getRoot().invalidate(); - getRoot().assemble(target); - } - - @Override - protected void handleInput(Input input) { - getRoot().dispatchInput(input); - } - - @Override - public void invalidate() { - super.invalidate(); - getRoot().invalidate(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui; + +import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.input.bus.Input; + +public abstract class GUILayer extends AssembledFlatLayer { + + private final Component root = new Component("Root") { + @Override + protected void handleReassemblyRequest() { + GUILayer.this.invalidate(); + } + }; + + public GUILayer(String name, Layout layout) { + super(name); + getRoot().setLayout(layout); + } + + public Component getRoot() { + return root; + } + + @Override + protected void assemble(RenderTarget target) { + getRoot().setBounds(0, 0, getWidth(), getHeight()); + getRoot().invalidate(); + getRoot().assemble(target); + } + + @Override + protected void handleInput(Input input) { + getRoot().dispatchInput(input); + } + + @Override + public void invalidate() { + super.invalidate(); + getRoot().invalidate(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java index 6a3157b..f7dbe33 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Label.java @@ -1,90 +1,111 @@ -package ru.windcorp.progressia.client.graphics.gui; - -import glm.mat._4.Mat4; -import glm.vec._2.i.Vec2i; -import ru.windcorp.progressia.client.graphics.flat.RenderTarget; -import ru.windcorp.progressia.client.graphics.font.Font; -import ru.windcorp.progressia.client.localization.MutableString; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; - -public class Label extends Component { - - private Font font; - private String currentText; - private Vec2i currentSize; - private Supplier contents; - - private MutableString.Listener mutableStringListener = null; - - private float maxWidth = Float.POSITIVE_INFINITY; - - public Label(String name, Font font, Supplier contents) { - super(name); - this.font = font; - this.contents = contents; - update(); - } - - public Label(String name, Font font, String contents) { - this(name, font, () -> contents); - } - - public Label(String name, Font font, MutableString contents) { - // Not the most elegant solution - - this(name, font, () -> { - contents.update(); - return contents.get(); - }); - - AtomicBoolean isUpdating = new AtomicBoolean(); - - this.mutableStringListener = () -> { - if (isUpdating.compareAndSet(false, true)) { - this.update(); - isUpdating.set(false); - } - }; - contents.addListener(mutableStringListener); - } - - public void update() { - currentText = contents.get(); - currentSize = font.getSize(currentText, maxWidth, null).mul(2); - requestReassembly(); - } - - @Override - public synchronized Vec2i getPreferredSize() { - return currentSize; - } - - public Font getFont() { - return font; - } - - public String getCurrentText() { - return currentText; - } - - public Supplier getContentSupplier() { - return contents; - } - - @Override - protected void assembleSelf(RenderTarget target) { - float startX = getX() + font.getAlign() * (getWidth() - currentSize.x); - - target.pushTransform( - new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf is this magic <--- - .scale(2) - ); - - target.addCustomRenderer(font.assemble(currentText, maxWidth)); - - target.popTransform(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui; + +import glm.mat._4.Mat4; +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.flat.RenderTarget; +import ru.windcorp.progressia.client.graphics.font.Font; +import ru.windcorp.progressia.client.localization.MutableString; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; + +public class Label extends Component { + + private Font font; + private String currentText; + private Vec2i currentSize; + private Supplier contents; + + private MutableString.Listener mutableStringListener = null; + + private float maxWidth = Float.POSITIVE_INFINITY; + + public Label(String name, Font font, Supplier contents) { + super(name); + this.font = font; + this.contents = contents; + update(); + } + + public Label(String name, Font font, String contents) { + this(name, font, () -> contents); + } + + public Label(String name, Font font, MutableString contents) { + // Not the most elegant solution + + this(name, font, () -> { + contents.update(); + return contents.get(); + }); + + AtomicBoolean isUpdating = new AtomicBoolean(); + + this.mutableStringListener = () -> { + if (isUpdating.compareAndSet(false, true)) { + this.update(); + isUpdating.set(false); + } + }; + contents.addListener(mutableStringListener); + } + + public void update() { + currentText = contents.get(); + currentSize = font.getSize(currentText, maxWidth, null).mul(2); + requestReassembly(); + } + + @Override + public synchronized Vec2i getPreferredSize() { + return currentSize; + } + + public Font getFont() { + return font; + } + + public String getCurrentText() { + return currentText; + } + + public Supplier getContentSupplier() { + return contents; + } + + @Override + protected void assembleSelf(RenderTarget target) { + float startX = getX() + font.getAlign() * (getWidth() - currentSize.x); + + target.pushTransform( + new Mat4().identity().translate(startX, getY(), -1000) // TODO wtf + // is this + // magic + // <--- + .scale(2) + ); + + target.addCustomRenderer(font.assemble(currentText, maxWidth)); + + target.popTransform(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java index d7003eb..8d5d84f 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Layout.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui; - -import glm.vec._2.i.Vec2i; - -public interface Layout { - - public void layout(Component c); - - public Vec2i calculatePreferredSize(Component c); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui; + +import glm.vec._2.i.Vec2i; + +public interface Layout { + + public void layout(Component c); + + public Vec2i calculatePreferredSize(Component c); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java index 18c4172..88e10f1 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/Panel.java @@ -1,10 +1,28 @@ -package ru.windcorp.progressia.client.graphics.gui; - -public class Panel extends Component { - - public Panel(String name, Layout layout) { - super(name); - setLayout(layout); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui; + +public class Panel extends Component { + + public Panel(String name, Layout layout) { + super(name); + setLayout(layout); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java index f84d7df..f1611fe 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildAddedEvent.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public class ChildAddedEvent extends ChildEvent { - - public ChildAddedEvent(Component component, Component child) { - super(component, child); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class ChildAddedEvent extends ChildEvent { + + public ChildAddedEvent(Component component, Component child) { + super(component, child); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java index 08b2ba3..a27cf79 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildEvent.java @@ -1,35 +1,36 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public abstract class ChildEvent extends HierarchyEvent { - - private final Component child; - - public ChildEvent(Component component, Component child) { - super(component); - this.child = child; - } - - public Component getChild() { - return child; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public abstract class ChildEvent extends HierarchyEvent { + + private final Component child; + + public ChildEvent(Component component, Component child) { + super(component); + this.child = child; + } + + public Component getChild() { + return child; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java index 8fe35d7..897d787 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ChildRemovedEvent.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public class ChildRemovedEvent extends ChildEvent { - - public ChildRemovedEvent(Component component, Component child) { - super(component, child); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class ChildRemovedEvent extends ChildEvent { + + public ChildRemovedEvent(Component component, Component child) { + super(component, child); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java index 54a4edb..b1d1175 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ComponentEvent.java @@ -1,34 +1,35 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public abstract class ComponentEvent { - - private final Component component; - - public ComponentEvent(Component component) { - this.component = component; - } - - public Component getComponent() { - return component; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public abstract class ComponentEvent { + + private final Component component; + + public ComponentEvent(Component component) { + this.component = component; + } + + public Component getComponent() { + return component; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java index ec523eb..ff859f3 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/FocusEvent.java @@ -1,35 +1,36 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public class FocusEvent extends ComponentEvent { - - private final boolean newState; - - public FocusEvent(Component component, boolean newState) { - super(component); - this.newState = newState; - } - - public boolean getNewState() { - return newState; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class FocusEvent extends ComponentEvent { + + private final boolean newState; + + public FocusEvent(Component component, boolean newState) { + super(component); + this.newState = newState; + } + + public boolean getNewState() { + return newState; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java index 943bec6..d3a4984 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HierarchyEvent.java @@ -1,28 +1,29 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public abstract class HierarchyEvent extends ComponentEvent { - - public HierarchyEvent(Component component) { - super(component); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public abstract class HierarchyEvent extends ComponentEvent { + + public HierarchyEvent(Component component) { + super(component); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java index 98df19c..b1d63ad 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/HoverEvent.java @@ -1,39 +1,40 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public class HoverEvent extends ComponentEvent { - - private final boolean newState; - - public HoverEvent(Component component, boolean newState) { - super(component); - this.newState = newState; - } - - public boolean isNowHovered() { - return newState; - } - - public boolean wasHovered() { - return !isNowHovered(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class HoverEvent extends ComponentEvent { + + private final boolean newState; + + public HoverEvent(Component component, boolean newState) { + super(component); + this.newState = newState; + } + + public boolean isNowHovered() { + return newState; + } + + public boolean wasHovered() { + return !isNowHovered(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java index 89c1a57..a7d9d40 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/event/ParentChangedEvent.java @@ -1,41 +1,42 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.gui.event; - -import ru.windcorp.progressia.client.graphics.gui.Component; - -public class ParentChangedEvent extends HierarchyEvent { - - private final Component previousParent; - private final Component newParent; - - public ParentChangedEvent(Component component, Component previousParent, Component newParent) { - super(component); - this.previousParent = previousParent; - this.newParent = newParent; - } - - public Component getPreviousParent() { - return previousParent; - } - - public Component getNewParent() { - return newParent; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.gui.event; + +import ru.windcorp.progressia.client.graphics.gui.Component; + +public class ParentChangedEvent extends HierarchyEvent { + + private final Component previousParent; + private final Component newParent; + + public ParentChangedEvent(Component component, Component previousParent, Component newParent) { + super(component); + this.previousParent = previousParent; + this.newParent = newParent; + } + + public Component getPreviousParent() { + return previousParent; + } + + public Component getNewParent() { + return newParent; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java index d458ae5..d521914 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutAlign.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -28,17 +29,17 @@ public class LayoutAlign implements Layout { private final int margin; private double alignX, alignY; - + public LayoutAlign(double alignX, double alignY, int margin) { this.alignX = alignX; this.alignY = alignY; this.margin = margin; } - + public LayoutAlign(int margin) { this(0.5, 0.5, margin); } - + public LayoutAlign() { this(1); } @@ -46,43 +47,43 @@ public class LayoutAlign implements Layout { @Override public void layout(Component c) { c.getChildren().forEach(child -> { - + Vec2i size = child.getPreferredSize(); - + int cWidth = c.getWidth() - 2 * margin; int cHeight = c.getHeight() - 2 * margin; - + size.x = min(size.x, cWidth); size.y = min(size.y, cHeight); - + child.setBounds( - c.getX() + - (int) ((cWidth - size.x) * alignX) + margin, - c.getY() + - (int) ((cHeight - size.y) * alignY) + margin, - size + c.getX() + + (int) ((cWidth - size.x) * alignX) + margin, + c.getY() + + (int) ((cHeight - size.y) * alignY) + margin, + size ); - + }); } @Override public Vec2i calculatePreferredSize(Component c) { Vec2i result = new Vec2i(0, 0); - + c.getChildren().stream() .map(child -> child.getPreferredSize()) .forEach(size -> { result.x = max(size.x, result.x); result.y = max(size.y, result.y); }); - + result.x += 2 * margin; result.y += 2 * margin; - + return result; } - + @Override public String toString() { return getClass().getSimpleName() + "(" + margin + ")"; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java index 704a63c..3e271de 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderHorizontal.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -24,17 +25,17 @@ import ru.windcorp.progressia.client.graphics.gui.Component; import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutBorderHorizontal implements Layout { - + public static final String CENTER = "Center", - LEFT = "Left", - RIGHT = "Right"; - + LEFT = "Left", + RIGHT = "Right"; + private final int margin; - + public LayoutBorderHorizontal(int margin) { this.margin = margin; } - + public LayoutBorderHorizontal() { this(1); } @@ -42,38 +43,41 @@ public class LayoutBorderHorizontal implements Layout { @Override public void layout(Component c) { int left = 0, right = 0; - + Vec2i childSize; - - synchronized (c.getChildren()) { + + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { if (child.getLayoutHint() == LEFT) { childSize = child.getPreferredSize(); left = childSize.x + margin; child.setBounds( - c.getX(), - c.getY(), - childSize.x, - c.getHeight()); + c.getX(), + c.getY(), + childSize.x, + c.getHeight() + ); } else if (child.getLayoutHint() == RIGHT) { childSize = child.getPreferredSize(); right = childSize.x + margin; child.setBounds( - c.getX() + c.getWidth() - childSize.x, - c.getY(), - childSize.x, - c.getHeight()); + c.getX() + c.getWidth() - childSize.x, + c.getY(), + childSize.x, + c.getHeight() + ); } } - + for (Component child : c.getChildren()) { if (child.getLayoutHint() == CENTER) { child.setBounds( - c.getX() + left, - c.getY(), - c.getWidth() - left - right, - c.getHeight()); - + c.getX() + left, + c.getY(), + c.getWidth() - left - right, + c.getHeight() + ); + } } } @@ -83,14 +87,14 @@ public class LayoutBorderHorizontal implements Layout { public Vec2i calculatePreferredSize(Component c) { Vec2i result = new Vec2i(0, 0); int left = 0, right = 0; - + Vec2i childSize; - - synchronized (c.getChildren()) { + + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { childSize = child.getPreferredSize(); if (child.getLayoutHint() instanceof String) { - + if (child.getLayoutHint() == LEFT) { left = max(left, childSize.x + margin); result.y = max(result.y, childSize.y); @@ -100,7 +104,7 @@ public class LayoutBorderHorizontal implements Layout { result.y = max(result.y, childSize.y); continue; } - + } result.x = max(result.x, childSize.x); @@ -108,10 +112,10 @@ public class LayoutBorderHorizontal implements Layout { } } result.x += left + right; - + return result; } - + @Override public String toString() { return getClass().getSimpleName() + "(" + margin + ")"; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java index ba20156..0efcaa4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutBorderVertical.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -24,18 +25,17 @@ import ru.windcorp.progressia.client.graphics.gui.Component; import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutBorderVertical implements Layout { - - public static final String - CENTER = "Center", - UP = "Up", - DOWN = "Down"; - + + public static final String CENTER = "Center", + UP = "Up", + DOWN = "Down"; + private final int margin; - + public LayoutBorderVertical(int margin) { this.margin = margin; } - + public LayoutBorderVertical() { this(1); } @@ -43,37 +43,41 @@ public class LayoutBorderVertical implements Layout { @Override public void layout(Component c) { int top = 0, bottom = 0; - + Vec2i childSize; - - synchronized (c.getChildren()) { + + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { if (child.getLayoutHint() == UP) { childSize = child.getPreferredSize(); top = childSize.y + margin; child.setBounds( - c.getX(), - c.getY(), - c.getWidth(), - childSize.y); + c.getX(), + c.getY(), + c.getWidth(), + childSize.y + ); } else if (child.getLayoutHint() == DOWN) { childSize = child.getPreferredSize(); bottom = childSize.y + margin; child.setBounds( - c.getX(), - c.getY() + c.getHeight() - childSize.y, - c.getWidth(), childSize.y); + c.getX(), + c.getY() + c.getHeight() - childSize.y, + c.getWidth(), + childSize.y + ); } } - + for (Component child : c.getChildren()) { if (child.getLayoutHint() == CENTER) { child.setBounds( - c.getX(), - c.getY() + top, - c.getWidth(), - c.getHeight() - top - bottom); - + c.getX(), + c.getY() + top, + c.getWidth(), + c.getHeight() - top - bottom + ); + } } } @@ -83,14 +87,14 @@ public class LayoutBorderVertical implements Layout { public Vec2i calculatePreferredSize(Component c) { Vec2i result = new Vec2i(0, 0); int up = 0, down = 0; - + Vec2i childSize; - - synchronized (c.getChildren()) { + + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { childSize = child.getPreferredSize(); if (child.getLayoutHint() instanceof String) { - + if (child.getLayoutHint() == UP) { up = max(up, childSize.y + margin); result.x = max(result.x, childSize.x); @@ -100,7 +104,7 @@ public class LayoutBorderVertical implements Layout { result.x = max(result.x, childSize.x); continue; } - + } result.x = max(result.x, childSize.x); @@ -108,10 +112,10 @@ public class LayoutBorderVertical implements Layout { } } result.y += up + down; - + return result; } - + @Override public String toString() { return getClass().getSimpleName() + "(" + margin + ")"; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java index 9726e53..fa2cdfe 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutGrid.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import java.util.Arrays; @@ -24,14 +25,15 @@ import ru.windcorp.progressia.client.graphics.gui.Component; import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutGrid implements Layout { - + private class GridDimensions { int[] columns = new int[4]; int[] rows = new int[10]; boolean isSummed = false; - + void add(int column, int row, Vec2i size) { - if (isSummed) throw new IllegalStateException("Already summed"); + if (isSummed) + throw new IllegalStateException("Already summed"); columns = update(columns, column, size.x); rows = update(rows, row, size.y); } @@ -40,85 +42,86 @@ public class LayoutGrid implements Layout { if (array.length <= index) { array = Arrays.copyOf(array, ((index / 10) + 1) * 10); } - + if (array[index] < value) { array[index] = value; } - + return array; } - + Vec2i getBounds() { - if (isSummed) throw new IllegalStateException("Already summed"); - Vec2i result = new Vec2i(2*margin - gap, 2*margin - gap); - + if (isSummed) + throw new IllegalStateException("Already summed"); + Vec2i result = new Vec2i(2 * margin - gap, 2 * margin - gap); + for (int i = 0; i < columns.length; ++i) { if (columns[i] != 0) { result.x += columns[i] + gap; } } - + for (int i = 0; i < rows.length; ++i) { if (rows[i] != 0) { result.y += rows[i] + gap; } } - + return result; } - + void sum() { - if (isSummed) throw new IllegalStateException("Already summed"); - + if (isSummed) + throw new IllegalStateException("Already summed"); + int accumulator = margin; int buffer; - + for (int i = 0; i < columns.length; ++i) { buffer = columns[i]; columns[i] = accumulator; accumulator += buffer + gap; } - + accumulator = margin; - + for (int i = 0; i < rows.length; ++i) { buffer = rows[i]; rows[i] = accumulator; accumulator += buffer + gap; } - + isSummed = true; } - + void setBounds(int column, int row, Component child, Component parent) { - if (!isSummed) throw new IllegalStateException("Not summed yet"); - + if (!isSummed) + throw new IllegalStateException("Not summed yet"); + child.setBounds( - parent.getX() + columns[column], - parent.getY() + rows[row], - - (column != (columns.length-1) ? - (columns[column + 1] - columns[column] - gap) : - (parent.getWidth() - margin - columns[column])), - - (row != (rows.length-1) ? - (rows[row + 1] - rows[row] - gap) : - (parent.getHeight() - margin - rows[row])) - ); + parent.getX() + columns[column], + parent.getY() + rows[row], + + (column != (columns.length - 1) ? (columns[column + 1] - columns[column] - gap) + : (parent.getWidth() - margin - columns[column])), + + (row != (rows.length - 1) ? (rows[row + 1] - rows[row] - gap) + : (parent.getHeight() - margin - rows[row])) + ); } } private int gap, margin; - + public LayoutGrid(int margin, int gap) { this.margin = margin; this.gap = gap; } - + public LayoutGrid(int gap) { this(gap, gap); } - + public LayoutGrid() { this(1); } @@ -128,7 +131,7 @@ public class LayoutGrid implements Layout { synchronized (c.getChildren()) { GridDimensions grid = calculateGrid(c); grid.sum(); - + int[] coords; for (Component child : c.getChildren()) { coords = (int[]) child.getLayoutHint(); @@ -143,16 +146,16 @@ public class LayoutGrid implements Layout { return calculateGrid(c).getBounds(); } } - + private GridDimensions calculateGrid(Component parent) { GridDimensions result = new GridDimensions(); int[] coords; - + for (Component child : parent.getChildren()) { coords = (int[]) child.getLayoutHint(); result.add(coords[0], coords[1], child.getPreferredSize()); } - + return result; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java index 1f3aa2e..85c37fa 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutHorizontal.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -24,18 +25,18 @@ import ru.windcorp.progressia.client.graphics.gui.Component; import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutHorizontal implements Layout { - + private final int margin, gap; public LayoutHorizontal(int margin, int gap) { this.margin = margin; this.gap = gap; } - + public LayoutHorizontal(int gap) { this(gap, gap); } - + public LayoutHorizontal() { this(1); } @@ -44,16 +45,16 @@ public class LayoutHorizontal implements Layout { public void layout(Component c) { int x = c.getX() + margin, y = c.getY() + margin; - + int width; - + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { - + width = child.getPreferredSize().x; child.setBounds(x, y, width, c.getHeight() - 2 * margin); x += gap + width; - + } } } @@ -62,26 +63,26 @@ public class LayoutHorizontal implements Layout { public Vec2i calculatePreferredSize(Component c) { Vec2i size = new Vec2i(0, 0); Vec2i childPreferredSize; - + synchronized (c.getChildren()) { for (int i = 0; i < c.getChildren().size(); ++i) { childPreferredSize = c.getChild(i).getPreferredSize(); - + if (i > 0) { size.x += gap; } - + size.y = max(size.y, childPreferredSize.y); size.x += childPreferredSize.x; } } - + size.x += 2 * margin; size.y += 2 * margin; - + return size; } - + @Override public String toString() { return getClass().getSimpleName() + "(" + gap + ", " + margin + ")"; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java index 83e331f..6e48d69 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/layout/LayoutVertical.java @@ -1,6 +1,6 @@ -/******************************************************************************* +/* * Progressia - * Copyright (C) 2020 Wind Corporation + * Copyright (C) 2020-2021 Wind Corporation and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,8 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - *******************************************************************************/ + */ + package ru.windcorp.progressia.client.graphics.gui.layout; import static java.lang.Math.max; @@ -24,18 +25,18 @@ import ru.windcorp.progressia.client.graphics.gui.Component; import ru.windcorp.progressia.client.graphics.gui.Layout; public class LayoutVertical implements Layout { - + private final int margin, gap; public LayoutVertical(int margin, int gap) { this.margin = margin; this.gap = gap; } - + public LayoutVertical(int gap) { this(gap, gap); } - + public LayoutVertical() { this(1); } @@ -44,14 +45,14 @@ public class LayoutVertical implements Layout { public void layout(Component c) { int x = c.getX() + margin, y = c.getY() + c.getHeight(); - + synchronized (c.getChildren()) { for (Component child : c.getChildren()) { - + int height = child.getPreferredSize().y; y -= gap + height; child.setBounds(x, y, c.getWidth() - 2 * margin, height); - + } } } @@ -60,26 +61,26 @@ public class LayoutVertical implements Layout { public Vec2i calculatePreferredSize(Component c) { Vec2i size = new Vec2i(0, 0); Vec2i childPreferredSize; - + synchronized (c.getChildren()) { for (int i = 0; i < c.getChildren().size(); ++i) { childPreferredSize = c.getChild(i).getPreferredSize(); - + if (i > 0) { size.y += gap; } - + size.x = max(size.x, childPreferredSize.x); size.y += childPreferredSize.y; } } - + size.x += 2 * margin; size.y += 2 * margin; - + return size; } - + @Override public String toString() { return getClass().getSimpleName() + "(" + gap + ", " + margin + ")"; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java index be832e4..43dd965 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorEvent.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import glm.vec._2.d.Vec2d; -import ru.windcorp.progressia.client.graphics.backend.InputTracker; - -public abstract class CursorEvent extends InputEvent { - - public CursorEvent(double time) { - super(time); - } - - public double getCursorX() { - return InputTracker.getCursorX(); - } - - public double getCursorY() { - return InputTracker.getCursorY(); - } - - public Vec2d getCursorPosition() { - return InputTracker.getCursorPosition(); - } - - @Override - public abstract CursorEvent snapshot(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import glm.vec._2.d.Vec2d; +import ru.windcorp.progressia.client.graphics.backend.InputTracker; + +public abstract class CursorEvent extends InputEvent { + + public CursorEvent(double time) { + super(time); + } + + public double getCursorX() { + return InputTracker.getCursorX(); + } + + public double getCursorY() { + return InputTracker.getCursorY(); + } + + public Vec2d getCursorPosition() { + return InputTracker.getCursorPosition(); + } + + @Override + public abstract CursorEvent snapshot(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java index 95e881f..c87fc62 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/CursorMoveEvent.java @@ -1,116 +1,117 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import glm.vec._2.Vec2; -import glm.vec._2.d.Vec2d; - -public class CursorMoveEvent extends CursorEvent { - - private final Vec2d newPosition = new Vec2d(); - - protected CursorMoveEvent(double newX, double newY, double time) { - super(time); - newPosition.set(newX, newY); - } - - protected CursorMoveEvent(Vec2d newPos, double time) { - this(newPos.x, newPos.y, time); - } - - @Override - public double getCursorX() { - return getCursorPosition().x; - } - - @Override - public double getCursorY() { - return getCursorPosition().y; - } - - @Override - public Vec2d getCursorPosition() { - return getNewPosition(); - } - - public double getNewX() { - return getNewPosition().x; - } - - public double getNewY() { - return getNewPosition().y; - } - - public Vec2d getNewPosition() { - return newPosition; - } - - public double getPreviousX() { - return getPreviousPosition().x; - } - - public double getPreviousY() { - return getPreviousPosition().y; - } - - public Vec2d getPreviousPosition() { - return super.getCursorPosition(); - } - - public double getChangeX() { - return getNewX() - getPreviousX(); - } - - public double getChangeY() { - return getNewY() - getPreviousY(); - } - - public Vec2 getChange(Vec2 result) { - return result.set(getChangeX(), getChangeY()); - } - - @Override - public CursorMoveEvent snapshot() { - return new StaticMouseMoveEvent( - getPreviousPosition(), - getNewPosition(), - getTime() - ); - } - - private class StaticMouseMoveEvent extends CursorMoveEvent { - - private final Vec2d previousPosition = new Vec2d(); - - public StaticMouseMoveEvent( - Vec2d previousPosition, - Vec2d newPosition, - double time - ) { - super(newPosition, time); - this.previousPosition.set(previousPosition.x, previousPosition.y); - } - - @Override - public Vec2d getPreviousPosition() { - return previousPosition; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import glm.vec._2.Vec2; +import glm.vec._2.d.Vec2d; + +public class CursorMoveEvent extends CursorEvent { + + private final Vec2d newPosition = new Vec2d(); + + protected CursorMoveEvent(double newX, double newY, double time) { + super(time); + newPosition.set(newX, newY); + } + + protected CursorMoveEvent(Vec2d newPos, double time) { + this(newPos.x, newPos.y, time); + } + + @Override + public double getCursorX() { + return getCursorPosition().x; + } + + @Override + public double getCursorY() { + return getCursorPosition().y; + } + + @Override + public Vec2d getCursorPosition() { + return getNewPosition(); + } + + public double getNewX() { + return getNewPosition().x; + } + + public double getNewY() { + return getNewPosition().y; + } + + public Vec2d getNewPosition() { + return newPosition; + } + + public double getPreviousX() { + return getPreviousPosition().x; + } + + public double getPreviousY() { + return getPreviousPosition().y; + } + + public Vec2d getPreviousPosition() { + return super.getCursorPosition(); + } + + public double getChangeX() { + return getNewX() - getPreviousX(); + } + + public double getChangeY() { + return getNewY() - getPreviousY(); + } + + public Vec2 getChange(Vec2 result) { + return result.set(getChangeX(), getChangeY()); + } + + @Override + public CursorMoveEvent snapshot() { + return new StaticMouseMoveEvent( + getPreviousPosition(), + getNewPosition(), + getTime() + ); + } + + private class StaticMouseMoveEvent extends CursorMoveEvent { + + private final Vec2d previousPosition = new Vec2d(); + + public StaticMouseMoveEvent( + Vec2d previousPosition, + Vec2d newPosition, + double time + ) { + super(newPosition, time); + this.previousPosition.set(previousPosition.x, previousPosition.y); + } + + @Override + public Vec2d getPreviousPosition() { + return previousPosition; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java index dd9da64..5589158 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/FrameResizeEvent.java @@ -1,85 +1,86 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import glm.vec._2.i.Vec2i; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; - -public class FrameResizeEvent extends InputEvent { - - private final Vec2i newSize = new Vec2i(); - - protected FrameResizeEvent(int newWidth, int newHeight, double time) { - super(time); - this.newSize.set(newWidth, newHeight); - } - - protected FrameResizeEvent(Vec2i newSize, double time) { - this(newSize.x, newSize.y, time); - } - - public int getNewWidth() { - return getNewSize().x; - } - - public int getNewHeight() { - return getNewSize().y; - } - - public Vec2i getNewSize() { - return newSize; - } - - public int getPreviousWidth() { - return getPreviousSize().x; - } - - public int getPreviousHeight() { - return getPreviousSize().y; - } - - public Vec2i getPreviousSize() { - return GraphicsInterface.getFrameSize(); - } - - @Override - public FrameResizeEvent snapshot() { - return new StaticFrameResizeEvent(getNewSize(), getPreviousSize(), getTime()); - } - - private static class StaticFrameResizeEvent extends FrameResizeEvent { - - private final Vec2i previousSize; - - public StaticFrameResizeEvent( - Vec2i newSize, - Vec2i previousSize, - double time - ) { - super(newSize, time); - this.previousSize = previousSize; - } - - @Override - public Vec2i getPreviousSize() { - return previousSize; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import glm.vec._2.i.Vec2i; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; + +public class FrameResizeEvent extends InputEvent { + + private final Vec2i newSize = new Vec2i(); + + protected FrameResizeEvent(int newWidth, int newHeight, double time) { + super(time); + this.newSize.set(newWidth, newHeight); + } + + protected FrameResizeEvent(Vec2i newSize, double time) { + this(newSize.x, newSize.y, time); + } + + public int getNewWidth() { + return getNewSize().x; + } + + public int getNewHeight() { + return getNewSize().y; + } + + public Vec2i getNewSize() { + return newSize; + } + + public int getPreviousWidth() { + return getPreviousSize().x; + } + + public int getPreviousHeight() { + return getPreviousSize().y; + } + + public Vec2i getPreviousSize() { + return GraphicsInterface.getFrameSize(); + } + + @Override + public FrameResizeEvent snapshot() { + return new StaticFrameResizeEvent(getNewSize(), getPreviousSize(), getTime()); + } + + private static class StaticFrameResizeEvent extends FrameResizeEvent { + + private final Vec2i previousSize; + + public StaticFrameResizeEvent( + Vec2i newSize, + Vec2i previousSize, + double time + ) { + super(newSize, time); + this.previousSize = previousSize; + } + + @Override + public Vec2i getPreviousSize() { + return previousSize; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java index 53dd23e..b0c2483 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/InputEvent.java @@ -1,38 +1,39 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -public abstract class InputEvent { - - private double time; - - public InputEvent(double time) { - this.time = time; - } - - protected void setTime(double time) { - this.time = time; - } - - public double getTime() { - return time; - } - - public abstract InputEvent snapshot(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +public abstract class InputEvent { + + private double time; + + public InputEvent(double time) { + this.time = time; + } + + protected void setTime(double time) { + this.time = time; + } + + public double getTime() { + return time; + } + + public abstract InputEvent snapshot(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java index 7088cfb..291b89e 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyEvent.java @@ -1,104 +1,109 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import org.lwjgl.glfw.GLFW; - -public class KeyEvent extends InputEvent { - - protected int key; - protected int scancode; - protected int action; - protected int mods; - - protected KeyEvent( - int key, int scancode, int action, int mods, double time - ) { - super(time); - this.key = key; - this.scancode = scancode; - this.action = action; - this.mods = mods; - } - - public int getKey() { - return key; - } - - public int getScancode() { - return scancode; - } - - public int getAction() { - return action; - } - - public boolean isPress() { - return action == GLFW.GLFW_PRESS; - } - - public boolean isRelease() { - return action == GLFW.GLFW_RELEASE; - } - - public boolean isRepeat() { - return action == GLFW.GLFW_REPEAT; - } - - public boolean isLeftMouseButton() { - return key == GLFW.GLFW_MOUSE_BUTTON_LEFT; - } - - public boolean isRightMouseButton() { - return key == GLFW.GLFW_MOUSE_BUTTON_RIGHT; - } - - public boolean isMiddleMouseButton() { - return key == GLFW.GLFW_MOUSE_BUTTON_MIDDLE; - } - - public boolean isMouse() { - return Keys.isMouse(getKey()); - } - - public int getMods() { - return mods; - } - - public boolean hasShift() { - return (getMods() & GLFW.GLFW_MOD_SHIFT) != 0; - } - - public boolean hasControl() { - return (getMods() & GLFW.GLFW_MOD_CONTROL) != 0; - } - - public boolean hasAlt() { - return (getMods() & GLFW.GLFW_MOD_ALT) != 0; - } - - public boolean hasSuper() { - return (getMods() & GLFW.GLFW_MOD_SUPER) != 0; - } - - @Override - public KeyEvent snapshot() { - return new KeyEvent(key, scancode, action, mods, getTime()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import org.lwjgl.glfw.GLFW; + +public class KeyEvent extends InputEvent { + + protected int key; + protected int scancode; + protected int action; + protected int mods; + + protected KeyEvent( + int key, + int scancode, + int action, + int mods, + double time + ) { + super(time); + this.key = key; + this.scancode = scancode; + this.action = action; + this.mods = mods; + } + + public int getKey() { + return key; + } + + public int getScancode() { + return scancode; + } + + public int getAction() { + return action; + } + + public boolean isPress() { + return action == GLFW.GLFW_PRESS; + } + + public boolean isRelease() { + return action == GLFW.GLFW_RELEASE; + } + + public boolean isRepeat() { + return action == GLFW.GLFW_REPEAT; + } + + public boolean isLeftMouseButton() { + return key == GLFW.GLFW_MOUSE_BUTTON_LEFT; + } + + public boolean isRightMouseButton() { + return key == GLFW.GLFW_MOUSE_BUTTON_RIGHT; + } + + public boolean isMiddleMouseButton() { + return key == GLFW.GLFW_MOUSE_BUTTON_MIDDLE; + } + + public boolean isMouse() { + return Keys.isMouse(getKey()); + } + + public int getMods() { + return mods; + } + + public boolean hasShift() { + return (getMods() & GLFW.GLFW_MOD_SHIFT) != 0; + } + + public boolean hasControl() { + return (getMods() & GLFW.GLFW_MOD_CONTROL) != 0; + } + + public boolean hasAlt() { + return (getMods() & GLFW.GLFW_MOD_ALT) != 0; + } + + public boolean hasSuper() { + return (getMods() & GLFW.GLFW_MOD_SUPER) != 0; + } + + @Override + public KeyEvent snapshot() { + return new KeyEvent(key, scancode, action, mods, getTime()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java index df6c7a8..6fedcd6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/KeyMatcher.java @@ -1,94 +1,98 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import java.util.function.Predicate; - -import org.lwjgl.glfw.GLFW; - -public class KeyMatcher { - - private final int key; - private final int mods; - - protected KeyMatcher(int key, int mods) { - this.key = key; - this.mods = mods; - } - - public boolean matches(KeyEvent event) { - if (!event.isPress()) return false; - if (event.getKey() != getKey()) return false; - if ((event.getMods() & getMods()) != getMods()) return false; - - return true; - } - - public int getKey() { - return key; - } - - public int getMods() { - return mods; - } - - public static KeyMatcher.Builder of(int key) { - return new KeyMatcher.Builder(key); - } - - public static class Builder { - - private final int key; - private int mods = 0; - - public Builder(int key) { - this.key = key; - } - - public Builder with(int modifier) { - this.mods += modifier; - return this; - } - - public Builder withShift() { - return with(GLFW.GLFW_MOD_SHIFT); - } - - public Builder withCtrl() { - return with(GLFW.GLFW_MOD_CONTROL); - } - - public Builder withAlt() { - return with(GLFW.GLFW_MOD_ALT); - } - - public Builder withSuper() { - return with(GLFW.GLFW_MOD_SUPER); - } - - public KeyMatcher build() { - return new KeyMatcher(key, mods); - } - - public Predicate matcher() { - return build()::matches; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import java.util.function.Predicate; + +import org.lwjgl.glfw.GLFW; + +public class KeyMatcher { + + private final int key; + private final int mods; + + protected KeyMatcher(int key, int mods) { + this.key = key; + this.mods = mods; + } + + public boolean matches(KeyEvent event) { + if (!event.isPress()) + return false; + if (event.getKey() != getKey()) + return false; + if ((event.getMods() & getMods()) != getMods()) + return false; + + return true; + } + + public int getKey() { + return key; + } + + public int getMods() { + return mods; + } + + public static KeyMatcher.Builder of(int key) { + return new KeyMatcher.Builder(key); + } + + public static class Builder { + + private final int key; + private int mods = 0; + + public Builder(int key) { + this.key = key; + } + + public Builder with(int modifier) { + this.mods += modifier; + return this; + } + + public Builder withShift() { + return with(GLFW.GLFW_MOD_SHIFT); + } + + public Builder withCtrl() { + return with(GLFW.GLFW_MOD_CONTROL); + } + + public Builder withAlt() { + return with(GLFW.GLFW_MOD_ALT); + } + + public Builder withSuper() { + return with(GLFW.GLFW_MOD_SUPER); + } + + public KeyMatcher build() { + return new KeyMatcher(key, mods); + } + + public Predicate matcher() { + return build()::matches; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java index f8e2dd9..3904f59 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/Keys.java @@ -1,141 +1,153 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import org.lwjgl.glfw.GLFW; - -import gnu.trove.map.TIntObjectMap; -import gnu.trove.map.TObjectIntMap; -import gnu.trove.map.hash.TIntObjectHashMap; -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.TIntSet; -import gnu.trove.set.hash.TIntHashSet; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Keys { - - private static final TIntObjectMap CODES_TO_NAMES = new TIntObjectHashMap<>(); - - private static final TObjectIntMap NAMES_TO_CODES = new TObjectIntHashMap<>(); - - private static final TIntSet MOUSE_BUTTONS = new TIntHashSet(); - - private static final String KEY_PREFIX = "GLFW_KEY_"; - private static final String MOUSE_BUTTON_PREFIX = "GLFW_MOUSE_BUTTON_"; - - private static final Set IGNORE_FIELDS = new HashSet<>( - Arrays.asList("GLFW_KEY_UNKNOWN", "GLFW_KEY_LAST", "GLFW_MOUSE_BUTTON_LAST", "GLFW_MOUSE_BUTTON_1", // Alias - // for - // LEFT - "GLFW_MOUSE_BUTTON_2", // Alias for RIGHT - "GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE - )); - - static { - initializeDictionary(); - } - - private static void initializeDictionary() { - try { - - for (Field field : GLFW.class.getFields()) { - if (!Modifier.isStatic(field.getModifiers())) - continue; - if (!Modifier.isFinal(field.getModifiers())) - continue; - - String name = field.getName(); - - if (!name.startsWith(KEY_PREFIX) && !name.startsWith(MOUSE_BUTTON_PREFIX)) - continue; - - if (IGNORE_FIELDS.contains(name)) - continue; - - addToDictionary(field); - } - - } catch (IllegalAccessException e) { - throw CrashReports.report(e, "Cannot access GLFW constants"); - } - } - - private static void addToDictionary(Field field) throws IllegalAccessException { - - int value = field.getInt(null); - String name = field.getName(); - - if (name.startsWith(KEY_PREFIX)) { - name = name.substring(KEY_PREFIX.length()); - } else if (name.startsWith(MOUSE_BUTTON_PREFIX)) { - name = "MOUSE_" + name.substring(MOUSE_BUTTON_PREFIX.length()); - MOUSE_BUTTONS.add(value); - } - - if (CODES_TO_NAMES.containsKey(value)) { - throw CrashReports.report(null, "Duplicate keys: %s and %s both map to %d(0x%s)", - CODES_TO_NAMES.get(value), name, value, Integer.toHexString(value)); - } - - CODES_TO_NAMES.put(value, name); - NAMES_TO_CODES.put(name, value); - } - - public static String getInternalName(int code) { - String result = CODES_TO_NAMES.get(code); - - if (result == null) { - return "UNKNOWN"; - } - - return result; - } - - public static String getDisplayName(int code) { - String name = getInternalName(code); - - if (name.startsWith("KP_")) { - name = "KEYPAD_" + name.substring("KP_".length()); - } - - name = Character.toTitleCase(name.charAt(0)) + name.substring(1).toLowerCase(); - - name = name.replace('_', ' '); - - return name; - } - - public static int getCode(String internalName) { - if (NAMES_TO_CODES.containsKey(internalName)) { - return -1; - } else { - return NAMES_TO_CODES.get(internalName); - } - } - - public static boolean isMouse(int code) { - return MOUSE_BUTTONS.contains(code); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.lwjgl.glfw.GLFW; + +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.TObjectIntMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.TIntSet; +import gnu.trove.set.hash.TIntHashSet; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Keys { + + private static final TIntObjectMap CODES_TO_NAMES = new TIntObjectHashMap<>(); + + private static final TObjectIntMap NAMES_TO_CODES = new TObjectIntHashMap<>(); + + private static final TIntSet MOUSE_BUTTONS = new TIntHashSet(); + + private static final String KEY_PREFIX = "GLFW_KEY_"; + private static final String MOUSE_BUTTON_PREFIX = "GLFW_MOUSE_BUTTON_"; + + private static final Set IGNORE_FIELDS = new HashSet<>( + Arrays.asList( + "GLFW_KEY_UNKNOWN", + "GLFW_KEY_LAST", + "GLFW_MOUSE_BUTTON_LAST", + "GLFW_MOUSE_BUTTON_1", // Alias + // for + // LEFT + "GLFW_MOUSE_BUTTON_2", // Alias for RIGHT + "GLFW_MOUSE_BUTTON_3" // Alias for MIDDLE + ) + ); + + static { + initializeDictionary(); + } + + private static void initializeDictionary() { + try { + + for (Field field : GLFW.class.getFields()) { + if (!Modifier.isStatic(field.getModifiers())) + continue; + if (!Modifier.isFinal(field.getModifiers())) + continue; + + String name = field.getName(); + + if (!name.startsWith(KEY_PREFIX) && !name.startsWith(MOUSE_BUTTON_PREFIX)) + continue; + + if (IGNORE_FIELDS.contains(name)) + continue; + + addToDictionary(field); + } + + } catch (IllegalAccessException e) { + throw CrashReports.report(e, "Cannot access GLFW constants"); + } + } + + private static void addToDictionary(Field field) throws IllegalAccessException { + + int value = field.getInt(null); + String name = field.getName(); + + if (name.startsWith(KEY_PREFIX)) { + name = name.substring(KEY_PREFIX.length()); + } else if (name.startsWith(MOUSE_BUTTON_PREFIX)) { + name = "MOUSE_" + name.substring(MOUSE_BUTTON_PREFIX.length()); + MOUSE_BUTTONS.add(value); + } + + if (CODES_TO_NAMES.containsKey(value)) { + throw CrashReports.report( + null, + "Duplicate keys: %s and %s both map to %d(0x%s)", + CODES_TO_NAMES.get(value), + name, + value, + Integer.toHexString(value) + ); + } + + CODES_TO_NAMES.put(value, name); + NAMES_TO_CODES.put(name, value); + } + + public static String getInternalName(int code) { + String result = CODES_TO_NAMES.get(code); + + if (result == null) { + return "UNKNOWN"; + } + + return result; + } + + public static String getDisplayName(int code) { + String name = getInternalName(code); + + if (name.startsWith("KP_")) { + name = "KEYPAD_" + name.substring("KP_".length()); + } + + name = Character.toTitleCase(name.charAt(0)) + name.substring(1).toLowerCase(); + + name = name.replace('_', ' '); + + return name; + } + + public static int getCode(String internalName) { + if (NAMES_TO_CODES.containsKey(internalName)) { + return -1; + } else { + return NAMES_TO_CODES.get(internalName); + } + } + + public static boolean isMouse(int code) { + return MOUSE_BUTTONS.contains(code); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java index 7714743..24938c3 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelEvent.java @@ -1,29 +1,30 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -public abstract class WheelEvent extends InputEvent { - - public WheelEvent(double time) { - super(time); - } - - @Override - public abstract WheelEvent snapshot(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +public abstract class WheelEvent extends InputEvent { + + public WheelEvent(double time) { + super(time); + } + + @Override + public abstract WheelEvent snapshot(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java index af61381..968ff64 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/WheelScrollEvent.java @@ -1,75 +1,76 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input; - -import glm.vec._2.d.Vec2d; - -public class WheelScrollEvent extends WheelEvent { - - private final Vec2d offset = new Vec2d(); - - protected WheelScrollEvent(double xOffset, double yOffset, double time) { - super(time); - this.offset.set(xOffset, yOffset); - } - - protected WheelScrollEvent(Vec2d offset, double time) { - this(offset.x, offset.y, time); - } - - public boolean isUp() { - return getY() > 0; - } - - public boolean isDown() { - return getY() < 0; - } - - public boolean isRight() { - return getX() > 0; - } - - public boolean isLeft() { - return getX() < 0; - } - - public boolean hasVerticalMovement() { - return getY() != 0; - } - - public boolean hasHorizontalMovement() { - return getX() != 0; - } - - public double getX() { - return getOffset().x; - } - - public double getY() { - return getOffset().y; - } - - public Vec2d getOffset() { - return offset; - } - - @Override - public WheelEvent snapshot() { - return new WheelScrollEvent(getOffset(), getTime()); - } -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input; + +import glm.vec._2.d.Vec2d; + +public class WheelScrollEvent extends WheelEvent { + + private final Vec2d offset = new Vec2d(); + + protected WheelScrollEvent(double xOffset, double yOffset, double time) { + super(time); + this.offset.set(xOffset, yOffset); + } + + protected WheelScrollEvent(Vec2d offset, double time) { + this(offset.x, offset.y, time); + } + + public boolean isUp() { + return getY() > 0; + } + + public boolean isDown() { + return getY() < 0; + } + + public boolean isRight() { + return getX() > 0; + } + + public boolean isLeft() { + return getX() < 0; + } + + public boolean hasVerticalMovement() { + return getY() != 0; + } + + public boolean hasHorizontalMovement() { + return getX() != 0; + } + + public double getX() { + return getOffset().x; + } + + public double getY() { + return getOffset().y; + } + + public Vec2d getOffset() { + return offset; + } + + @Override + public WheelEvent snapshot() { + return new WheelScrollEvent(getOffset(), getTime()); + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java index 2c8b2e6..1aad6bb 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/Input.java @@ -1,61 +1,62 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input.bus; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; - -public class Input { - - public static enum Target { - FOCUSED, HOVERED, ALL - } - - private InputEvent event; - - private boolean isConsumed; - - private Target target; - - protected void initialize(InputEvent event, Target target) { - this.event = event; - this.target = target; - - this.isConsumed = false; - } - - public InputEvent getEvent() { - return event; - } - - public boolean isConsumed() { - return isConsumed; - } - - public void setConsumed(boolean isConsumed) { - this.isConsumed = isConsumed; - } - - public void consume() { - setConsumed(true); - } - - public Target getTarget() { - return target; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input.bus; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; + +public class Input { + + public static enum Target { + FOCUSED, HOVERED, ALL + } + + private InputEvent event; + + private boolean isConsumed; + + private Target target; + + protected void initialize(InputEvent event, Target target) { + this.event = event; + this.target = target; + + this.isConsumed = false; + } + + public InputEvent getEvent() { + return event; + } + + public boolean isConsumed() { + return isConsumed; + } + + public void setConsumed(boolean isConsumed) { + this.isConsumed = isConsumed; + } + + public void consume() { + setConsumed(true); + } + + public Target getTarget() { + return target; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java index bf69898..a22a243 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputBus.java @@ -1,88 +1,88 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input.bus; - -import java.util.ArrayList; -import java.util.Collection; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; - -public class InputBus { - - private static class WrappedListener { - - private final Class type; - private final boolean handleConsumed; - private final InputListener listener; - - public WrappedListener( - Class type, - boolean handleConsumed, - InputListener listener - ) { - this.type = type; - this.handleConsumed = handleConsumed; - this.listener = listener; - } - - private boolean handles(Input input) { - return - (!input.isConsumed() || handleConsumed) && - type.isInstance(input.getEvent()); - } - - @SuppressWarnings("unchecked") - public void handle(Input input) { - if (handles(input)) { - boolean consumed = ((InputListener) listener) - .handle( - (InputEvent) type.cast(input.getEvent()) - ); - - input.setConsumed(consumed); - } - } - - } - - private final Collection listeners = new ArrayList<>(4); - - public void dispatch(Input input) { - listeners.forEach(l -> l.handle(input)); - } - - public void register( - Class type, - boolean handlesConsumed, - InputListener listener - ) { - listeners.add(new WrappedListener(type, handlesConsumed, listener)); - } - - public void register( - Class type, - InputListener listener - ) { - register(type, false, listener); - } - - public void unregister(InputListener listener) { - listeners.removeIf(l -> l.listener == listener); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input.bus; + +import java.util.ArrayList; +import java.util.Collection; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; + +public class InputBus { + + private static class WrappedListener { + + private final Class type; + private final boolean handleConsumed; + private final InputListener listener; + + public WrappedListener( + Class type, + boolean handleConsumed, + InputListener listener + ) { + this.type = type; + this.handleConsumed = handleConsumed; + this.listener = listener; + } + + private boolean handles(Input input) { + return (!input.isConsumed() || handleConsumed) && + type.isInstance(input.getEvent()); + } + + @SuppressWarnings("unchecked") + public void handle(Input input) { + if (handles(input)) { + boolean consumed = ((InputListener) listener) + .handle( + (InputEvent) type.cast(input.getEvent()) + ); + + input.setConsumed(consumed); + } + } + + } + + private final Collection listeners = new ArrayList<>(4); + + public void dispatch(Input input) { + listeners.forEach(l -> l.handle(input)); + } + + public void register( + Class type, + boolean handlesConsumed, + InputListener listener + ) { + listeners.add(new WrappedListener(type, handlesConsumed, listener)); + } + + public void register( + Class type, + InputListener listener + ) { + register(type, false, listener); + } + + public void unregister(InputListener listener) { + listeners.removeIf(l -> l.listener == listener); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java index 0661d92..0d68b5e 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/input/bus/InputListener.java @@ -1,27 +1,28 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.input.bus; - -import ru.windcorp.progressia.client.graphics.input.InputEvent; - -@FunctionalInterface -public interface InputListener { - - boolean handle(T event); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.input.bus; + +import ru.windcorp.progressia.client.graphics.input.InputEvent; + +@FunctionalInterface +public interface InputListener { + + boolean handle(T event); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java index 568adf3..3b929c0 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/BlockFaceVectors.java @@ -1,112 +1,128 @@ -package ru.windcorp.progressia.client.graphics.model; - -import static ru.windcorp.progressia.common.world.block.BlockFace.*; - -import com.google.common.collect.ImmutableMap; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.common.world.block.BlockFace; - -class BlockFaceVectors { - - private static BlockFaceVectors createInner(BlockFaceVectors outer) { - ImmutableMap.Builder originBuilder = - ImmutableMap.builder(); - - ImmutableMap.Builder widthBuilder = - ImmutableMap.builder(); - - ImmutableMap.Builder heightBuilder = - ImmutableMap.builder(); - - for (BlockFace face : getFaces()) { - Vec3 width = outer.getWidth(face); - Vec3 height = outer.getHeight(face); - - originBuilder.put(face, - new Vec3(outer.getOrigin(face)) - ); - - widthBuilder.put(face, new Vec3(width)); - heightBuilder.put(face, new Vec3(height)); - } - - return new BlockFaceVectors( - originBuilder.build(), - widthBuilder.build(), - heightBuilder.build() - ); - } - - private static final BlockFaceVectors OUTER; - private static final BlockFaceVectors INNER; - - static { - OUTER = new BlockFaceVectors( - ImmutableMap.builder() - - .put(TOP, new Vec3(-0.5f, +0.5f, +0.5f)) - .put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f)) - .put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f)) - .put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f)) - .put(WEST, new Vec3(+0.5f, +0.5f, -0.5f)) - .put(EAST, new Vec3(-0.5f, -0.5f, -0.5f)) - - .build(), - - ImmutableMap.builder() - - .put(TOP, new Vec3( 0, -1, 0)) - .put(BOTTOM, new Vec3( 0, +1, 0)) - .put(NORTH, new Vec3( 0, +1, 0)) - .put(SOUTH, new Vec3( 0, -1, 0)) - .put(WEST, new Vec3(-1, 0, 0)) - .put(EAST, new Vec3(+1, 0, 0)) - - .build(), - - ImmutableMap.builder() - - .put(TOP, new Vec3(+1, 0, 0)) - .put(BOTTOM, new Vec3(+1, 0, 0)) - .put(NORTH, new Vec3( 0, 0, +1)) - .put(SOUTH, new Vec3( 0, 0, +1)) - .put(WEST, new Vec3( 0, 0, +1)) - .put(EAST, new Vec3( 0, 0, +1)) - - .build() - ); - - INNER = createInner(OUTER); - } - - public static BlockFaceVectors get(boolean inner) { - return inner ? INNER : OUTER; - } - - private final ImmutableMap origins; - private final ImmutableMap widths; - private final ImmutableMap heights; - - public BlockFaceVectors( - ImmutableMap origins, - ImmutableMap widths, - ImmutableMap heights - ) { - this.origins = origins; - this.widths = widths; - this.heights = heights; - } - - public Vec3 getOrigin(BlockFace face) { - return origins.get(face); - } - - public Vec3 getWidth(BlockFace face) { - return widths.get(face); - } - - public Vec3 getHeight(BlockFace face) { - return heights.get(face); - } -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import static ru.windcorp.progressia.common.world.block.BlockFace.*; + +import com.google.common.collect.ImmutableMap; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.common.world.block.BlockFace; + +class BlockFaceVectors { + + private static BlockFaceVectors createInner(BlockFaceVectors outer) { + ImmutableMap.Builder originBuilder = ImmutableMap.builder(); + + ImmutableMap.Builder widthBuilder = ImmutableMap.builder(); + + ImmutableMap.Builder heightBuilder = ImmutableMap.builder(); + + for (BlockFace face : getFaces()) { + Vec3 width = outer.getWidth(face); + Vec3 height = outer.getHeight(face); + + originBuilder.put( + face, + new Vec3(outer.getOrigin(face)) + ); + + widthBuilder.put(face, new Vec3(width)); + heightBuilder.put(face, new Vec3(height)); + } + + return new BlockFaceVectors( + originBuilder.build(), + widthBuilder.build(), + heightBuilder.build() + ); + } + + private static final BlockFaceVectors OUTER; + private static final BlockFaceVectors INNER; + + static { + OUTER = new BlockFaceVectors( + ImmutableMap.builder() + + .put(TOP, new Vec3(-0.5f, +0.5f, +0.5f)) + .put(BOTTOM, new Vec3(-0.5f, -0.5f, -0.5f)) + .put(NORTH, new Vec3(+0.5f, -0.5f, -0.5f)) + .put(SOUTH, new Vec3(-0.5f, +0.5f, -0.5f)) + .put(WEST, new Vec3(+0.5f, +0.5f, -0.5f)) + .put(EAST, new Vec3(-0.5f, -0.5f, -0.5f)) + + .build(), + + ImmutableMap.builder() + + .put(TOP, new Vec3(0, -1, 0)) + .put(BOTTOM, new Vec3(0, +1, 0)) + .put(NORTH, new Vec3(0, +1, 0)) + .put(SOUTH, new Vec3(0, -1, 0)) + .put(WEST, new Vec3(-1, 0, 0)) + .put(EAST, new Vec3(+1, 0, 0)) + + .build(), + + ImmutableMap.builder() + + .put(TOP, new Vec3(+1, 0, 0)) + .put(BOTTOM, new Vec3(+1, 0, 0)) + .put(NORTH, new Vec3(0, 0, +1)) + .put(SOUTH, new Vec3(0, 0, +1)) + .put(WEST, new Vec3(0, 0, +1)) + .put(EAST, new Vec3(0, 0, +1)) + + .build() + ); + + INNER = createInner(OUTER); + } + + public static BlockFaceVectors get(boolean inner) { + return inner ? INNER : OUTER; + } + + private final ImmutableMap origins; + private final ImmutableMap widths; + private final ImmutableMap heights; + + public BlockFaceVectors( + ImmutableMap origins, + ImmutableMap widths, + ImmutableMap heights + ) { + this.origins = origins; + this.widths = widths; + this.heights = heights; + } + + public Vec3 getOrigin(BlockFace face) { + return origins.get(face); + } + + public Vec3 getWidth(BlockFace face) { + return widths.get(face); + } + + public Vec3 getHeight(BlockFace face) { + return heights.get(face); + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java index dddf1a7..9460bd7 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/DynamicModel.java @@ -1,124 +1,126 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import com.google.common.primitives.Booleans; - -import glm.mat._4.Mat4; - -public abstract class DynamicModel extends Model { - - private static final Mat4 IDENTITY = new Mat4(); - - private final Mat4[] transforms; - private final boolean[] dynamics; - - public DynamicModel( - Renderable[] parts, - Mat4[] transforms, - boolean[] dynamic - ) { - super(parts); - this.transforms = transforms; - this.dynamics = dynamic; - } - - public DynamicModel(Builder builder) { - this( - builder.getParts(), - builder.getTransforms(), - builder.getDynamics() - ); - } - - @Override - protected Mat4 getTransform(int shapeIndex) { - Mat4 transform = transforms[shapeIndex]; - - if (dynamics[shapeIndex]) { - transform.identity(); - getDynamicTransform(shapeIndex, transform); - } - - return transform; - } - - protected abstract void getDynamicTransform(int shapeIndex, Mat4 result); - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private final List parts = new ArrayList<>(); - private final List transforms = new ArrayList<>(); - private final List dynamics = new ArrayList<>(); - - protected Builder() {} - - private Builder addPart( - Renderable part, - Mat4 transform, - boolean isDynamic - ) { - parts.add(Objects.requireNonNull(part, "part")); - transforms.add(Objects.requireNonNull(transform, "transform")); - dynamics.add(isDynamic); - - return this; - } - - public Builder addStaticPart( - Renderable part, - Mat4 transform - ) { - return addPart(part, new Mat4(transform), false); - } - - public Builder addDynamicPart( - Renderable part - ) { - return addPart(part, new Mat4(), true); - } - - public Builder addStaticPart( - Renderable part - ) { - return addStaticPart(part, IDENTITY); - } - - private Renderable[] getParts() { - return parts.toArray(new Renderable[parts.size()]); - } - - private Mat4[] getTransforms() { - return transforms.toArray(new Mat4[transforms.size()]); - } - - private boolean[] getDynamics() { - return Booleans.toArray(dynamics); - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.google.common.primitives.Booleans; + +import glm.mat._4.Mat4; + +public abstract class DynamicModel extends Model { + + private static final Mat4 IDENTITY = new Mat4(); + + private final Mat4[] transforms; + private final boolean[] dynamics; + + public DynamicModel( + Renderable[] parts, + Mat4[] transforms, + boolean[] dynamic + ) { + super(parts); + this.transforms = transforms; + this.dynamics = dynamic; + } + + public DynamicModel(Builder builder) { + this( + builder.getParts(), + builder.getTransforms(), + builder.getDynamics() + ); + } + + @Override + protected Mat4 getTransform(int shapeIndex) { + Mat4 transform = transforms[shapeIndex]; + + if (dynamics[shapeIndex]) { + transform.identity(); + getDynamicTransform(shapeIndex, transform); + } + + return transform; + } + + protected abstract void getDynamicTransform(int shapeIndex, Mat4 result); + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private final List parts = new ArrayList<>(); + private final List transforms = new ArrayList<>(); + private final List dynamics = new ArrayList<>(); + + protected Builder() { + } + + private Builder addPart( + Renderable part, + Mat4 transform, + boolean isDynamic + ) { + parts.add(Objects.requireNonNull(part, "part")); + transforms.add(Objects.requireNonNull(transform, "transform")); + dynamics.add(isDynamic); + + return this; + } + + public Builder addStaticPart( + Renderable part, + Mat4 transform + ) { + return addPart(part, new Mat4(transform), false); + } + + public Builder addDynamicPart( + Renderable part + ) { + return addPart(part, new Mat4(), true); + } + + public Builder addStaticPart( + Renderable part + ) { + return addStaticPart(part, IDENTITY); + } + + private Renderable[] getParts() { + return parts.toArray(new Renderable[parts.size()]); + } + + private Mat4[] getTransforms() { + return transforms.toArray(new Mat4[transforms.size()]); + } + + private boolean[] getDynamics() { + return Booleans.toArray(dynamics); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java index 49c0b44..f9cff67 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/EmptyModel.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import glm.mat._4.Mat4; - -public class EmptyModel extends Model { - - private static final EmptyModel INSTANCE = new EmptyModel(); - - private EmptyModel() { - super(new Renderable[0]); - } - - public static EmptyModel getInstance() { - return INSTANCE; - } - - @Override - public void render(ShapeRenderHelper helper) { - // Do nothing - } - - @Override - protected Mat4 getTransform(int shapeIndex) { - throw new UnsupportedOperationException(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import glm.mat._4.Mat4; + +public class EmptyModel extends Model { + + private static final EmptyModel INSTANCE = new EmptyModel(); + + private EmptyModel() { + super(new Renderable[0]); + } + + public static EmptyModel getInstance() { + return INSTANCE; + } + + @Override + public void render(ShapeRenderHelper helper) { + // Do nothing + } + + @Override + protected Mat4 getTransform(int shapeIndex) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java index 15df29a..79da464 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Face.java @@ -1,252 +1,256 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; -import java.util.Objects; - -import ru.windcorp.progressia.client.graphics.texture.Texture; - -public class Face implements Comparable { - - private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null; - - private Shape shape = null; - int locationOfIndices; - int locationOfVertices; - - private Texture texture; - - ByteBuffer vertices; - private boolean verticesUpdated = true; - - private ShortBuffer userIndices; - private boolean userIndicesUpdated = true; - - public Face( - Texture texture, - ByteBuffer vertices, - ShortBuffer indices - ) { - setTexture(texture); - setVertices(vertices); - setIndices(indices); - } - - public Face( - Texture texture, - ByteBuffer vertices - ) { - this(texture, vertices, null); - } - - void setShape(Shape shape) { - this.shape = shape; - - checkVertices(); - checkIndices(); - } - - private void checkVertices() { - if (vertices.remaining() % getBytesPerVertex() != 0) { - throw new IllegalArgumentException( - "Invalid vertex buffer: " + - (vertices.remaining() % getBytesPerVertex()) + - " extra bytes after last vertex" - ); - } - } - - private void checkIndices() { - if (userIndices != GENERATE_SUCCESSIVE_LATER) { - if (userIndices.remaining() % 3 != 0) { - throw new IllegalArgumentException( - "Invalid vertex indices: " + - (userIndices.remaining() % 3) + - " extra indices after last triangle" - ); - } - - userIndices.mark(); - int vertexCount = getVertexCount(); - - while (userIndices.hasRemaining()) { - short index = userIndices.get(); - if (index < 0 || index >= vertexCount) { - throw new IllegalArgumentException( - "Invalid vertex index " + index + - " (" + vertexCount + " vertices available)" - ); - } - } - - userIndices.reset(); - } else { - if (getVertexCount() % 3 != 0) { - throw new IllegalArgumentException( - "Invalid vertices: " + - (getVertexCount() % 3) + - " extra indices after last triangle " + - "(indices are automatic)" - ); - } - } - } - - public void markForVertexUpdate() { - if (shape != null) checkVertices(); - markShapeForReassembly(); - verticesUpdated = true; - } - - boolean needsVerticesUpdate() { - return verticesUpdated; - } - - public void markForIndexUpdate() { - if (shape != null) checkIndices(); - markShapeForReassembly(); - userIndicesUpdated = true; - } - - boolean needsIndicesUpdate() { - return userIndicesUpdated; - } - - void resetUpdateFlags() { - verticesUpdated = false; - userIndicesUpdated = false; - } - - private void markShapeForReassembly() { - if (shape != null) { - shape.markForReassembly(); - } - } - - public int getVertexCount() { - return vertices.remaining() / getBytesPerVertex(); - } - - private int getBytesPerVertex() { - return shape.getProgram().getBytesPerVertex(); - } - - public ByteBuffer getVertices() { - return vertices; - } - - public Face setVertices(ByteBuffer vertices) { - this.vertices = Objects.requireNonNull(vertices, "vertices"); - markForVertexUpdate(); - return this; - } - - int getLocationOfVertices() { - return locationOfVertices; - } - - int getByteOffsetOfVertices() { - return locationOfVertices; - } - - public ShortBuffer getIndices() { - if (userIndices == GENERATE_SUCCESSIVE_LATER) { - userIndices = generateSuccessiveIndices(0); - } - - return userIndices; - } - - public int getIndex(int i) { - if (userIndices == GENERATE_SUCCESSIVE_LATER) { - return i; - } else { - ShortBuffer indices = getIndicesOrNull(); - return indices.get(indices.position() + i); - } - } - - ShortBuffer getIndicesOrNull() { - if (userIndices == GENERATE_SUCCESSIVE_LATER) { - return null; - } - - return userIndices; - } - - public int getIndexCount() { - if (userIndices == GENERATE_SUCCESSIVE_LATER) { - return getVertexCount(); - } - - return userIndices.remaining(); - } - - public Face setIndices(ShortBuffer indices) { - if (indices == null) { - indices = GENERATE_SUCCESSIVE_LATER; - } - - this.userIndices = indices; - markForIndexUpdate(); - - if (shape != null) checkIndices(); - - return this; - } - - private ShortBuffer generateSuccessiveIndices(int offset) { - int vertexCount = getVertexCount(); - ShortBuffer result = ShortBuffer.allocate(vertexCount); - - for (short vertex = 0; vertex < vertexCount; ++vertex) { - result.put((short) (vertex + offset)); - } - - result.flip(); - return result; - } - - int getLocationOfIndices() { - return locationOfIndices; - } - - int getByteOffsetOfIndices() { - return locationOfIndices * Short.BYTES; - } - - public Texture getTexture() { - return texture; - } - - public void setTexture(Texture texture) { - this.texture = texture; - } - - @Override - public int compareTo(Face o) { - return Integer.compare(getSortingIndex(), o.getSortingIndex()); - } - - public int getSortingIndex() { - return texture == null ? -1 : texture.getSprite().getPrimitive().getId(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.util.Objects; + +import ru.windcorp.progressia.client.graphics.texture.Texture; + +public class Face implements Comparable { + + private static final ShortBuffer GENERATE_SUCCESSIVE_LATER = null; + + private Shape shape = null; + int locationOfIndices; + int locationOfVertices; + + private Texture texture; + + ByteBuffer vertices; + private boolean verticesUpdated = true; + + private ShortBuffer userIndices; + private boolean userIndicesUpdated = true; + + public Face( + Texture texture, + ByteBuffer vertices, + ShortBuffer indices + ) { + setTexture(texture); + setVertices(vertices); + setIndices(indices); + } + + public Face( + Texture texture, + ByteBuffer vertices + ) { + this(texture, vertices, null); + } + + void setShape(Shape shape) { + this.shape = shape; + + checkVertices(); + checkIndices(); + } + + private void checkVertices() { + if (vertices.remaining() % getBytesPerVertex() != 0) { + throw new IllegalArgumentException( + "Invalid vertex buffer: " + + (vertices.remaining() % getBytesPerVertex()) + + " extra bytes after last vertex" + ); + } + } + + private void checkIndices() { + if (userIndices != GENERATE_SUCCESSIVE_LATER) { + if (userIndices.remaining() % 3 != 0) { + throw new IllegalArgumentException( + "Invalid vertex indices: " + + (userIndices.remaining() % 3) + + " extra indices after last triangle" + ); + } + + userIndices.mark(); + int vertexCount = getVertexCount(); + + while (userIndices.hasRemaining()) { + short index = userIndices.get(); + if (index < 0 || index >= vertexCount) { + throw new IllegalArgumentException( + "Invalid vertex index " + index + + " (" + vertexCount + " vertices available)" + ); + } + } + + userIndices.reset(); + } else { + if (getVertexCount() % 3 != 0) { + throw new IllegalArgumentException( + "Invalid vertices: " + + (getVertexCount() % 3) + + " extra indices after last triangle " + + "(indices are automatic)" + ); + } + } + } + + public void markForVertexUpdate() { + if (shape != null) + checkVertices(); + markShapeForReassembly(); + verticesUpdated = true; + } + + boolean needsVerticesUpdate() { + return verticesUpdated; + } + + public void markForIndexUpdate() { + if (shape != null) + checkIndices(); + markShapeForReassembly(); + userIndicesUpdated = true; + } + + boolean needsIndicesUpdate() { + return userIndicesUpdated; + } + + void resetUpdateFlags() { + verticesUpdated = false; + userIndicesUpdated = false; + } + + private void markShapeForReassembly() { + if (shape != null) { + shape.markForReassembly(); + } + } + + public int getVertexCount() { + return vertices.remaining() / getBytesPerVertex(); + } + + private int getBytesPerVertex() { + return shape.getProgram().getBytesPerVertex(); + } + + public ByteBuffer getVertices() { + return vertices; + } + + public Face setVertices(ByteBuffer vertices) { + this.vertices = Objects.requireNonNull(vertices, "vertices"); + markForVertexUpdate(); + return this; + } + + int getLocationOfVertices() { + return locationOfVertices; + } + + int getByteOffsetOfVertices() { + return locationOfVertices; + } + + public ShortBuffer getIndices() { + if (userIndices == GENERATE_SUCCESSIVE_LATER) { + userIndices = generateSuccessiveIndices(0); + } + + return userIndices; + } + + public int getIndex(int i) { + if (userIndices == GENERATE_SUCCESSIVE_LATER) { + return i; + } else { + ShortBuffer indices = getIndicesOrNull(); + return indices.get(indices.position() + i); + } + } + + ShortBuffer getIndicesOrNull() { + if (userIndices == GENERATE_SUCCESSIVE_LATER) { + return null; + } + + return userIndices; + } + + public int getIndexCount() { + if (userIndices == GENERATE_SUCCESSIVE_LATER) { + return getVertexCount(); + } + + return userIndices.remaining(); + } + + public Face setIndices(ShortBuffer indices) { + if (indices == null) { + indices = GENERATE_SUCCESSIVE_LATER; + } + + this.userIndices = indices; + markForIndexUpdate(); + + if (shape != null) + checkIndices(); + + return this; + } + + private ShortBuffer generateSuccessiveIndices(int offset) { + int vertexCount = getVertexCount(); + ShortBuffer result = ShortBuffer.allocate(vertexCount); + + for (short vertex = 0; vertex < vertexCount; ++vertex) { + result.put((short) (vertex + offset)); + } + + result.flip(); + return result; + } + + int getLocationOfIndices() { + return locationOfIndices; + } + + int getByteOffsetOfIndices() { + return locationOfIndices * Short.BYTES; + } + + public Texture getTexture() { + return texture; + } + + public void setTexture(Texture texture) { + this.texture = texture; + } + + @Override + public int compareTo(Face o) { + return Integer.compare(getSortingIndex(), o.getSortingIndex()); + } + + public int getSortingIndex() { + return texture == null ? -1 : texture.getSprite().getPrimitive().getId(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java index f544907..ee91544 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/FaceGroup.java @@ -1,43 +1,61 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.model; import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; public class FaceGroup { - + private final TexturePrimitive texture; private final int indexCount; private final int byteOffsetOfIndices; FaceGroup(Face[] faces, int start, int end) { - + Texture t = faces[start].getTexture(); this.texture = t == null ? null : t.getSprite().getPrimitive(); this.byteOffsetOfIndices = faces[start].getByteOffsetOfIndices(); - + int indexCount = 0; - + for (int i = start; i < end; ++i) { Face face = faces[i]; - + assert this.texture == null - ? (face.getTexture() == null) - : (face.getTexture().getSprite().getPrimitive() == this.texture); - + ? (face.getTexture() == null) + : (face.getTexture().getSprite().getPrimitive() == this.texture); + indexCount += face.getIndexCount(); } - + this.indexCount = indexCount; } public TexturePrimitive getTexture() { return this.texture; } - + public int getIndexCount() { return this.indexCount; } - + public int getByteOffsetOfIndices() { return this.byteOffsetOfIndices; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java index 6834e4e..d1e9c07 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Faces.java @@ -1,98 +1,117 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.nio.ShortBuffer; - -import glm.vec._2.Vec2; -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class Faces { - - private Faces() {} - - public static Face createRectangle( - ShapeRenderProgram program, - Texture texture, - Vec4 colorMultiplier, - Vec3 origin, - Vec3 width, - Vec3 height, - boolean flip - ) { - VertexBuilder builder = program.getVertexBuilder(); - - builder.addVertex( - origin, - colorMultiplier, - new Vec2(0, 0) - ).addVertex( - origin.add_(height), - colorMultiplier, - new Vec2(0, 1) - ).addVertex( - origin.add_(width), - colorMultiplier, - new Vec2(1, 0) - ).addVertex( - origin.add_(width).add(height), - colorMultiplier, - new Vec2(1, 1) - ); - - ShortBuffer buffer = flip ? ShortBuffer.wrap(new short[] { - 0, 1, 3, - 0, 3, 2 - }) : ShortBuffer.wrap(new short[] { - 3, 1, 0, - 2, 3, 0 - }); - - return new Face( - texture, - builder.assemble(), - buffer - ); - } - - public static Face createBlockFace( - ShapeRenderProgram program, - Texture texture, - Vec4 colorMultiplier, - Vec3 blockCenter, - BlockFace face, - boolean inner - ) { - BlockFaceVectors vectors = BlockFaceVectors.get(inner); - - Vec3 origin = blockCenter.add_(vectors.getOrigin(face)); - Vec3 width = vectors.getWidth(face); - Vec3 height = vectors.getHeight(face); - - return createRectangle( - program, texture, colorMultiplier, - origin, width, height, - inner - ); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.nio.ShortBuffer; + +import glm.vec._2.Vec2; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class Faces { + + private Faces() { + } + + public static Face createRectangle( + ShapeRenderProgram program, + Texture texture, + Vec4 colorMultiplier, + Vec3 origin, + Vec3 width, + Vec3 height, + boolean flip + ) { + VertexBuilder builder = program.getVertexBuilder(); + + builder.addVertex( + origin, + colorMultiplier, + new Vec2(0, 0) + ).addVertex( + origin.add_(height), + colorMultiplier, + new Vec2(0, 1) + ).addVertex( + origin.add_(width), + colorMultiplier, + new Vec2(1, 0) + ).addVertex( + origin.add_(width).add(height), + colorMultiplier, + new Vec2(1, 1) + ); + + ShortBuffer buffer = flip ? ShortBuffer.wrap( + new short[] { + 0, + 1, + 3, + 0, + 3, + 2 + } + ) + : ShortBuffer.wrap( + new short[] { + 3, + 1, + 0, + 2, + 3, + 0 + } + ); + + return new Face( + texture, + builder.assemble(), + buffer + ); + } + + public static Face createBlockFace( + ShapeRenderProgram program, + Texture texture, + Vec4 colorMultiplier, + Vec3 blockCenter, + BlockFace face, + boolean inner + ) { + BlockFaceVectors vectors = BlockFaceVectors.get(inner); + + Vec3 origin = blockCenter.add_(vectors.getOrigin(face)); + Vec3 width = vectors.getWidth(face); + Vec3 height = vectors.getHeight(face); + + return createRectangle( + program, + texture, + colorMultiplier, + origin, + width, + height, + inner + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java index 00d47b1..0ae31bf 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/LambdaModel.java @@ -1,134 +1,138 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import com.google.common.primitives.Booleans; - -import glm.mat._4.Mat4; - -public class LambdaModel extends DynamicModel { - - private static final Mat4 IDENTITY = new Mat4(); - - @FunctionalInterface - public static interface TransformGetter { - void transform(Mat4 result); - } - - private final TransformGetter[] getters; - - public LambdaModel( - Renderable[] parts, - Mat4[] transforms, - boolean[] dynamic, - TransformGetter[] getters - ) { - super(parts, transforms, dynamic); - this.getters = getters; - } - - public LambdaModel(Builder builder) { - this( - builder.getParts(), builder.getTransforms(), - builder.getDynamics(), builder.getGetters() - ); - } - - @Override - protected void getDynamicTransform(int shapeIndex, Mat4 result) { - getters[shapeIndex].transform(result); - } - - public static Builder lambdaBuilder() { - return new Builder(); - } - - public static class Builder { - - private final List parts = new ArrayList<>(); - private final List transforms = new ArrayList<>(); - private final List dynamics = new ArrayList<>(); - private final List getters = new ArrayList<>(); - - protected Builder() {} - - private Builder addPart( - Renderable part, - Mat4 transform, - TransformGetter getter - ) { - parts.add(Objects.requireNonNull(part, "part")); - transforms.add(Objects.requireNonNull(transform, "transform")); - dynamics.add(getter != null); - getters.add(getter); - - return this; - } - - public Builder addStaticPart( - Renderable part, - Mat4 transform - ) { - return addPart(part, new Mat4(transform), null); - } - - public Builder addDynamicPart( - Renderable part, - TransformGetter getter - ) { - return addPart(part, new Mat4(), getter); - } - - public Builder addStaticPart( - Renderable part - ) { - return addStaticPart(part, IDENTITY); - } - - private Renderable[] getParts() { - return parts.toArray(new Renderable[parts.size()]); - } - - private Mat4[] getTransforms() { - return transforms.toArray(new Mat4[transforms.size()]); - } - - private boolean[] getDynamics() { - return Booleans.toArray(dynamics); - } - - private TransformGetter[] getGetters() { - return getters.toArray(new TransformGetter[getters.size()]); - } - - } - - public static LambdaModel animate(Renderable model, TransformGetter transform) { - return new LambdaModel( - new Renderable[] { model }, - new Mat4[] { new Mat4() }, - new boolean[] { true }, - new TransformGetter[] { transform } - ); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.google.common.primitives.Booleans; + +import glm.mat._4.Mat4; + +public class LambdaModel extends DynamicModel { + + private static final Mat4 IDENTITY = new Mat4(); + + @FunctionalInterface + public static interface TransformGetter { + void transform(Mat4 result); + } + + private final TransformGetter[] getters; + + public LambdaModel( + Renderable[] parts, + Mat4[] transforms, + boolean[] dynamic, + TransformGetter[] getters + ) { + super(parts, transforms, dynamic); + this.getters = getters; + } + + public LambdaModel(Builder builder) { + this( + builder.getParts(), + builder.getTransforms(), + builder.getDynamics(), + builder.getGetters() + ); + } + + @Override + protected void getDynamicTransform(int shapeIndex, Mat4 result) { + getters[shapeIndex].transform(result); + } + + public static Builder lambdaBuilder() { + return new Builder(); + } + + public static class Builder { + + private final List parts = new ArrayList<>(); + private final List transforms = new ArrayList<>(); + private final List dynamics = new ArrayList<>(); + private final List getters = new ArrayList<>(); + + protected Builder() { + } + + private Builder addPart( + Renderable part, + Mat4 transform, + TransformGetter getter + ) { + parts.add(Objects.requireNonNull(part, "part")); + transforms.add(Objects.requireNonNull(transform, "transform")); + dynamics.add(getter != null); + getters.add(getter); + + return this; + } + + public Builder addStaticPart( + Renderable part, + Mat4 transform + ) { + return addPart(part, new Mat4(transform), null); + } + + public Builder addDynamicPart( + Renderable part, + TransformGetter getter + ) { + return addPart(part, new Mat4(), getter); + } + + public Builder addStaticPart( + Renderable part + ) { + return addStaticPart(part, IDENTITY); + } + + private Renderable[] getParts() { + return parts.toArray(new Renderable[parts.size()]); + } + + private Mat4[] getTransforms() { + return transforms.toArray(new Mat4[transforms.size()]); + } + + private boolean[] getDynamics() { + return Booleans.toArray(dynamics); + } + + private TransformGetter[] getGetters() { + return getters.toArray(new TransformGetter[getters.size()]); + } + + } + + public static LambdaModel animate(Renderable model, TransformGetter transform) { + return new LambdaModel( + new Renderable[] { model }, + new Mat4[] { new Mat4() }, + new boolean[] { true }, + new TransformGetter[] { transform } + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java index e32bab9..47cd88b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Model.java @@ -1,47 +1,48 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import glm.mat._4.Mat4; - -public abstract class Model implements Renderable { - - private final Renderable[] parts; - - public Model(Renderable[] parts) { - this.parts = parts; - } - - protected abstract Mat4 getTransform(int partIndex); - - @Override - public void render(ShapeRenderHelper helper) { - for (int i = 0; i < parts.length; ++i) { - Renderable part = parts[i]; - Mat4 transform = getTransform(i); - - try { - helper.pushTransform().mul(transform); - part.render(helper); - } finally { - helper.popTransform(); - } - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import glm.mat._4.Mat4; + +public abstract class Model implements Renderable { + + private final Renderable[] parts; + + public Model(Renderable[] parts) { + this.parts = parts; + } + + protected abstract Mat4 getTransform(int partIndex); + + @Override + public void render(ShapeRenderHelper helper) { + for (int i = 0; i < parts.length; ++i) { + Renderable part = parts[i]; + Mat4 transform = getTransform(i); + + try { + helper.pushTransform().mul(transform); + part.render(helper); + } finally { + helper.popTransform(); + } + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java index 52118ac..6063685 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Renderable.java @@ -1,24 +1,25 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -public interface Renderable { - - void render(ShapeRenderHelper renderer); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +public interface Renderable { + + void render(ShapeRenderHelper renderer); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java index cb4fb89..145b149 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shape.java @@ -1,249 +1,253 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.nio.ByteBuffer; -import java.nio.ShortBuffer; -import java.util.Arrays; - -import org.lwjgl.BufferUtils; - -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; - -public class Shape implements Renderable { - - private final ShapeRenderProgram program; - private final Face[] faces; - private final Usage usage; - - private FaceGroup[] groups; - - private ByteBuffer vertices; - private ShortBuffer indices; - - private boolean initialized = false; - private boolean needsAssembly = true; - private boolean needsVBOUpdate = true; - - private VertexBufferObject verticesVbo; - private VertexBufferObject indicesVbo; - - public Shape(Usage usage, ShapeRenderProgram program, Face... faces) { - this.program = program; - this.faces = faces; - this.usage = usage; - - configureFaces(); - program.preprocess(this); - - assembleBuffers(); - } - - private void configureFaces() { - for (Face face : faces) { - face.setShape(this); - } - } - - private void assembleBuffers() { - // TODO optimize: only update faces that requested it - - sortFaces(); - resizeBuffers(); - - for (Face face : faces) { - assembleVertices(face); - assembleIndices(face); - face.resetUpdateFlags(); - } - - this.vertices.flip(); - this.indices.flip(); - - assembleGroups(); - - needsAssembly = false; - needsVBOUpdate = true; - } - - private void resizeBuffers() { - int verticesRequired = 0, indicesRequired = 0; - for (Face face : faces) { - verticesRequired += face.getVertices().remaining(); - indicesRequired += face.getIndices().remaining(); - } - - if (this.vertices == null || vertices.capacity() < verticesRequired) { - this.vertices = BufferUtils.createByteBuffer(verticesRequired); - } else { - this.vertices.position(0).limit(verticesRequired); - } - - if (this.indices == null || this.indices.capacity() < indicesRequired) { - this.indices = BufferUtils.createShortBuffer(indicesRequired); - } else { - this.indices.position(0).limit(indicesRequired); - } - } - - private void assembleVertices(Face face) { - face.locationOfVertices = this.vertices.position(); - - insertVertices(face); - linkVerticesWith(face); - } - - private void insertVertices(Face face) { - ByteBuffer faceVertices = face.getVertices(); - - faceVertices.mark(); - this.vertices.put(faceVertices); - faceVertices.reset(); - } - - private void linkVerticesWith(Face face) { - int limit = vertices.limit(); - int position = vertices.position(); - - vertices.limit(position).position(face.getLocationOfVertices()); - face.vertices = vertices.slice(); - - vertices.position(position).limit(limit); - } - - private void assembleIndices(Face face) { - short vertexOffset = (short) ( - face.getLocationOfVertices() / program.getBytesPerVertex() - ); - - face.locationOfIndices = indices.position(); - - ShortBuffer faceIndices = face.getIndices(); - - if (faceIndices == null) { - for (int i = 0; i < face.getVertexCount(); ++i) { - this.indices.put((short) (vertexOffset + i)); - } - } else { - for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) { - short faceIndex = faceIndices.get(i); - faceIndex += vertexOffset; - this.indices.put(faceIndex); - } - } - } - - private void sortFaces() { - Arrays.sort(faces); - } - - private void assembleGroups() { - int unique = countUniqueFaces(); - this.groups = new FaceGroup[unique]; - - if (faces.length == 0) return; - - int previousHandle = faces[0].getSortingIndex(); - int start = 0; - int groupIndex = 0; - - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { - - groups[groupIndex] = new FaceGroup(faces, start, i); - start = i; - groupIndex++; - - previousHandle = faces[i].getSortingIndex(); - } - } - - assert groupIndex == groups.length - 1; - groups[groupIndex] = new FaceGroup(faces, start, faces.length); - } - - private int countUniqueFaces() { - if (faces.length == 0) return 0; - - int result = 1; - int previousHandle = faces[0].getSortingIndex(); - - for (int i = 1; i < faces.length; ++i) { - if (previousHandle != faces[i].getSortingIndex()) { - result++; - previousHandle = faces[i].getSortingIndex(); - } - } - - return result; - } - - void markForReassembly() { - needsAssembly = true; - } - - @Override - public void render(ShapeRenderHelper helper) { - if (!initialized) initialize(); - if (needsAssembly) assembleBuffers(); - if (needsVBOUpdate) updateVBO(); - - program.render(helper, this); - } - - private void initialize() { - verticesVbo = new VertexBufferObject(usage); - indicesVbo = new VertexBufferObject(usage); - needsVBOUpdate = true; - - initialized = true; - } - - private void updateVBO() { - verticesVbo.setData(vertices); - indicesVbo.setData(indices); - - needsVBOUpdate = false; - } - - VertexBufferObject getVerticesVbo() { - return verticesVbo; - } - - VertexBufferObject getIndicesVbo() { - return indicesVbo; - } - - public ShapeRenderProgram getProgram() { - return program; - } - - public Face[] getFaces() { - return faces; - } - - public FaceGroup[] getGroups() { - return groups; - } - - public Usage getUsage() { - return usage; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.util.Arrays; + +import org.lwjgl.BufferUtils; + +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; + +public class Shape implements Renderable { + + private final ShapeRenderProgram program; + private final Face[] faces; + private final Usage usage; + + private FaceGroup[] groups; + + private ByteBuffer vertices; + private ShortBuffer indices; + + private boolean initialized = false; + private boolean needsAssembly = true; + private boolean needsVBOUpdate = true; + + private VertexBufferObject verticesVbo; + private VertexBufferObject indicesVbo; + + public Shape(Usage usage, ShapeRenderProgram program, Face... faces) { + this.program = program; + this.faces = faces; + this.usage = usage; + + configureFaces(); + program.preprocess(this); + + assembleBuffers(); + } + + private void configureFaces() { + for (Face face : faces) { + face.setShape(this); + } + } + + private void assembleBuffers() { + // TODO optimize: only update faces that requested it + + sortFaces(); + resizeBuffers(); + + for (Face face : faces) { + assembleVertices(face); + assembleIndices(face); + face.resetUpdateFlags(); + } + + this.vertices.flip(); + this.indices.flip(); + + assembleGroups(); + + needsAssembly = false; + needsVBOUpdate = true; + } + + private void resizeBuffers() { + int verticesRequired = 0, indicesRequired = 0; + for (Face face : faces) { + verticesRequired += face.getVertices().remaining(); + indicesRequired += face.getIndices().remaining(); + } + + if (this.vertices == null || vertices.capacity() < verticesRequired) { + this.vertices = BufferUtils.createByteBuffer(verticesRequired); + } else { + this.vertices.position(0).limit(verticesRequired); + } + + if (this.indices == null || this.indices.capacity() < indicesRequired) { + this.indices = BufferUtils.createShortBuffer(indicesRequired); + } else { + this.indices.position(0).limit(indicesRequired); + } + } + + private void assembleVertices(Face face) { + face.locationOfVertices = this.vertices.position(); + + insertVertices(face); + linkVerticesWith(face); + } + + private void insertVertices(Face face) { + ByteBuffer faceVertices = face.getVertices(); + + faceVertices.mark(); + this.vertices.put(faceVertices); + faceVertices.reset(); + } + + private void linkVerticesWith(Face face) { + int limit = vertices.limit(); + int position = vertices.position(); + + vertices.limit(position).position(face.getLocationOfVertices()); + face.vertices = vertices.slice(); + + vertices.position(position).limit(limit); + } + + private void assembleIndices(Face face) { + short vertexOffset = (short) (face.getLocationOfVertices() / program.getBytesPerVertex()); + + face.locationOfIndices = indices.position(); + + ShortBuffer faceIndices = face.getIndices(); + + if (faceIndices == null) { + for (int i = 0; i < face.getVertexCount(); ++i) { + this.indices.put((short) (vertexOffset + i)); + } + } else { + for (int i = faceIndices.position(); i < faceIndices.limit(); ++i) { + short faceIndex = faceIndices.get(i); + faceIndex += vertexOffset; + this.indices.put(faceIndex); + } + } + } + + private void sortFaces() { + Arrays.sort(faces); + } + + private void assembleGroups() { + int unique = countUniqueFaces(); + this.groups = new FaceGroup[unique]; + + if (faces.length == 0) + return; + + int previousHandle = faces[0].getSortingIndex(); + int start = 0; + int groupIndex = 0; + + for (int i = 1; i < faces.length; ++i) { + if (previousHandle != faces[i].getSortingIndex()) { + + groups[groupIndex] = new FaceGroup(faces, start, i); + start = i; + groupIndex++; + + previousHandle = faces[i].getSortingIndex(); + } + } + + assert groupIndex == groups.length - 1; + groups[groupIndex] = new FaceGroup(faces, start, faces.length); + } + + private int countUniqueFaces() { + if (faces.length == 0) + return 0; + + int result = 1; + int previousHandle = faces[0].getSortingIndex(); + + for (int i = 1; i < faces.length; ++i) { + if (previousHandle != faces[i].getSortingIndex()) { + result++; + previousHandle = faces[i].getSortingIndex(); + } + } + + return result; + } + + void markForReassembly() { + needsAssembly = true; + } + + @Override + public void render(ShapeRenderHelper helper) { + if (!initialized) + initialize(); + if (needsAssembly) + assembleBuffers(); + if (needsVBOUpdate) + updateVBO(); + + program.render(helper, this); + } + + private void initialize() { + verticesVbo = new VertexBufferObject(usage); + indicesVbo = new VertexBufferObject(usage); + needsVBOUpdate = true; + + initialized = true; + } + + private void updateVBO() { + verticesVbo.setData(vertices); + indicesVbo.setData(indices); + + needsVBOUpdate = false; + } + + VertexBufferObject getVerticesVbo() { + return verticesVbo; + } + + VertexBufferObject getIndicesVbo() { + return indicesVbo; + } + + public ShapeRenderProgram getProgram() { + return program; + } + + public Face[] getFaces() { + return faces; + } + + public FaceGroup[] getGroups() { + return groups; + } + + public Usage getUsage() { + return usage; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java index a4cf6ef..67578f6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderHelper.java @@ -1,84 +1,87 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import glm.mat._4.Mat4; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.common.util.StashingStack; - -public class ShapeRenderHelper { - - protected static final int TRANSFORM_STACK_SIZE = 64; - protected static final int COLOR_MULTIPLIER_STACK_SIZE = TRANSFORM_STACK_SIZE; - - protected final StashingStack transformStack = new StashingStack<>( - TRANSFORM_STACK_SIZE, Mat4::new - ); - - protected final StashingStack colorMultiplierStack = new StashingStack<>( - COLOR_MULTIPLIER_STACK_SIZE, Vec4::new - ); - - { - transformStack.push().identity(); - colorMultiplierStack.push().set(Colors.WHITE); - } - - public Mat4 pushTransform() { - Mat4 previous = transformStack.getHead(); - return transformStack.push().set(previous); - } - - public void popTransform() { - transformStack.removeHead(); - } - - public Mat4 getTransform() { - return transformStack.getHead(); - } - - public Mat4 getFinalTransform() { - return getTransform(); - } - - public Vec4 pushColorMultiplier() { - Vec4 previous = colorMultiplierStack.getHead(); - return colorMultiplierStack.push().set(previous); - } - - public void popColorMultiplier() { - colorMultiplierStack.removeHead(); - } - - public Vec4 getColorMultiplier() { - return colorMultiplierStack.getHead(); - } - - public Vec4 getFinalColorMultiplier() { - return getColorMultiplier(); - } - - public void reset() { - transformStack.removeAll(); - transformStack.push().identity(); - colorMultiplierStack.removeAll(); - colorMultiplierStack.push().set(Colors.WHITE); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import glm.mat._4.Mat4; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.common.util.StashingStack; + +public class ShapeRenderHelper { + + protected static final int TRANSFORM_STACK_SIZE = 64; + protected static final int COLOR_MULTIPLIER_STACK_SIZE = TRANSFORM_STACK_SIZE; + + protected final StashingStack transformStack = new StashingStack<>( + TRANSFORM_STACK_SIZE, + Mat4::new + ); + + protected final StashingStack colorMultiplierStack = new StashingStack<>( + COLOR_MULTIPLIER_STACK_SIZE, + Vec4::new + ); + + { + transformStack.push().identity(); + colorMultiplierStack.push().set(Colors.WHITE); + } + + public Mat4 pushTransform() { + Mat4 previous = transformStack.getHead(); + return transformStack.push().set(previous); + } + + public void popTransform() { + transformStack.removeHead(); + } + + public Mat4 getTransform() { + return transformStack.getHead(); + } + + public Mat4 getFinalTransform() { + return getTransform(); + } + + public Vec4 pushColorMultiplier() { + Vec4 previous = colorMultiplierStack.getHead(); + return colorMultiplierStack.push().set(previous); + } + + public void popColorMultiplier() { + colorMultiplierStack.removeHead(); + } + + public Vec4 getColorMultiplier() { + return colorMultiplierStack.getHead(); + } + + public Vec4 getFinalColorMultiplier() { + return getColorMultiplier(); + } + + public void reset() { + transformStack.removeAll(); + transformStack.push().identity(); + colorMultiplierStack.removeAll(); + colorMultiplierStack.push().set(Colors.WHITE); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java index 890f02d..e27bc77 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/ShapeRenderProgram.java @@ -1,351 +1,383 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; - -import com.google.common.collect.ObjectArrays; - -import glm.vec._2.Vec2; -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; -import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject.BindTarget; -import ru.windcorp.progressia.client.graphics.backend.shaders.CombinedShader; -import ru.windcorp.progressia.client.graphics.backend.shaders.Program; -import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; -import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; -import ru.windcorp.progressia.client.graphics.texture.Sprite; -import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; -import ru.windcorp.progressia.common.util.Vectors; - -public class ShapeRenderProgram extends Program { - - private static final int DEFAULT_BYTES_PER_VERTEX = - 3 * Float.BYTES + // Position - 4 * Float.BYTES + // Color multiplier - 2 * Float.BYTES; // Texture coordinates - - private static final String SHAPE_VERTEX_SHADER_RESOURCE = - "Shape.vertex.glsl"; - private static final String SHAPE_FRAGMENT_SHADER_RESOURCE = - "Shape.fragment.glsl"; - - private static final String - FINAL_TRANSFORM_UNIFORM_NAME = "finalTransform", - POSITIONS_ATTRIBUTE_NAME = "inputPositions", - UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier", - ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier", - TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords", - USE_TEXTURE_UNIFORM_NAME = "useTexture", - TEXTURE_SLOT_UNIFORM_NAME = "textureSlot"; - - private final Uniform4Matrix finalTransformUniform; - private final AttributeVertexArray positionsAttribute; - private final Uniform4Float colorsUniform; - private final AttributeVertexArray colorsAttribute; - private final AttributeVertexArray textureCoordsAttribute; - private final Uniform1Int useTextureUniform; - private final Uniform1Int textureSlotUniform; - - public ShapeRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - new CombinedShader( - attachVertexShader(vertexShaderResources) - ), - new CombinedShader( - attachFragmentShader(fragmentShaderResources) - ) - ); - - this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME) - .as4Matrix(); - - this.positionsAttribute = - getAttribute(POSITIONS_ATTRIBUTE_NAME).asVertexArray(); - - this.colorsUniform = - getUniform(UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME).as4Float(); - - this.colorsAttribute = - getAttribute(ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME).asVertexArray(); - - this.textureCoordsAttribute = - getAttribute(TEXTURE_COORDS_ATTRIBUTE_NAME).asVertexArray(); - - this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME) - .as1Int(); - - this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME) - .as1Int(); - } - - private static String[] attachVertexShader(String[] others) { - return ObjectArrays.concat(SHAPE_VERTEX_SHADER_RESOURCE, others); - } - - private static String[] attachFragmentShader(String[] others) { - return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others); - } - - public void render( - ShapeRenderHelper helper, - Shape shape - ) { - use(); - configure(helper); - - bindVertices(shape.getVerticesVbo()); - bindIndices(shape.getIndicesVbo()); - - try { - enableAttributes(); - for (FaceGroup group : shape.getGroups()) { - renderFaceGroup(group); - } - } finally { - disableAttributes(); - } - } - - protected void enableAttributes() { - positionsAttribute.enable(); - colorsAttribute.enable(); - textureCoordsAttribute.enable(); - } - - protected void disableAttributes() { - positionsAttribute.disable(); - colorsAttribute.disable(); - textureCoordsAttribute.disable(); - } - - protected void configure(ShapeRenderHelper helper) { - finalTransformUniform.set(helper.getFinalTransform()); - colorsUniform.set(helper.getFinalColorMultiplier()); - } - - protected int bindVertices(VertexBufferObject vertices) { - int vertexStride = getBytesPerVertex(); - int offset = 0; - - positionsAttribute.set( - 3, GL11.GL_FLOAT, false, vertexStride, vertices, - offset - ); - offset += 3 * Float.BYTES; - - colorsAttribute.set( - 4, GL11.GL_FLOAT, false, vertexStride, vertices, - offset - ); - offset += 4 * Float.BYTES; - - textureCoordsAttribute.set( - 2, GL11.GL_FLOAT, false, vertexStride, vertices, - offset - ); - offset += 2 * Float.BYTES; - - return offset; - } - - protected void bindIndices(VertexBufferObject indices) { - indices.bind(BindTarget.ELEMENT_ARRAY); - } - - protected void renderFaceGroup(FaceGroup group) { - TexturePrimitive texture = group.getTexture(); - - if (texture != null) { - texture.bind(0); - textureSlotUniform.set(0); - useTextureUniform.set(1); - } else { - useTextureUniform.set(0); - } - - GL11.glDrawElements( - GL11.GL_TRIANGLES, - group.getIndexCount(), - GL11.GL_UNSIGNED_SHORT, - group.getByteOffsetOfIndices() - ); - } - - public int getBytesPerVertex() { - return DEFAULT_BYTES_PER_VERTEX; - } - - public void preprocess(Shape shape) { - for (Face face : shape.getFaces()) { - applySprites(face); - } - } - - private void applySprites(Face face) { - if (face.getTexture() == null) return; - - Vec2 v = Vectors.grab2(); - ByteBuffer vertices = face.getVertices(); - Sprite sprite = face.getTexture().getSprite(); - - for (int i = 0; i < face.getVertexCount(); i++) { - int offset = vertices.position() + i * getBytesPerVertex() + ( - 3 * Float.BYTES + - 4 * Float.BYTES - ); - - v.set( - vertices.getFloat(offset + 0 * Float.BYTES), - vertices.getFloat(offset + 1 * Float.BYTES) - ); - - v.mul(sprite.getSize()).add(sprite.getStart()); - - vertices.putFloat(offset + 0 * Float.BYTES, v.x); - vertices.putFloat(offset + 1 * Float.BYTES, v.y); - } - - face.markForVertexUpdate(); - - Vectors.release(v); - } - - public VertexBuilder getVertexBuilder() { - return new SRPVertexBuilder(); - } - - public static interface VertexBuilder { - VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, - float tx, float ty - ); - - VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, float a, - float tx, float ty - ); - - VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ); - - ByteBuffer assemble(); - } - - public static class SRPVertexBuilder implements VertexBuilder { - - private static class Vertex { - final Vec3 position; - final Vec4 colorMultiplier; - final Vec2 textureCoords; - - Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { - this.position = position; - this.colorMultiplier = colorMultiplier; - this.textureCoords = textureCoords; - } - } - - private final List vertices = new ArrayList<>(); - - @Override - public VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, float a, - float tx, float ty - ) { - vertices.add(new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, a), - new Vec2(tx, ty) - )); - - return this; - } - - @Override - public VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, - float tx, float ty - ) { - vertices.add(new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, 1f), - new Vec2(tx, ty) - )); - - return this; - } - - @Override - public VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ) { - vertices.add(new Vertex( - new Vec3(position), - new Vec4(colorMultiplier), - new Vec2(textureCoords) - )); - - return this; - } - - @Override - public ByteBuffer assemble() { - ByteBuffer result = BufferUtils.createByteBuffer( - DEFAULT_BYTES_PER_VERTEX * vertices.size() - ); - - for (Vertex v : vertices) { - result - .putFloat(v.position.x) - .putFloat(v.position.y) - .putFloat(v.position.z) - .putFloat(v.colorMultiplier.x) - .putFloat(v.colorMultiplier.y) - .putFloat(v.colorMultiplier.z) - .putFloat(v.colorMultiplier.w) - .putFloat(v.textureCoords.x) - .putFloat(v.textureCoords.y); - } - - result.flip(); - - return result; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; + +import com.google.common.collect.ObjectArrays; + +import glm.vec._2.Vec2; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; +import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject.BindTarget; +import ru.windcorp.progressia.client.graphics.backend.shaders.CombinedShader; +import ru.windcorp.progressia.client.graphics.backend.shaders.Program; +import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; +import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; +import ru.windcorp.progressia.client.graphics.texture.Sprite; +import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; +import ru.windcorp.progressia.common.util.Vectors; + +public class ShapeRenderProgram extends Program { + + private static final int DEFAULT_BYTES_PER_VERTEX = 3 * Float.BYTES + // Position + 4 * Float.BYTES + // Color multiplier + 2 * Float.BYTES; // Texture coordinates + + private static final String SHAPE_VERTEX_SHADER_RESOURCE = "Shape.vertex.glsl"; + private static final String SHAPE_FRAGMENT_SHADER_RESOURCE = "Shape.fragment.glsl"; + + private static final String FINAL_TRANSFORM_UNIFORM_NAME = "finalTransform", + POSITIONS_ATTRIBUTE_NAME = "inputPositions", + UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME = "uniformColorMultiplier", + ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME = "inputColorMultiplier", + TEXTURE_COORDS_ATTRIBUTE_NAME = "inputTextureCoords", + USE_TEXTURE_UNIFORM_NAME = "useTexture", + TEXTURE_SLOT_UNIFORM_NAME = "textureSlot"; + + private final Uniform4Matrix finalTransformUniform; + private final AttributeVertexArray positionsAttribute; + private final Uniform4Float colorsUniform; + private final AttributeVertexArray colorsAttribute; + private final AttributeVertexArray textureCoordsAttribute; + private final Uniform1Int useTextureUniform; + private final Uniform1Int textureSlotUniform; + + public ShapeRenderProgram( + String[] vertexShaderResources, + String[] fragmentShaderResources + ) { + super( + new CombinedShader( + attachVertexShader(vertexShaderResources) + ), + new CombinedShader( + attachFragmentShader(fragmentShaderResources) + ) + ); + + this.finalTransformUniform = getUniform(FINAL_TRANSFORM_UNIFORM_NAME) + .as4Matrix(); + + this.positionsAttribute = getAttribute(POSITIONS_ATTRIBUTE_NAME).asVertexArray(); + + this.colorsUniform = getUniform(UNIFORM_COLOR_MULTIPLER_ATTRIBUTE_NAME).as4Float(); + + this.colorsAttribute = getAttribute(ATTRIBUTE_COLOR_MULTIPLER_ATTRIBUTE_NAME).asVertexArray(); + + this.textureCoordsAttribute = getAttribute(TEXTURE_COORDS_ATTRIBUTE_NAME).asVertexArray(); + + this.useTextureUniform = getUniform(USE_TEXTURE_UNIFORM_NAME) + .as1Int(); + + this.textureSlotUniform = getUniform(TEXTURE_SLOT_UNIFORM_NAME) + .as1Int(); + } + + private static String[] attachVertexShader(String[] others) { + return ObjectArrays.concat(SHAPE_VERTEX_SHADER_RESOURCE, others); + } + + private static String[] attachFragmentShader(String[] others) { + return ObjectArrays.concat(SHAPE_FRAGMENT_SHADER_RESOURCE, others); + } + + public void render( + ShapeRenderHelper helper, + Shape shape + ) { + use(); + configure(helper); + + bindVertices(shape.getVerticesVbo()); + bindIndices(shape.getIndicesVbo()); + + try { + enableAttributes(); + for (FaceGroup group : shape.getGroups()) { + renderFaceGroup(group); + } + } finally { + disableAttributes(); + } + } + + protected void enableAttributes() { + positionsAttribute.enable(); + colorsAttribute.enable(); + textureCoordsAttribute.enable(); + } + + protected void disableAttributes() { + positionsAttribute.disable(); + colorsAttribute.disable(); + textureCoordsAttribute.disable(); + } + + protected void configure(ShapeRenderHelper helper) { + finalTransformUniform.set(helper.getFinalTransform()); + colorsUniform.set(helper.getFinalColorMultiplier()); + } + + protected int bindVertices(VertexBufferObject vertices) { + int vertexStride = getBytesPerVertex(); + int offset = 0; + + positionsAttribute.set( + 3, + GL11.GL_FLOAT, + false, + vertexStride, + vertices, + offset + ); + offset += 3 * Float.BYTES; + + colorsAttribute.set( + 4, + GL11.GL_FLOAT, + false, + vertexStride, + vertices, + offset + ); + offset += 4 * Float.BYTES; + + textureCoordsAttribute.set( + 2, + GL11.GL_FLOAT, + false, + vertexStride, + vertices, + offset + ); + offset += 2 * Float.BYTES; + + return offset; + } + + protected void bindIndices(VertexBufferObject indices) { + indices.bind(BindTarget.ELEMENT_ARRAY); + } + + protected void renderFaceGroup(FaceGroup group) { + TexturePrimitive texture = group.getTexture(); + + if (texture != null) { + texture.bind(0); + textureSlotUniform.set(0); + useTextureUniform.set(1); + } else { + useTextureUniform.set(0); + } + + GL11.glDrawElements( + GL11.GL_TRIANGLES, + group.getIndexCount(), + GL11.GL_UNSIGNED_SHORT, + group.getByteOffsetOfIndices() + ); + } + + public int getBytesPerVertex() { + return DEFAULT_BYTES_PER_VERTEX; + } + + public void preprocess(Shape shape) { + for (Face face : shape.getFaces()) { + applySprites(face); + } + } + + private void applySprites(Face face) { + if (face.getTexture() == null) + return; + + Vec2 v = Vectors.grab2(); + ByteBuffer vertices = face.getVertices(); + Sprite sprite = face.getTexture().getSprite(); + + for (int i = 0; i < face.getVertexCount(); i++) { + int offset = vertices.position() + i * getBytesPerVertex() + (3 * Float.BYTES + + 4 * Float.BYTES); + + v.set( + vertices.getFloat(offset + 0 * Float.BYTES), + vertices.getFloat(offset + 1 * Float.BYTES) + ); + + v.mul(sprite.getSize()).add(sprite.getStart()); + + vertices.putFloat(offset + 0 * Float.BYTES, v.x); + vertices.putFloat(offset + 1 * Float.BYTES, v.y); + } + + face.markForVertexUpdate(); + + Vectors.release(v); + } + + public VertexBuilder getVertexBuilder() { + return new SRPVertexBuilder(); + } + + public static interface VertexBuilder { + VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float tx, + float ty + ); + + VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float a, + float tx, + float ty + ); + + VertexBuilder addVertex( + Vec3 position, + Vec4 colorMultiplier, + Vec2 textureCoords + ); + + ByteBuffer assemble(); + } + + public static class SRPVertexBuilder implements VertexBuilder { + + private static class Vertex { + final Vec3 position; + final Vec4 colorMultiplier; + final Vec2 textureCoords; + + Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { + this.position = position; + this.colorMultiplier = colorMultiplier; + this.textureCoords = textureCoords; + } + } + + private final List vertices = new ArrayList<>(); + + @Override + public VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float a, + float tx, + float ty + ) { + vertices.add( + new Vertex( + new Vec3(x, y, z), + new Vec4(r, g, b, a), + new Vec2(tx, ty) + ) + ); + + return this; + } + + @Override + public VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float tx, + float ty + ) { + vertices.add( + new Vertex( + new Vec3(x, y, z), + new Vec4(r, g, b, 1f), + new Vec2(tx, ty) + ) + ); + + return this; + } + + @Override + public VertexBuilder addVertex( + Vec3 position, + Vec4 colorMultiplier, + Vec2 textureCoords + ) { + vertices.add( + new Vertex( + new Vec3(position), + new Vec4(colorMultiplier), + new Vec2(textureCoords) + ) + ); + + return this; + } + + @Override + public ByteBuffer assemble() { + ByteBuffer result = BufferUtils.createByteBuffer( + DEFAULT_BYTES_PER_VERTEX * vertices.size() + ); + + for (Vertex v : vertices) { + result + .putFloat(v.position.x) + .putFloat(v.position.y) + .putFloat(v.position.z) + .putFloat(v.colorMultiplier.x) + .putFloat(v.colorMultiplier.y) + .putFloat(v.colorMultiplier.z) + .putFloat(v.colorMultiplier.w) + .putFloat(v.textureCoords.x) + .putFloat(v.textureCoords.y); + } + + result.flip(); + + return result; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java index 2da7332..7ddd5d6 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/Shapes.java @@ -1,273 +1,288 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.util.Map; - -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class Shapes { - - public static Shape createParallelepiped( // Try saying that 10 times fast - ShapeRenderProgram program, - - Vec3 origin, - - Vec3 width, - Vec3 height, - Vec3 depth, - - Vec4 colorMultiplier, - - Texture topTexture, - Texture bottomTexture, - Texture northTexture, - Texture southTexture, - Texture eastTexture, - Texture westTexture, - - boolean flip - ) { - - Face top = Faces.createRectangle( - program, - topTexture, colorMultiplier, - origin.add_(height).add(width), - width.negate_(), - depth, - flip - ); - - Face bottom = Faces.createRectangle( - program, - bottomTexture, colorMultiplier, - origin, - width, - depth, - flip - ); - - Face north = Faces.createRectangle( - program, - northTexture, colorMultiplier, - origin.add_(depth), - width, - height, - flip - ); - - Face south = Faces.createRectangle( - program, - southTexture, colorMultiplier, - origin.add_(width), - width.negate_(), - height, - flip - ); - - Face east = Faces.createRectangle( - program, - eastTexture, colorMultiplier, - origin, - depth, - height, - flip - ); - - Face west = Faces.createRectangle( - program, - westTexture, colorMultiplier, - origin.add_(width).add(depth), - depth.negate_(), - height, - flip - ); - - Shape result = new Shape( - Usage.STATIC, - program, - top, bottom, north, south, east, west - ); - - return result; - } - - public static class PppBuilder { - - private final ShapeRenderProgram program; - - private final Vec3 origin = new Vec3(-0.5f, -0.5f, -0.5f); - - private final Vec3 depth = new Vec3(1, 0, 0); - private final Vec3 width = new Vec3(0, 1, 0); - private final Vec3 height = new Vec3(0, 0, 1); - - private final Vec4 colorMultiplier = new Vec4(1, 1, 1, 1); - - private final Texture topTexture; - private final Texture bottomTexture; - private final Texture northTexture; - private final Texture southTexture; - private final Texture eastTexture; - private final Texture westTexture; - - private boolean flip = false; - - public PppBuilder( - ShapeRenderProgram program, - Texture top, - Texture bottom, - Texture north, - Texture south, - Texture east, - Texture west - ) { - this.program = program; - this.topTexture = top; - this.bottomTexture = bottom; - this.northTexture = north; - this.southTexture = south; - this.eastTexture = east; - this.westTexture = west; - } - - public PppBuilder( - ShapeRenderProgram program, - Map textureMap - ) { - this( - program, - textureMap.get(BlockFace.TOP), - textureMap.get(BlockFace.BOTTOM), - textureMap.get(BlockFace.NORTH), - textureMap.get(BlockFace.SOUTH), - textureMap.get(BlockFace.EAST), - textureMap.get(BlockFace.WEST) - ); - } - - public PppBuilder(ShapeRenderProgram program, Texture texture) { - this(program, texture, texture, texture, texture, texture, texture); - } - - public PppBuilder setOrigin(Vec3 origin) { - this.origin.set(origin); - return this; - } - - public PppBuilder setOrigin(float x, float y, float z) { - this.origin.set(x, y, z); - return this; - } - - public PppBuilder setColorMultiplier(Vec4 colorMultiplier) { - this.colorMultiplier.set(colorMultiplier); - return this; - } - - public PppBuilder setColorMultiplier(float r, float g, float b) { - this.colorMultiplier.set(r, g, b, 1); - return this; - } - - public PppBuilder setColorMultiplier(float r, float g, float b, float a) { - this.colorMultiplier.set(r, g, b, a); - return this; - } - - public PppBuilder setDepth(Vec3 vector) { - this.depth.set(vector); - return this; - } - - public PppBuilder setDepth(float x, float y, float z) { - this.depth.set(x, y, z); - return this; - } - - public PppBuilder setDepth(float x) { - this.depth.set(x, 0, 0); - return this; - } - - public PppBuilder setWidth(Vec3 vector) { - this.width.set(vector); - return this; - } - - public PppBuilder setWidth(float x, float y, float z) { - this.width.set(x, y, z); - return this; - } - - public PppBuilder setWidth(float y) { - this.width.set(0, y, 0); - return this; - } - - public PppBuilder setHeight(Vec3 vector) { - this.height.set(vector); - return this; - } - - public PppBuilder setHeight(float x, float y, float z) { - this.height.set(x, y, z); - return this; - } - - public PppBuilder setHeight(float z) { - this.height.set(0, 0, z); - return this; - } - - public PppBuilder setSize(float x, float y, float z) { - return this.setDepth(x).setWidth(y).setHeight(z); - } - - public PppBuilder setSize(float size) { - return this.setSize(size, size, size); - } - - public PppBuilder flip() { - this.flip = true; - return this; - } - - public Shape create() { - return createParallelepiped( - program, - origin, - width, height, depth, - colorMultiplier, - topTexture, - bottomTexture, - northTexture, - southTexture, - eastTexture, - westTexture, - flip - ); - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.util.Map; + +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class Shapes { + + public static Shape createParallelepiped( + // Try saying that 10 times fast + ShapeRenderProgram program, + + Vec3 origin, + + Vec3 width, + Vec3 height, + Vec3 depth, + + Vec4 colorMultiplier, + + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture eastTexture, + Texture westTexture, + + boolean flip + ) { + + Face top = Faces.createRectangle( + program, + topTexture, + colorMultiplier, + origin.add_(height).add(width), + width.negate_(), + depth, + flip + ); + + Face bottom = Faces.createRectangle( + program, + bottomTexture, + colorMultiplier, + origin, + width, + depth, + flip + ); + + Face north = Faces.createRectangle( + program, + northTexture, + colorMultiplier, + origin.add_(depth), + width, + height, + flip + ); + + Face south = Faces.createRectangle( + program, + southTexture, + colorMultiplier, + origin.add_(width), + width.negate_(), + height, + flip + ); + + Face east = Faces.createRectangle( + program, + eastTexture, + colorMultiplier, + origin, + depth, + height, + flip + ); + + Face west = Faces.createRectangle( + program, + westTexture, + colorMultiplier, + origin.add_(width).add(depth), + depth.negate_(), + height, + flip + ); + + Shape result = new Shape( + Usage.STATIC, + program, + top, + bottom, + north, + south, + east, + west + ); + + return result; + } + + public static class PppBuilder { + + private final ShapeRenderProgram program; + + private final Vec3 origin = new Vec3(-0.5f, -0.5f, -0.5f); + + private final Vec3 depth = new Vec3(1, 0, 0); + private final Vec3 width = new Vec3(0, 1, 0); + private final Vec3 height = new Vec3(0, 0, 1); + + private final Vec4 colorMultiplier = new Vec4(1, 1, 1, 1); + + private final Texture topTexture; + private final Texture bottomTexture; + private final Texture northTexture; + private final Texture southTexture; + private final Texture eastTexture; + private final Texture westTexture; + + private boolean flip = false; + + public PppBuilder( + ShapeRenderProgram program, + Texture top, + Texture bottom, + Texture north, + Texture south, + Texture east, + Texture west + ) { + this.program = program; + this.topTexture = top; + this.bottomTexture = bottom; + this.northTexture = north; + this.southTexture = south; + this.eastTexture = east; + this.westTexture = west; + } + + public PppBuilder( + ShapeRenderProgram program, + Map textureMap + ) { + this( + program, + textureMap.get(BlockFace.TOP), + textureMap.get(BlockFace.BOTTOM), + textureMap.get(BlockFace.NORTH), + textureMap.get(BlockFace.SOUTH), + textureMap.get(BlockFace.EAST), + textureMap.get(BlockFace.WEST) + ); + } + + public PppBuilder(ShapeRenderProgram program, Texture texture) { + this(program, texture, texture, texture, texture, texture, texture); + } + + public PppBuilder setOrigin(Vec3 origin) { + this.origin.set(origin); + return this; + } + + public PppBuilder setOrigin(float x, float y, float z) { + this.origin.set(x, y, z); + return this; + } + + public PppBuilder setColorMultiplier(Vec4 colorMultiplier) { + this.colorMultiplier.set(colorMultiplier); + return this; + } + + public PppBuilder setColorMultiplier(float r, float g, float b) { + this.colorMultiplier.set(r, g, b, 1); + return this; + } + + public PppBuilder setColorMultiplier(float r, float g, float b, float a) { + this.colorMultiplier.set(r, g, b, a); + return this; + } + + public PppBuilder setDepth(Vec3 vector) { + this.depth.set(vector); + return this; + } + + public PppBuilder setDepth(float x, float y, float z) { + this.depth.set(x, y, z); + return this; + } + + public PppBuilder setDepth(float x) { + this.depth.set(x, 0, 0); + return this; + } + + public PppBuilder setWidth(Vec3 vector) { + this.width.set(vector); + return this; + } + + public PppBuilder setWidth(float x, float y, float z) { + this.width.set(x, y, z); + return this; + } + + public PppBuilder setWidth(float y) { + this.width.set(0, y, 0); + return this; + } + + public PppBuilder setHeight(Vec3 vector) { + this.height.set(vector); + return this; + } + + public PppBuilder setHeight(float x, float y, float z) { + this.height.set(x, y, z); + return this; + } + + public PppBuilder setHeight(float z) { + this.height.set(0, 0, z); + return this; + } + + public PppBuilder setSize(float x, float y, float z) { + return this.setDepth(x).setWidth(y).setHeight(z); + } + + public PppBuilder setSize(float size) { + return this.setSize(size, size, size); + } + + public PppBuilder flip() { + this.flip = true; + return this; + } + + public Shape create() { + return createParallelepiped( + program, + origin, + width, + height, + depth, + colorMultiplier, + topTexture, + bottomTexture, + northTexture, + southTexture, + eastTexture, + westTexture, + flip + ); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java b/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java index 04de1d9..69e5de3 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/model/StaticModel.java @@ -1,86 +1,88 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.model; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -import glm.mat._4.Mat4; - -public class StaticModel extends Model { - - private static final Mat4 IDENTITY = new Mat4(); - - private final Mat4[] transforms; - - public StaticModel( - Renderable[] parts, - Mat4[] transforms - ) { - super(parts); - this.transforms = transforms; - } - - public StaticModel(Builder builder) { - this(builder.getParts(), builder.getTransforms()); - } - - @Override - protected Mat4 getTransform(int partIndex) { - return transforms[partIndex]; - } - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private final List parts = new ArrayList<>(); - private final List transforms = new ArrayList<>(); - - protected Builder() {} - - public Builder addPart( - Renderable part, - Mat4 transform - ) { - parts.add(Objects.requireNonNull(part, "part")); - transforms.add(Objects.requireNonNull(transform, "transform")); - - return this; - } - - public Builder addPart( - Renderable part - ) { - return addPart(part, IDENTITY); - } - - private Renderable[] getParts() { - return parts.toArray(new Renderable[parts.size()]); - } - - private Mat4[] getTransforms() { - return transforms.toArray(new Mat4[transforms.size()]); - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import glm.mat._4.Mat4; + +public class StaticModel extends Model { + + private static final Mat4 IDENTITY = new Mat4(); + + private final Mat4[] transforms; + + public StaticModel( + Renderable[] parts, + Mat4[] transforms + ) { + super(parts); + this.transforms = transforms; + } + + public StaticModel(Builder builder) { + this(builder.getParts(), builder.getTransforms()); + } + + @Override + protected Mat4 getTransform(int partIndex) { + return transforms[partIndex]; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private final List parts = new ArrayList<>(); + private final List transforms = new ArrayList<>(); + + protected Builder() { + } + + public Builder addPart( + Renderable part, + Mat4 transform + ) { + parts.add(Objects.requireNonNull(part, "part")); + transforms.add(Objects.requireNonNull(transform, "transform")); + + return this; + } + + public Builder addPart( + Renderable part + ) { + return addPart(part, IDENTITY); + } + + private Renderable[] getParts() { + return parts.toArray(new Renderable[parts.size()]); + } + + private Mat4[] getTransforms() { + return transforms.toArray(new Mat4[transforms.size()]); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java index 489d922..94ed270 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Atlases.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.texture; import java.io.IOException; @@ -69,8 +87,11 @@ public class Atlases { editor.draw(data, nextX, nextY); - Sprite result = new Sprite(getPrimitive(), toPrimitiveCoords(nextX, nextY), - toPrimitiveCoords(width, height)); + Sprite result = new Sprite( + getPrimitive(), + toPrimitiveCoords(nextX, nextY), + toPrimitiveCoords(width, height) + ); nextX += width; diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java index 8aaf4d4..a4f2881 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/ComplexTexture.java @@ -1,66 +1,97 @@ -package ru.windcorp.progressia.client.graphics.texture; - -import java.util.Map; - -import glm.vec._2.Vec2; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class ComplexTexture { - - private final TexturePrimitive primitive; - - private final float assumedWidth; - private final float assumedHeight; - - public ComplexTexture( - TexturePrimitive primitive, - int abstractWidth, int abstractHeight - ) { - this.primitive = primitive; - - this.assumedWidth = abstractWidth - / (float) primitive.getWidth() * primitive.getBufferWidth(); - - this.assumedHeight = abstractHeight - / (float) primitive.getHeight() * primitive.getBufferHeight(); - } - - public Texture get(int x, int y, int width, int height) { - return new SimpleTexture(new Sprite( - primitive, - new Vec2(x / assumedWidth, y / assumedHeight), - new Vec2(width / assumedWidth, height / assumedHeight) - )); - } - - public Map getCuboidTextures( - int x, int y, - int width, int height, int depth - ) { - return BlockFace.mapToFaces( - get( - x + depth + width, y + height + depth, - -width, -depth - ), - get( - x + depth + width + width, y + height + depth, - -width, -depth - ), - get(x + depth, y, width, height), - get( - x + depth + width + depth, y, - width, height - ), - get(x, y, depth, height), - get(x + depth + width, y, depth, height) - ); - } - - public Map getCuboidTextures( - int x, int y, - int size - ) { - return getCuboidTextures(x, y, size, size, size); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +import java.util.Map; + +import glm.vec._2.Vec2; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class ComplexTexture { + + private final TexturePrimitive primitive; + + private final float assumedWidth; + private final float assumedHeight; + + public ComplexTexture( + TexturePrimitive primitive, + int abstractWidth, + int abstractHeight + ) { + this.primitive = primitive; + + this.assumedWidth = abstractWidth + / (float) primitive.getWidth() * primitive.getBufferWidth(); + + this.assumedHeight = abstractHeight + / (float) primitive.getHeight() * primitive.getBufferHeight(); + } + + public Texture get(int x, int y, int width, int height) { + return new SimpleTexture( + new Sprite( + primitive, + new Vec2(x / assumedWidth, y / assumedHeight), + new Vec2(width / assumedWidth, height / assumedHeight) + ) + ); + } + + public Map getCuboidTextures( + int x, + int y, + int width, + int height, + int depth + ) { + return BlockFace.mapToFaces( + get( + x + depth + width, + y + height + depth, + -width, + -depth + ), + get( + x + depth + width + width, + y + height + depth, + -width, + -depth + ), + get(x + depth, y, width, height), + get( + x + depth + width + depth, + y, + width, + height + ), + get(x, y, depth, height), + get(x + depth + width, y, depth, height) + ); + } + + public Map getCuboidTextures( + int x, + int y, + int size + ) { + return getCuboidTextures(x, y, size, size, size); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java index c628f3c..d772faa 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTexture.java @@ -1,33 +1,34 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -public class SimpleTexture extends Texture { - - private final Sprite sprite; - - public SimpleTexture(Sprite sprite) { - this.sprite = sprite; - } - - @Override - public Sprite getSprite() { - return sprite; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +public class SimpleTexture extends Texture { + + private final Sprite sprite; + + public SimpleTexture(Sprite sprite) { + this.sprite = sprite; + } + + @Override + public Sprite getSprite() { + return sprite; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java index 4b5ea61..12db086 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/SimpleTextures.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.texture; import java.io.IOException; @@ -24,11 +42,10 @@ public class SimpleTextures { private static Texture load(Resource resource) { try { - TextureDataEditor data = - TextureLoader.loadPixels(resource, SETTINGS); - + TextureDataEditor data = TextureLoader.loadPixels(resource, SETTINGS); + return new SimpleTexture( - new Sprite(new TexturePrimitive(data.getData())) + new Sprite(new TexturePrimitive(data.getData())) ); } catch (IOException e) { throw CrashReports.report(e, "Could not load texture %s", resource); @@ -36,6 +53,7 @@ public class SimpleTextures { } - private SimpleTextures() {} + private SimpleTextures() { + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java index 2145b9b..fc13896 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Sprite.java @@ -1,66 +1,71 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -import java.util.Objects; - -import glm.vec._2.Vec2; - -public class Sprite { - - private static final Vec2 ORIGIN = new Vec2(0, 0); - - private final TexturePrimitive primitive; - - private final Vec2 start; - private final Vec2 size; - - public Sprite(TexturePrimitive primitive, Vec2 start, Vec2 size) { - this.primitive = Objects.requireNonNull(primitive, "primitive"); - this.start = Objects.requireNonNull(start, "start"); - this.size = Objects.requireNonNull(size, "size"); - } - - public Sprite(TexturePrimitive primitive) { - this(primitive, ORIGIN, new Vec2( - primitive.getWidth() / (float) primitive.getBufferWidth(), - primitive.getHeight() / (float) primitive.getBufferHeight() - )); - } - - public TexturePrimitive getPrimitive() { - return primitive; - } - - public Vec2 getStart() { - return start; - } - - public Vec2 getSize() { - return size; - } - - public int getWidth() { - return (int) (size.x * primitive.getBufferWidth()); - } - - public int getHeight() { - return (int) (size.y * primitive.getBufferHeight()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +import java.util.Objects; + +import glm.vec._2.Vec2; + +public class Sprite { + + private static final Vec2 ORIGIN = new Vec2(0, 0); + + private final TexturePrimitive primitive; + + private final Vec2 start; + private final Vec2 size; + + public Sprite(TexturePrimitive primitive, Vec2 start, Vec2 size) { + this.primitive = Objects.requireNonNull(primitive, "primitive"); + this.start = Objects.requireNonNull(start, "start"); + this.size = Objects.requireNonNull(size, "size"); + } + + public Sprite(TexturePrimitive primitive) { + this( + primitive, + ORIGIN, + new Vec2( + primitive.getWidth() / (float) primitive.getBufferWidth(), + primitive.getHeight() / (float) primitive.getBufferHeight() + ) + ); + } + + public TexturePrimitive getPrimitive() { + return primitive; + } + + public Vec2 getStart() { + return start; + } + + public Vec2 getSize() { + return size; + } + + public int getWidth() { + return (int) (size.x * primitive.getBufferWidth()); + } + + public int getHeight() { + return (int) (size.y * primitive.getBufferHeight()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java index 5831f8a..a4d89bf 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/Texture.java @@ -1,24 +1,25 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -public abstract class Texture { - - public abstract Sprite getSprite(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +public abstract class Texture { + + public abstract Sprite getSprite(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java index afd44db..0453984 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureData.java @@ -1,105 +1,108 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL12.*; - -import java.nio.ByteBuffer; - -class TextureData { - - private final ByteBuffer data; - - private final int bufferWidth; - private final int bufferHeight; - - private final TextureSettings settings; - - private final int width; - private final int height; - - public TextureData( - ByteBuffer data, - int bufferWidth, int bufferHeight, - int width, int height, - TextureSettings settings - ) { - this.data = data; - this.width = width; - this.height = height; - this.bufferWidth = bufferWidth; - this.bufferHeight = bufferHeight; - this.settings = settings; - } - - public int load() { - int handle = glGenTextures(); - glBindTexture(GL_TEXTURE_2D, handle); - - if (settings.isFiltered()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D( - GL_TEXTURE_2D, // Load 2D image - 0, // Not mipmapped - GL_RGBA, // Use RGBA - bufferWidth, // Width - bufferHeight, // Height - 0, // No border - GL_RGBA, // Use RGBA (required) - GL_UNSIGNED_BYTE, // Use unsigned bytes - data // Data buffer - ); - - return handle; - } - - public ByteBuffer getData() { - return data; - } - - public int getBufferWidth() { - return bufferWidth; - } - - public int getBufferHeight() { - return bufferHeight; - } - - public int getContentWidth() { - return width; - } - - public int getContentHeight() { - return height; - } - - public TextureSettings getSettings() { - return settings; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL12.*; + +import java.nio.ByteBuffer; + +class TextureData { + + private final ByteBuffer data; + + private final int bufferWidth; + private final int bufferHeight; + + private final TextureSettings settings; + + private final int width; + private final int height; + + public TextureData( + ByteBuffer data, + int bufferWidth, + int bufferHeight, + int width, + int height, + TextureSettings settings + ) { + this.data = data; + this.width = width; + this.height = height; + this.bufferWidth = bufferWidth; + this.bufferHeight = bufferHeight; + this.settings = settings; + } + + public int load() { + int handle = glGenTextures(); + glBindTexture(GL_TEXTURE_2D, handle); + + if (settings.isFiltered()) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexImage2D( + GL_TEXTURE_2D, // Load 2D image + 0, // Not mipmapped + GL_RGBA, // Use RGBA + bufferWidth, // Width + bufferHeight, // Height + 0, // No border + GL_RGBA, // Use RGBA (required) + GL_UNSIGNED_BYTE, // Use unsigned bytes + data // Data buffer + ); + + return handle; + } + + public ByteBuffer getData() { + return data; + } + + public int getBufferWidth() { + return bufferWidth; + } + + public int getBufferHeight() { + return bufferHeight; + } + + public int getContentWidth() { + return width; + } + + public int getContentHeight() { + return height; + } + + public TextureSettings getSettings() { + return settings; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java index 1753d4b..7079f59 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureDataEditor.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.texture; import static ru.windcorp.progressia.client.graphics.texture.TextureUtil.BYTES_PER_PIXEL; @@ -7,189 +25,227 @@ import java.nio.ByteBuffer; import org.lwjgl.BufferUtils; public class TextureDataEditor { - + protected final TextureData data; - + public TextureDataEditor( - int bufferWidth, int bufferHeight, - int contentWidth, int contentHeight, - TextureSettings settings + int bufferWidth, + int bufferHeight, + int contentWidth, + int contentHeight, + TextureSettings settings ) { this.data = new TextureData( - BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4), - bufferWidth, bufferHeight, - contentWidth, contentHeight, - settings + BufferUtils.createByteBuffer(bufferWidth * bufferHeight * 4), + bufferWidth, + bufferHeight, + contentWidth, + contentHeight, + settings ); } - + public TextureDataEditor(TextureData data) { this.data = data; } - + public TextureData getData() { return data; } - + protected ByteBuffer getBuffer() { return getData().getData(); } - + public TextureData createSnapshot() { TextureData t = getData(); - + ByteBuffer fromBuffer = getBuffer(); ByteBuffer toBuffer = BufferUtils.createByteBuffer( - fromBuffer.capacity() + fromBuffer.capacity() ); - + copy(fromBuffer, 0, fromBuffer.capacity(), toBuffer); toBuffer.clear(); - + return new TextureData( - toBuffer, - t.getBufferWidth(), t.getBufferHeight(), - t.getContentWidth(), t.getContentHeight(), - t.getSettings() + toBuffer, + t.getBufferWidth(), + t.getBufferHeight(), + t.getContentWidth(), + t.getContentHeight(), + t.getSettings() ); } - + public TextureData createSnapshot(TextureData output) { ByteBuffer src = getBuffer(); ByteBuffer dst = output.getData(); - + int position = dst.position(); int limit = dst.limit(); - + try { copy(src, 0, src.capacity(), output.getData()); } finally { dst.limit(dst.capacity()).position(position).limit(limit); } - + return output; } public int getBufferWidth() { return getData().getBufferWidth(); } - + public int getBufferHeight() { return getData().getBufferHeight(); } - + public int getContentWidth() { return getData().getContentWidth(); } - + public int getContentHeight() { return getData().getContentHeight(); } - + public TextureSettings getSettings() { return getData().getSettings(); } - + public void draw( - ByteBuffer src, - int srcWidth, - int srcX, int srcY, - int dstX, int dstY, - int width, int height + ByteBuffer src, + int srcWidth, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height ) { ByteBuffer dst = getBuffer(); - + int position = src.position(); int limit = src.limit(); - + try { - + for (int line = 0; line < height; ++line) { src.limit(src.capacity()); - + position(dst, dstX, dstY + line, getBufferWidth()); position(src, srcX, srcY + line, srcWidth); setLength(src, width); - + dst.put(src); dst.clear(); } - + } finally { src.limit(src.capacity()).position(position).limit(limit); } } - + public void draw( - TextureData source, - int srcX, int srcY, - int dstX, int dstY, - int width, int height + TextureData source, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height ) { draw( - source.getData(), - source.getBufferWidth(), - srcX, srcY, dstX, dstY, width, height - ); - } - - public void draw( - TextureData source, - int dstX, int dstY - ) { - draw( - source, 0, 0, dstX, dstY, - source.getContentWidth(), source.getContentHeight() + source.getData(), + source.getBufferWidth(), + srcX, + srcY, + dstX, + dstY, + width, + height ); } public void draw( - TextureDataEditor source, - int srcX, int srcY, - int dstX, int dstY, - int width, int height + TextureData source, + int dstX, + int dstY ) { draw( - source.getData(), - srcX, srcY, dstX, dstY, width, height + source, + 0, + 0, + dstX, + dstY, + source.getContentWidth(), + source.getContentHeight() ); } - + public void draw( - TextureDataEditor source, - int dstX, int dstY + TextureDataEditor source, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height ) { draw( - source, 0, 0, dstX, dstY, - source.getContentWidth(), source.getContentHeight() + source.getData(), + srcX, + srcY, + dstX, + dstY, + width, + height ); } - + + public void draw( + TextureDataEditor source, + int dstX, + int dstY + ) { + draw( + source, + 0, + 0, + dstX, + dstY, + source.getContentWidth(), + source.getContentHeight() + ); + } + public void setPixel(int x, int y, int color) { ByteBuffer dst = getBuffer(); - + position(dst, x, y, getBufferWidth()); dst.putInt(color); dst.clear(); } - + private static void position(ByteBuffer buffer, int x, int y, int width) { buffer.position((y * width + x) * BYTES_PER_PIXEL); } - + private static void setLength(ByteBuffer buffer, int length) { buffer.limit(buffer.position() + length * BYTES_PER_PIXEL); } - + private static void copy( - ByteBuffer src, - int srcStart, int srcEnd, - ByteBuffer dst + ByteBuffer src, + int srcStart, + int srcEnd, + ByteBuffer dst ) { int position = src.position(); int limit = src.limit(); - + try { src.limit(src.capacity()).position(srcStart).limit(srcEnd); dst.put(src); diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java index fcebda7..18f2326 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureLoader.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.texture; import java.awt.Graphics2D; @@ -12,57 +30,79 @@ import ru.windcorp.progressia.common.resource.Resource; import ru.windcorp.progressia.common.util.BinUtil; public class TextureLoader { - + public static TextureDataEditor loadPixels( - InputStream compressed, TextureSettings settings - ) throws IOException { + InputStream compressed, + TextureSettings settings + ) + throws IOException { BufferedImage readResult = ImageIO.read(compressed); - + int width = readResult.getWidth(); int height = readResult.getHeight(); - + int bufferWidth = BinUtil.roundToGreaterPowerOf2(width); int bufferHeight = BinUtil.roundToGreaterPowerOf2(height); - + WritableRaster raster = TextureUtil.createRaster( - bufferWidth, bufferHeight + bufferWidth, + bufferHeight ); - + BufferedImage canvas = TextureUtil.createCanvas(raster); Graphics2D g = canvas.createGraphics(); - + try { g.setColor(TextureUtil.CANVAS_BACKGROUND); g.fillRect(0, 0, bufferWidth, bufferHeight); g.drawImage( - readResult, - 0, 0, width, height, - 0, height, width, 0, // Flip the image - null + readResult, + 0, + 0, + width, + height, + 0, + height, + width, + 0, // Flip the image + null ); } finally { g.dispose(); } - + TextureDataEditor result = new TextureDataEditor( - bufferWidth, bufferHeight, width, height, settings + bufferWidth, + bufferHeight, + width, + height, + settings ); - + result.draw( - TextureUtil.extractBytes(raster), bufferWidth, - 0, 0, 0, 0, width, height + TextureUtil.extractBytes(raster), + bufferWidth, + 0, + 0, + 0, + 0, + width, + height ); - + return result; } - + public static TextureDataEditor loadPixels( - Resource resource, TextureSettings settings - ) throws IOException { + Resource resource, + TextureSettings settings + ) + throws IOException { return loadPixels(resource.getInputStream(), settings); } - - private TextureLoader() {} + + private TextureLoader() { + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java index be05ac7..a1895bb 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TexturePrimitive.java @@ -1,110 +1,112 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL20.*; - -import java.util.Arrays; - -import org.lwjgl.opengl.GL11; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; -import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class TexturePrimitive implements OpenGLDeletable { - - private static final int NOT_LOADED = -1; - - private static int[] currentlyBound = new int[32]; - static { - Arrays.fill(currentlyBound, NOT_LOADED); - } - - private static int nextId = 0; - - private int id = nextId++; - private int handle = NOT_LOADED; - private TextureData pixels; - - public TexturePrimitive(TextureData pixels) { - this.pixels = pixels; - } - - public TextureData getData() { - return pixels; - } - - public int getBufferWidth() { - return pixels.getBufferWidth(); - } - - public int getBufferHeight() { - return pixels.getBufferHeight(); - } - - public int getWidth() { - return pixels.getContentWidth(); - } - - public int getHeight() { - return pixels.getContentHeight(); - } - - public boolean isLoaded() { - return handle != NOT_LOADED; - } - - public void bind(int slot) { - if (!isLoaded()) { - load(); - } - - if (currentlyBound[slot] == handle) { - return; - } - - int code = GL_TEXTURE0 + slot; - - glActiveTexture(code); - glBindTexture(GL_TEXTURE_2D, handle); - - currentlyBound[slot] = handle; - } - - public void load() { - if (isLoaded()) return; - - handle = pixels.load(); - OpenGLObjectTracker.register(this, GL11::glDeleteTextures); - - if (handle < 0) { - throw CrashReports.report(null, "Failed to allocate texture"); - } - } - - @Override - public int getHandle() { - return handle; - } - - public int getId() { - return id; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL20.*; + +import java.util.Arrays; + +import org.lwjgl.opengl.GL11; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker; +import ru.windcorp.progressia.client.graphics.backend.OpenGLObjectTracker.OpenGLDeletable; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class TexturePrimitive implements OpenGLDeletable { + + private static final int NOT_LOADED = -1; + + private static int[] currentlyBound = new int[32]; + static { + Arrays.fill(currentlyBound, NOT_LOADED); + } + + private static int nextId = 0; + + private int id = nextId++; + private int handle = NOT_LOADED; + private TextureData pixels; + + public TexturePrimitive(TextureData pixels) { + this.pixels = pixels; + } + + public TextureData getData() { + return pixels; + } + + public int getBufferWidth() { + return pixels.getBufferWidth(); + } + + public int getBufferHeight() { + return pixels.getBufferHeight(); + } + + public int getWidth() { + return pixels.getContentWidth(); + } + + public int getHeight() { + return pixels.getContentHeight(); + } + + public boolean isLoaded() { + return handle != NOT_LOADED; + } + + public void bind(int slot) { + if (!isLoaded()) { + load(); + } + + if (currentlyBound[slot] == handle) { + return; + } + + int code = GL_TEXTURE0 + slot; + + glActiveTexture(code); + glBindTexture(GL_TEXTURE_2D, handle); + + currentlyBound[slot] = handle; + } + + public void load() { + if (isLoaded()) + return; + + handle = pixels.load(); + OpenGLObjectTracker.register(this, GL11::glDeleteTextures); + + if (handle < 0) { + throw CrashReports.report(null, "Failed to allocate texture"); + } + } + + @Override + public int getHandle() { + return handle; + } + + public int getId() { + return id; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java index 807bd3f..3dd43a4 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureSettings.java @@ -1,32 +1,33 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.texture; - -public class TextureSettings { - - private final boolean isFiltered; - - public TextureSettings(boolean isFiltered) { - this.isFiltered = isFiltered; - } - - public boolean isFiltered() { - return isFiltered; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.texture; + +public class TextureSettings { + + private final boolean isFiltered; + + public TextureSettings(boolean isFiltered) { + this.isFiltered = isFiltered; + } + + public boolean isFiltered() { + return isFiltered; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java index 88665cf..ea0fdee 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/texture/TextureUtil.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.texture; import java.awt.Color; @@ -16,95 +34,92 @@ import java.util.Hashtable; import org.lwjgl.BufferUtils; public class TextureUtil { - + public static final int BYTES_PER_PIXEL = 4; // ARGB - + public static final Color CANVAS_BACKGROUND = new Color(0, true); - + public static final ColorModel COLOR_MODEL = new ComponentColorModel( - ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB - null, // Use every bit - true, // Has alpha - false, // Not premultiplied - Transparency.TRANSLUCENT, // Can have any alpha - DataBuffer.TYPE_BYTE // Store bytewise + ColorSpace.getInstance(ColorSpace.CS_sRGB), // Use RGB + null, // Use every bit + true, // Has alpha + false, // Not premultiplied + Transparency.TRANSLUCENT, // Can have any alpha + DataBuffer.TYPE_BYTE // Store bytewise ); - - private static final Hashtable BUFFERED_IMAGE_PROPERTIES = - new Hashtable<>(); - + + private static final Hashtable BUFFERED_IMAGE_PROPERTIES = new Hashtable<>(); + public static WritableRaster createRaster( - int bufferWidth, - int bufferHeight + int bufferWidth, + int bufferHeight ) { return Raster.createInterleavedRaster( - DataBuffer.TYPE_BYTE, // Storage model - bufferWidth, // Buffer width - bufferHeight, // Buffer height - BYTES_PER_PIXEL, // ARGB - null // Location (here (0; 0)) + DataBuffer.TYPE_BYTE, // Storage model + bufferWidth, // Buffer width + bufferHeight, // Buffer height + BYTES_PER_PIXEL, // ARGB + null // Location (here (0; 0)) ); } - + public static WritableRaster createRaster( - ByteBuffer buffer, - int bufferWidth, - int bufferHeight + ByteBuffer buffer, + int bufferWidth, + int bufferHeight ) { final int bands = BYTES_PER_PIXEL; - + byte[] bytes = new byte[bufferWidth * bufferHeight * bands]; - + buffer.get(bytes); buffer.position(buffer.position() - bytes.length); - + DataBufferByte dataBuffer = new DataBufferByte(bytes, bytes.length); - + return Raster.createInterleavedRaster( - dataBuffer, // The buffer - bufferWidth, // Buffer width - bufferHeight, // Buffer height - bands * bufferWidth, // Scanline stride - bands, // Pixel stride - new int[] {0, 1, 2, 3}, // Band offsets - null // Location (here (0; 0)) + dataBuffer, // The buffer + bufferWidth, // Buffer width + bufferHeight, // Buffer height + bands * bufferWidth, // Scanline stride + bands, // Pixel stride + new int[] { 0, 1, 2, 3 }, // Band offsets + null // Location (here (0; 0)) ); } - + public static BufferedImage createCanvas(WritableRaster raster) { return new BufferedImage( - COLOR_MODEL, // Color model - raster, // Backing raster - false, // Raster is not premultipied - BUFFERED_IMAGE_PROPERTIES // Properties + COLOR_MODEL, // Color model + raster, // Backing raster + false, // Raster is not premultipied + BUFFERED_IMAGE_PROPERTIES // Properties ); } - + public static ByteBuffer extractBytes(WritableRaster raster) { - byte[] data = ( - (DataBufferByte) raster.getDataBuffer() - ).getData(); - + byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData(); + ByteBuffer buffer = BufferUtils.createByteBuffer(data.length); buffer.put(data); buffer.flip(); - + return buffer; } - + public static ByteBuffer extractBytes( - WritableRaster raster, ByteBuffer output + WritableRaster raster, + ByteBuffer output ) { - byte[] data = ( - (DataBufferByte) raster.getDataBuffer() - ).getData(); - + byte[] data = ((DataBufferByte) raster.getDataBuffer()).getData(); + output.put(data); output.flip(); - + return output; } - - private TextureUtil() {} + + private TextureUtil() { + } } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java index a7c1b93..46b551c 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Camera.java @@ -1,297 +1,316 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.world; - -import static java.lang.Math.*; -import static ru.windcorp.progressia.common.util.FloatMathUtil.*; - -import java.util.Collection; -import java.util.function.Consumer; - -import glm.Glm; -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.world.Camera.Anchor.Mode; - -public class Camera { - - public static interface Anchor { - - /** - * Offset is applied after the rotation. - */ - public static interface Mode { - void getCameraOffset(Vec3 output); - void applyCameraRotation(Mat4 output); - - public static Mode of( - Consumer offsetGetter, - Consumer rotator - ) { - return new Mode() { - @Override - public void getCameraOffset(Vec3 output) { - offsetGetter.accept(output); - } - - @Override - public void applyCameraRotation(Mat4 output) { - rotator.accept(output); - } - }; - } - } - - void getCameraPosition(Vec3 output); - void getCameraVelocity(Vec3 output); - float getCameraYaw(); - float getCameraPitch(); - - Collection getCameraModes(); - - } - - private Anchor anchor; - - private Anchor.Mode[] modes; - private int currentModeIndex; - - private float fieldOfView; - - /* - * Cache - */ - - private final Vec3 lastAnchorPosition = new Vec3(); - private float lastAnchorYaw; - private float lastAnchorPitch; - - private final Mat4 lastCameraMatrix = new Mat4(); - - private final Vec3 lastAnchorLookingAt = new Vec3(); - private final Vec3 lastAnchorUp = new Vec3(); - - { - invalidateCache(); - } - - public Camera(float fieldOfView) { - setFieldOfView(fieldOfView); - } - - public Camera() {} - - /* - * apply() and subroutines - */ - - public void apply(WorldRenderHelper helper) { - applyPerspective(helper); - rotateCoordinateSystem(helper); - - applyMode(helper); - applyDirection(helper); - applyPosition(helper); - - cacheCameraTransform(helper); - } - - private void applyPerspective(WorldRenderHelper helper) { - Mat4 previous = helper.getViewTransform(); - - Glm.perspective( - computeFovY(), - GraphicsInterface.getAspectRatio(), - 0.01f, 150.0f, - helper.pushViewTransform() - ).mul(previous); - } - - private void rotateCoordinateSystem(WorldRenderHelper helper) { - helper.pushViewTransform().rotateX(-PI / 2).rotateZ(PI / 2); - } - - private void applyMode(WorldRenderHelper helper) { - Mode mode = getMode(); - - Mat4 matrix = helper.pushViewTransform(); - - Vec3 offset = new Vec3(); - mode.getCameraOffset(offset); - - offset.negate(); - matrix.translate(offset); - - mode.applyCameraRotation(matrix); - } - - private void applyDirection(WorldRenderHelper helper) { - float pitch = anchor.getCameraPitch(); - float yaw = anchor.getCameraYaw(); - - helper.pushViewTransform() - .rotateY(-pitch) - .rotateZ(-yaw); - - this.lastAnchorYaw = yaw; - this.lastAnchorPitch = pitch; - - this.lastAnchorLookingAt.set( - cos(pitch) * cos(yaw), - cos(pitch) * sin(yaw), - sin(pitch) - ); - this.lastAnchorUp.set( - cos(pitch + PI_F / 2) * cos(yaw), - cos(pitch + PI_F / 2) * sin(yaw), - sin(pitch + PI_F / 2) - ); - } - - private void applyPosition(WorldRenderHelper helper) { - Vec3 v = new Vec3(); - anchor.getCameraPosition(v); - this.lastAnchorPosition.set(v); - - v.negate(); - helper.pushViewTransform().translate(v); - } - - private void cacheCameraTransform(WorldRenderHelper helper) { - this.lastCameraMatrix.set(helper.getViewTransform()); - } - - /* - * FOV management - */ - - private float computeFovY() { - float widthOverHeight = GraphicsInterface.getAspectRatio(); - - if (widthOverHeight >= 1) { - return fieldOfView; - } else { - return (float) (2 * atan( - 1 / widthOverHeight - * - tan(fieldOfView / 2) - )); - } - } - - public float getFieldOfView() { - return fieldOfView; - } - - public void setFieldOfView(float fieldOfView) { - this.fieldOfView = fieldOfView; - } - - /* - * Anchor management - */ - - public Anchor getAnchor() { - return anchor; - } - - public boolean hasAnchor() { - return anchor != null; - } - - public void setAnchor(Anchor anchor) { - if (anchor == null) { - this.anchor = null; - this.modes = null; - invalidateCache(); - return; - } - - Collection modesCollection = anchor.getCameraModes(); - - if (modesCollection.isEmpty()) { - throw new IllegalArgumentException( - "Anchor " + anchor + " returned no camera modes," - + " at least one required" - ); - } - - this.anchor = anchor; - - this.modes = modesCollection.toArray(new Mode[modesCollection.size()]); - this.currentModeIndex = 0; - } - - private void invalidateCache() { - this.lastAnchorPosition.set(Float.NaN); - this.lastAnchorYaw = Float.NaN; - this.lastAnchorPitch = Float.NaN; - - this.lastCameraMatrix.set( - Float.NaN, Float.NaN, Float.NaN, Float.NaN, - Float.NaN, Float.NaN, Float.NaN, Float.NaN, - Float.NaN, Float.NaN, Float.NaN, Float.NaN, - Float.NaN, Float.NaN, Float.NaN, Float.NaN - ); - - this.lastAnchorLookingAt.set(Float.NaN); - this.lastAnchorUp.set(Float.NaN); - } - - public Anchor.Mode getMode() { - return modes[currentModeIndex]; - } - - public void selectNextMode() { - if (currentModeIndex == modes.length - 1) { - currentModeIndex = 0; - } else { - currentModeIndex++; - } - } - - public int getCurrentModeIndex() { - return currentModeIndex; - } - - public float getLastAnchorYaw() { - return lastAnchorYaw; - } - - public float getLastAnchorPitch() { - return lastAnchorPitch; - } - - public Vec3 getLastAnchorPosition() { - return lastAnchorPosition; - } - - public Mat4 getLastCameraMatrix() { - return lastCameraMatrix; - } - - public Vec3 getLastAnchorLookingAt() { - return lastAnchorLookingAt; - } - - public Vec3 getLastAnchorUp() { - return lastAnchorUp; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.world; + +import static java.lang.Math.*; +import static ru.windcorp.progressia.common.util.FloatMathUtil.*; + +import java.util.Collection; +import java.util.function.Consumer; + +import glm.Glm; +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; +import ru.windcorp.progressia.client.graphics.world.Camera.Anchor.Mode; + +public class Camera { + + public static interface Anchor { + + /** + * Offset is applied after the rotation. + */ + public static interface Mode { + void getCameraOffset(Vec3 output); + + void applyCameraRotation(Mat4 output); + + public static Mode of( + Consumer offsetGetter, + Consumer rotator + ) { + return new Mode() { + @Override + public void getCameraOffset(Vec3 output) { + offsetGetter.accept(output); + } + + @Override + public void applyCameraRotation(Mat4 output) { + rotator.accept(output); + } + }; + } + } + + void getCameraPosition(Vec3 output); + + void getCameraVelocity(Vec3 output); + + float getCameraYaw(); + + float getCameraPitch(); + + Collection getCameraModes(); + + } + + private Anchor anchor; + + private Anchor.Mode[] modes; + private int currentModeIndex; + + private float fieldOfView; + + /* + * Cache + */ + + private final Vec3 lastAnchorPosition = new Vec3(); + private float lastAnchorYaw; + private float lastAnchorPitch; + + private final Mat4 lastCameraMatrix = new Mat4(); + + private final Vec3 lastAnchorLookingAt = new Vec3(); + private final Vec3 lastAnchorUp = new Vec3(); + + { + invalidateCache(); + } + + public Camera(float fieldOfView) { + setFieldOfView(fieldOfView); + } + + public Camera() { + } + + /* + * apply() and subroutines + */ + + public void apply(WorldRenderHelper helper) { + applyPerspective(helper); + rotateCoordinateSystem(helper); + + applyMode(helper); + applyDirection(helper); + applyPosition(helper); + + cacheCameraTransform(helper); + } + + private void applyPerspective(WorldRenderHelper helper) { + Mat4 previous = helper.getViewTransform(); + + Glm.perspective( + computeFovY(), + GraphicsInterface.getAspectRatio(), + 0.01f, + 150.0f, + helper.pushViewTransform() + ).mul(previous); + } + + private void rotateCoordinateSystem(WorldRenderHelper helper) { + helper.pushViewTransform().rotateX(-PI / 2).rotateZ(PI / 2); + } + + private void applyMode(WorldRenderHelper helper) { + Mode mode = getMode(); + + Mat4 matrix = helper.pushViewTransform(); + + Vec3 offset = new Vec3(); + mode.getCameraOffset(offset); + + offset.negate(); + matrix.translate(offset); + + mode.applyCameraRotation(matrix); + } + + private void applyDirection(WorldRenderHelper helper) { + float pitch = anchor.getCameraPitch(); + float yaw = anchor.getCameraYaw(); + + helper.pushViewTransform() + .rotateY(-pitch) + .rotateZ(-yaw); + + this.lastAnchorYaw = yaw; + this.lastAnchorPitch = pitch; + + this.lastAnchorLookingAt.set( + cos(pitch) * cos(yaw), + cos(pitch) * sin(yaw), + sin(pitch) + ); + this.lastAnchorUp.set( + cos(pitch + PI_F / 2) * cos(yaw), + cos(pitch + PI_F / 2) * sin(yaw), + sin(pitch + PI_F / 2) + ); + } + + private void applyPosition(WorldRenderHelper helper) { + Vec3 v = new Vec3(); + anchor.getCameraPosition(v); + this.lastAnchorPosition.set(v); + + v.negate(); + helper.pushViewTransform().translate(v); + } + + private void cacheCameraTransform(WorldRenderHelper helper) { + this.lastCameraMatrix.set(helper.getViewTransform()); + } + + /* + * FOV management + */ + + private float computeFovY() { + float widthOverHeight = GraphicsInterface.getAspectRatio(); + + if (widthOverHeight >= 1) { + return fieldOfView; + } else { + return (float) (2 * atan( + 1 / widthOverHeight + * + tan(fieldOfView / 2) + )); + } + } + + public float getFieldOfView() { + return fieldOfView; + } + + public void setFieldOfView(float fieldOfView) { + this.fieldOfView = fieldOfView; + } + + /* + * Anchor management + */ + + public Anchor getAnchor() { + return anchor; + } + + public boolean hasAnchor() { + return anchor != null; + } + + public void setAnchor(Anchor anchor) { + if (anchor == null) { + this.anchor = null; + this.modes = null; + invalidateCache(); + return; + } + + Collection modesCollection = anchor.getCameraModes(); + + if (modesCollection.isEmpty()) { + throw new IllegalArgumentException( + "Anchor " + anchor + " returned no camera modes," + + " at least one required" + ); + } + + this.anchor = anchor; + + this.modes = modesCollection.toArray(new Mode[modesCollection.size()]); + this.currentModeIndex = 0; + } + + private void invalidateCache() { + this.lastAnchorPosition.set(Float.NaN); + this.lastAnchorYaw = Float.NaN; + this.lastAnchorPitch = Float.NaN; + + this.lastCameraMatrix.set( + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN, + Float.NaN + ); + + this.lastAnchorLookingAt.set(Float.NaN); + this.lastAnchorUp.set(Float.NaN); + } + + public Anchor.Mode getMode() { + return modes[currentModeIndex]; + } + + public void selectNextMode() { + if (currentModeIndex == modes.length - 1) { + currentModeIndex = 0; + } else { + currentModeIndex++; + } + } + + public int getCurrentModeIndex() { + return currentModeIndex; + } + + public float getLastAnchorYaw() { + return lastAnchorYaw; + } + + public float getLastAnchorPitch() { + return lastAnchorPitch; + } + + public Vec3 getLastAnchorPosition() { + return lastAnchorPosition; + } + + public Mat4 getLastCameraMatrix() { + return lastCameraMatrix; + } + + public Vec3 getLastAnchorLookingAt() { + return lastAnchorLookingAt; + } + + public Vec3 getLastAnchorUp() { + return lastAnchorUp; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java index 86f859f..d11ea92 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/EntityAnchor.java @@ -1,67 +1,87 @@ -package ru.windcorp.progressia.client.graphics.world; - -import java.util.Collection; - -import com.google.common.collect.ImmutableList; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.world.Camera.Anchor; -import ru.windcorp.progressia.client.world.entity.EntityRenderable; -import ru.windcorp.progressia.common.world.entity.EntityData; - -public class EntityAnchor implements Anchor { - - private final EntityData entity; - private final EntityRenderable model; - - private final Collection modes; - - public EntityAnchor(EntityRenderable model) { - this.entity = model.getData(); - this.model = model; - - this.modes = ImmutableList.of( - // From viewpoint / first person - Mode.of(v -> v.set(0), m -> {}), - - // Third person, looking forward - Mode.of( - v -> v.set(-3.5f, +0.5f, 0), - m -> {} - ), - - // Third person, looking back - Mode.of( - v -> v.set(-3.5f, 0, 0), - m -> m.rotateZ((float) Math.PI) - ) - ); - } - - @Override - public void getCameraPosition(Vec3 output) { - model.getViewPoint(output); - output.add(entity.getPosition()); - } - - @Override - public void getCameraVelocity(Vec3 output) { - output.set(entity.getVelocity()); - } - - @Override - public float getCameraYaw() { - return entity.getYaw(); - } - - @Override - public float getCameraPitch() { - return entity.getPitch(); - } - - @Override - public Collection getCameraModes() { - return modes; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.world; + +import java.util.Collection; + +import com.google.common.collect.ImmutableList; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.world.Camera.Anchor; +import ru.windcorp.progressia.client.world.entity.EntityRenderable; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public class EntityAnchor implements Anchor { + + private final EntityData entity; + private final EntityRenderable model; + + private final Collection modes; + + public EntityAnchor(EntityRenderable model) { + this.entity = model.getData(); + this.model = model; + + this.modes = ImmutableList.of( + // From viewpoint / first person + Mode.of(v -> v.set(0), m -> { + }), + + // Third person, looking forward + Mode.of( + v -> v.set(-3.5f, +0.5f, 0), + m -> { + } + ), + + // Third person, looking back + Mode.of( + v -> v.set(-3.5f, 0, 0), + m -> m.rotateZ((float) Math.PI) + ) + ); + } + + @Override + public void getCameraPosition(Vec3 output) { + model.getViewPoint(output); + output.add(entity.getPosition()); + } + + @Override + public void getCameraVelocity(Vec3 output) { + output.set(entity.getVelocity()); + } + + @Override + public float getCameraYaw() { + return entity.getYaw(); + } + + @Override + public float getCameraPitch() { + return entity.getPitch(); + } + + @Override + public Collection getCameraModes() { + return modes; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java index 9fc4b5f..0db08f1 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LayerWorld.java @@ -1,211 +1,224 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.world; - -import java.util.ArrayList; -import java.util.List; - -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.Client; -import ru.windcorp.progressia.client.ClientState; -import ru.windcorp.progressia.client.comms.controls.InputBasedControls; -import ru.windcorp.progressia.client.graphics.Layer; -import ru.windcorp.progressia.client.graphics.backend.FaceCulling; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.input.bus.Input; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; -import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder; -import ru.windcorp.progressia.client.graphics.model.StaticModel; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.collision.Collideable; -import ru.windcorp.progressia.common.collision.colliders.Collider; -import ru.windcorp.progressia.common.util.FloatMathUtil; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.test.CollisionModelRenderer; -import ru.windcorp.progressia.test.TestPlayerControls; - -public class LayerWorld extends Layer { - - private final WorldRenderHelper helper = new WorldRenderHelper(); - - private final Client client; - private final InputBasedControls inputBasedControls; - private final TestPlayerControls tmp_testControls = TestPlayerControls.getInstance(); - - public LayerWorld(Client client) { - super("World"); - this.client = client; - this.inputBasedControls = new InputBasedControls(client); - } - - @Override - protected void initialize() { - // TODO Auto-generated method stub - - } - - @Override - protected void doValidate() { - // Do nothing - } - - @Override - protected void doRender() { - Camera camera = client.getCamera(); - if (camera.hasAnchor()) { - renderWorld(); - } - - client.getLocalPlayer().getEntity(); - - if (client.isReady()) { - client.getLocalPlayer().update(client.getWorld()); - } - } - - private void renderWorld() { - client.getCamera().apply(helper); - FaceCulling.push(true); - - this.client.getWorld().render(helper); - - tmp_doEveryFrame(); - - FaceCulling.pop(); - helper.reset(); - } - - private final Collider.ColliderWorkspace tmp_colliderWorkspace = new Collider.ColliderWorkspace(); - private final List tmp_collideableList = new ArrayList<>(); - - private static final boolean RENDER_COLLISION_MODELS = false; - - private void tmp_doEveryFrame() { - float tickLength = (float) GraphicsInterface.getFrameLength(); - - try { - tmp_performCollisions(tickLength); - tmp_drawSelectionBox(); - - tmp_testControls.applyPlayerControls(); - - for (EntityData data : this.client.getWorld().getData().getEntities()) { - tmp_applyFriction(data, tickLength); - tmp_applyGravity(data, tickLength); - tmp_renderCollisionModel(data); - } - } catch (Throwable e) { - e.printStackTrace(); - System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!"); - System.exit(31337); - } - } - - private void tmp_renderCollisionModel(EntityData entity) { - if (RENDER_COLLISION_MODELS) { - CollisionModelRenderer.renderCollisionModel(entity.getCollisionModel(), helper); - } - } - - private void tmp_performCollisions(float tickLength) { - tmp_collideableList.clear(); - tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); - - Collider.performCollisions( - tmp_collideableList, - this.client.getWorld().getData(), - tickLength, - tmp_colliderWorkspace - ); - } - - private static final Renderable SELECTION_BOX = tmp_createSelectionBox(); - - private void tmp_drawSelectionBox() { - if (!client.isReady()) return; - - Vec3i selection = client.getLocalPlayer().getSelection().getBlock(); - if (selection == null) return; - - helper.pushTransform().translate(selection.x, selection.y, selection.z); - SELECTION_BOX.render(helper); - helper.popTransform(); - } - - private static Renderable tmp_createSelectionBox() { - StaticModel.Builder b = StaticModel.builder(); - ShapeRenderProgram p = WorldRenderProgram.getDefault(); - - final float f = 1e-2f; - final float scale = 1 - f/2; - final Vec4 color = new Vec4(0, 0, 0, 1); - - for (float phi = 0; phi < 2*FloatMathUtil.PI_F; phi += FloatMathUtil.PI_F/2) { - Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale); - - b.addPart(new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f) - ).setSize(f, f, 2*f + 1).setColorMultiplier(color).create(), rot); - - b.addPart(new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, - 0.5f, -f - 0.5f) - ).setSize(f, 1, f).setColorMultiplier(color).create(), rot); - - b.addPart(new PppBuilder(p, (Texture) null).setOrigin( - new Vec3(-f - 0.5f, - 0.5f, + 0.5f) - ).setSize(f, 1, f).setColorMultiplier(color).create(), rot); - } - - return new StaticModel(b); - } - - private static final float FRICTION_COEFF = Units.get("1e-5f kg/s"); - - private void tmp_applyFriction(EntityData entity, float tickLength) { - entity.getVelocity().mul((float) Math.exp(-FRICTION_COEFF / entity.getCollisionMass() * tickLength)); - } - - private static final float MC_g = Units.get("32 m/s^2"); - private static final float IRL_g = Units.get("9.8 m/s^2"); - - private void tmp_applyGravity(EntityData entity, float tickLength) { - if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) { - return; - } - - final float gravitationalAcceleration = tmp_testControls.useMinecraftGravity() ? MC_g : IRL_g; - entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength); - } - - @Override - protected void handleInput(Input input) { - if (input.isConsumed()) return; - - tmp_testControls.handleInput(input); - - if (!input.isConsumed()) { - inputBasedControls.handleInput(input); - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.world; + +import java.util.ArrayList; +import java.util.List; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.client.ClientState; +import ru.windcorp.progressia.client.comms.controls.InputBasedControls; +import ru.windcorp.progressia.client.graphics.Layer; +import ru.windcorp.progressia.client.graphics.backend.FaceCulling; +import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; +import ru.windcorp.progressia.client.graphics.input.bus.Input; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder; +import ru.windcorp.progressia.client.graphics.model.StaticModel; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.collision.Collideable; +import ru.windcorp.progressia.common.collision.colliders.Collider; +import ru.windcorp.progressia.common.util.FloatMathUtil; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.test.CollisionModelRenderer; +import ru.windcorp.progressia.test.TestPlayerControls; + +public class LayerWorld extends Layer { + + private final WorldRenderHelper helper = new WorldRenderHelper(); + + private final Client client; + private final InputBasedControls inputBasedControls; + private final TestPlayerControls tmp_testControls = TestPlayerControls.getInstance(); + + public LayerWorld(Client client) { + super("World"); + this.client = client; + this.inputBasedControls = new InputBasedControls(client); + } + + @Override + protected void initialize() { + // TODO Auto-generated method stub + + } + + @Override + protected void doValidate() { + // Do nothing + } + + @Override + protected void doRender() { + Camera camera = client.getCamera(); + if (camera.hasAnchor()) { + renderWorld(); + } + + client.getLocalPlayer().getEntity(); + + if (client.isReady()) { + client.getLocalPlayer().update(client.getWorld()); + } + } + + private void renderWorld() { + client.getCamera().apply(helper); + FaceCulling.push(true); + + this.client.getWorld().render(helper); + + tmp_doEveryFrame(); + + FaceCulling.pop(); + helper.reset(); + } + + private final Collider.ColliderWorkspace tmp_colliderWorkspace = new Collider.ColliderWorkspace(); + private final List tmp_collideableList = new ArrayList<>(); + + private static final boolean RENDER_COLLISION_MODELS = false; + + private void tmp_doEveryFrame() { + float tickLength = (float) GraphicsInterface.getFrameLength(); + + try { + tmp_performCollisions(tickLength); + tmp_drawSelectionBox(); + + tmp_testControls.applyPlayerControls(); + + for (EntityData data : this.client.getWorld().getData().getEntities()) { + tmp_applyFriction(data, tickLength); + tmp_applyGravity(data, tickLength); + tmp_renderCollisionModel(data); + } + } catch (Throwable e) { + e.printStackTrace(); + System.err.println("OLEGSHA is to blame. Tell him he vry stupiDD!!"); + System.exit(31337); + } + } + + private void tmp_renderCollisionModel(EntityData entity) { + if (RENDER_COLLISION_MODELS) { + CollisionModelRenderer.renderCollisionModel(entity.getCollisionModel(), helper); + } + } + + private void tmp_performCollisions(float tickLength) { + tmp_collideableList.clear(); + tmp_collideableList.addAll(this.client.getWorld().getData().getEntities()); + + Collider.performCollisions( + tmp_collideableList, + this.client.getWorld().getData(), + tickLength, + tmp_colliderWorkspace + ); + } + + private static final Renderable SELECTION_BOX = tmp_createSelectionBox(); + + private void tmp_drawSelectionBox() { + if (!client.isReady()) + return; + + Vec3i selection = client.getLocalPlayer().getSelection().getBlock(); + if (selection == null) + return; + + helper.pushTransform().translate(selection.x, selection.y, selection.z); + SELECTION_BOX.render(helper); + helper.popTransform(); + } + + private static Renderable tmp_createSelectionBox() { + StaticModel.Builder b = StaticModel.builder(); + ShapeRenderProgram p = WorldRenderProgram.getDefault(); + + final float f = 1e-2f; + final float scale = 1 - f / 2; + final Vec4 color = new Vec4(0, 0, 0, 1); + + for (float phi = 0; phi < 2 * FloatMathUtil.PI_F; phi += FloatMathUtil.PI_F / 2) { + Mat4 rot = new Mat4().identity().rotateZ(phi).scale(scale); + + b.addPart( + new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, -f - 0.5f, -f - 0.5f) + ).setSize(f, f, 2 * f + 1).setColorMultiplier(color).create(), + rot + ); + + b.addPart( + new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, -0.5f, -f - 0.5f) + ).setSize(f, 1, f).setColorMultiplier(color).create(), + rot + ); + + b.addPart( + new PppBuilder(p, (Texture) null).setOrigin( + new Vec3(-f - 0.5f, -0.5f, +0.5f) + ).setSize(f, 1, f).setColorMultiplier(color).create(), + rot + ); + } + + return new StaticModel(b); + } + + private static final float FRICTION_COEFF = Units.get("1e-5f kg/s"); + + private void tmp_applyFriction(EntityData entity, float tickLength) { + entity.getVelocity().mul((float) Math.exp(-FRICTION_COEFF / entity.getCollisionMass() * tickLength)); + } + + private static final float MC_g = Units.get("32 m/s^2"); + private static final float IRL_g = Units.get("9.8 m/s^2"); + + private void tmp_applyGravity(EntityData entity, float tickLength) { + if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) { + return; + } + + final float gravitationalAcceleration = tmp_testControls.useMinecraftGravity() ? MC_g : IRL_g; + entity.getVelocity().add(0, 0, -gravitationalAcceleration * tickLength); + } + + @Override + protected void handleInput(Input input) { + if (input.isConsumed()) + return; + + tmp_testControls.handleInput(input); + + if (!input.isConsumed()) { + inputBasedControls.handleInput(input); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java index c877973..620185b 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/LocalPlayer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.world; import ru.windcorp.progressia.client.Client; @@ -8,58 +26,58 @@ import ru.windcorp.progressia.common.world.entity.EntityData; public class LocalPlayer { private final Client client; - + private long entityId = EntityData.NULL_ENTITY_ID; private EntityData lastKnownEntity = null; - + private final Selection selection = new Selection(); - + public LocalPlayer(Client client) { this.client = client; } - + public Client getClient() { return client; } - + public long getEntityId() { return entityId; } - + public void setEntityId(long entityId) { this.entityId = entityId; - + this.lastKnownEntity = null; getEntity(); } - + public boolean hasEntityId() { return entityId != EntityData.NULL_ENTITY_ID; } - + public boolean hasEntity() { return getEntity() != null; } - + public EntityData getEntity() { if (!hasEntityId()) { return null; } - + EntityData entity = getClient().getWorld().getData().getEntity(getEntityId()); - + if (entity != lastKnownEntity) { getClient().onLocalPlayerEntityChanged(entity, lastKnownEntity); this.lastKnownEntity = entity; } - + return entity; } - + public Selection getSelection() { return selection; } - + public void update(WorldRender world) { getSelection().update(world, getEntity()); } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java index 70951ee..cd4ba29 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/Selection.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.graphics.world; import glm.vec._2.Vec2; @@ -9,29 +27,29 @@ import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.entity.EntityData; public class Selection { - + private final Vec3i block = new Vec3i(); private BlockFace surface = null; private final Vec2 pointOnSurface = new Vec2(0.5f, 0.5f); private final Vec3 point = new Vec3(); - + private boolean exists = false; - + private BlockRay ray = new BlockRay(); - + public void update(WorldRender world, EntityData player) { Vec3 direction = new Vec3(); Vec3 start = new Vec3(); - + player.getLookingAtVector(direction); world.getEntityRenderable(player).getViewPoint(start); start.add(player.getPosition()); - + exists = false; - + for (ray.start(start, direction); ray.getDistance() < 6; ray.next()) { Vec3i blockInWorld = ray.current(); - + if (world.getData().getCollisionModelOfBlock(blockInWorld) != null) { exists = true; block.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); @@ -41,26 +59,26 @@ public class Selection { break; } } - + ray.end(); } - + public Vec3i getBlock() { return exists ? block : null; } - + public Vec3 getPoint() { return exists ? point : null; } - + public BlockFace getSurface() { return exists ? surface : null; } - + public Vec2 getPointOnSurface() { return exists ? pointOnSurface : null; } - + public boolean exists() { return exists; } diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java index d26b73b..de17238 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderHelper.java @@ -1,61 +1,63 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.world; - -import glm.mat._4.Mat4; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.common.util.StashingStack; - -public class WorldRenderHelper extends ShapeRenderHelper { - - private final StashingStack viewTransformStack = new StashingStack<>( - TRANSFORM_STACK_SIZE, Mat4::new - ); - - { - viewTransformStack.push().identity(); - } - - private final Mat4 finalTransform = new Mat4(); - - public Mat4 pushViewTransform() { - Mat4 previous = viewTransformStack.getHead(); - return viewTransformStack.push().set(previous); - } - - public void popViewTransform() { - viewTransformStack.removeHead(); - } - - public Mat4 getViewTransform() { - return viewTransformStack.getHead(); - } - - @Override - public Mat4 getFinalTransform() { - return finalTransform.set(getViewTransform()).mul(getTransform()); - } - - @Override - public void reset() { - super.reset(); - viewTransformStack.removeAll(); - viewTransformStack.push().identity(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.world; + +import glm.mat._4.Mat4; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.common.util.StashingStack; + +public class WorldRenderHelper extends ShapeRenderHelper { + + private final StashingStack viewTransformStack = new StashingStack<>( + TRANSFORM_STACK_SIZE, + Mat4::new + ); + + { + viewTransformStack.push().identity(); + } + + private final Mat4 finalTransform = new Mat4(); + + public Mat4 pushViewTransform() { + Mat4 previous = viewTransformStack.getHead(); + return viewTransformStack.push().set(previous); + } + + public void popViewTransform() { + viewTransformStack.removeHead(); + } + + public Mat4 getViewTransform() { + return viewTransformStack.getHead(); + } + + @Override + public Mat4 getFinalTransform() { + return finalTransform.set(getViewTransform()).mul(getTransform()); + } + + @Override + public void reset() { + super.reset(); + viewTransformStack.removeAll(); + viewTransformStack.push().identity(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java index 97a1094..5e55297 100644 --- a/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/world/WorldRenderProgram.java @@ -1,306 +1,324 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.graphics.world; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; - -import com.google.common.collect.ObjectArrays; - -import glm.vec._2.Vec2; -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; -import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; -import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; -import ru.windcorp.progressia.common.util.Vectors; - -public class WorldRenderProgram extends ShapeRenderProgram { - - private static WorldRenderProgram def = null; - - public static void init() { - def = new WorldRenderProgram( - new String[] {"WorldDefault.vertex.glsl"}, - new String[] {"WorldDefault.fragment.glsl"} - ); - } - - public static WorldRenderProgram getDefault() { - return def; - } - - private static final int DEFAULT_BYTES_PER_VERTEX = - 3 * Float.BYTES + // Position - 4 * Float.BYTES + // Color multiplier - 2 * Float.BYTES + // Texture coordinates - 3 * Float.BYTES; // Normals - - private static final String WORLD_VERTEX_SHADER_RESOURCE = - "World.vertex.glsl"; - private static final String WORLD_FRAGMENT_SHADER_RESOURCE = - "World.fragment.glsl"; - - private static final String - WORLD_TRANSFORM_UNIFORM_NAME = "worldTransform", - NORMALS_ATTRIBUTE_NAME = "inputNormals"; - - private final Uniform4Matrix worldTransformUniform; - private final AttributeVertexArray normalsAttribute; - - public WorldRenderProgram( - String[] vertexShaderResources, - String[] fragmentShaderResources - ) { - super( - attachVertexShader(vertexShaderResources), - attachFragmentShader(fragmentShaderResources) - ); - - this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME) - .as4Matrix(); - - this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME) - .asVertexArray(); - } - - private static String[] attachVertexShader(String[] others) { - return ObjectArrays.concat(WORLD_VERTEX_SHADER_RESOURCE, others); - } - - private static String[] attachFragmentShader(String[] others) { - return ObjectArrays.concat(WORLD_FRAGMENT_SHADER_RESOURCE, others); - } - - @Override - protected void configure(ShapeRenderHelper helper) { - super.configure(helper); - worldTransformUniform.set(helper.getTransform()); - } - - @Override - protected int bindVertices(VertexBufferObject vertices) { - int vertexStride = getBytesPerVertex(); - int offset = super.bindVertices(vertices); - - normalsAttribute.set( - 3, GL11.GL_FLOAT, false, vertexStride, vertices, - offset - ); - offset += 3 * Float.BYTES; - - return offset; - } - - @Override - protected void enableAttributes() { - super.enableAttributes(); - normalsAttribute.enable(); - } - - @Override - protected void disableAttributes() { - super.disableAttributes(); - normalsAttribute.disable(); - } - - @Override - public int getBytesPerVertex() { - return super.getBytesPerVertex() + - 3 * Float.BYTES; // Normals - } - - @Override - public void preprocess(Shape shape) { - super.preprocess(shape); - - for (Face face : shape.getFaces()) { - computeNormals(face); - } - } - - private void computeNormals(Face face) { - Vec3 a = Vectors.grab3(); - Vec3 b = Vectors.grab3(); - Vec3 c = Vectors.grab3(); - Vec3 normal = Vectors.grab3(); - - for (int i = 0; i < face.getIndexCount(); i += 3) { - int indexA = face.getIndex(i + 0); - int indexB = face.getIndex(i + 1); - int indexC = face.getIndex(i + 2); - - loadVertexPosition(face, indexA, a); - loadVertexPosition(face, indexB, b); - loadVertexPosition(face, indexC, c); - - computeOneNormal(a, b, c, normal); - - saveVertexNormal(face, indexA, normal); - saveVertexNormal(face, indexB, normal); - saveVertexNormal(face, indexC, normal); - } - - Vectors.release(a); - Vectors.release(b); - Vectors.release(c); - Vectors.release(normal); - } - - private void computeOneNormal( - Vec3 a, Vec3 b, Vec3 c, - Vec3 normal - ) { - b.sub(a); - c.sub(a); - b.cross(c, normal); - normal.normalize(); - } - - private void loadVertexPosition(Face face, int index, Vec3 result) { - ByteBuffer vertices = face.getVertices(); - int offset = vertices.position() + index * getBytesPerVertex(); - - result.set( - vertices.getFloat(offset + 0 * Float.BYTES), - vertices.getFloat(offset + 1 * Float.BYTES), - vertices.getFloat(offset + 2 * Float.BYTES) - ); - } - - private void saveVertexNormal(Face face, int index, Vec3 normal) { - ByteBuffer vertices = face.getVertices(); - int offset = vertices.position() + index * getBytesPerVertex() + ( - 3 * Float.BYTES + - 4 * Float.BYTES + - 2 * Float.BYTES - ); - - vertices.putFloat(offset + 0 * Float.BYTES, normal.x); - vertices.putFloat(offset + 1 * Float.BYTES, normal.y); - vertices.putFloat(offset + 2 * Float.BYTES, normal.z); - - face.markForVertexUpdate(); - } - - @Override - public VertexBuilder getVertexBuilder() { - return new WRPVertexBuilder(); - } - - private static class WRPVertexBuilder implements VertexBuilder { - // TODO Throw VertexBuilders out the window and rewrite completely. - // I want to _extend_ VBs, not re-implement them for children of SRP - - private static class Vertex { - final Vec3 position; - final Vec4 colorMultiplier; - final Vec2 textureCoords; - - Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { - this.position = position; - this.colorMultiplier = colorMultiplier; - this.textureCoords = textureCoords; - } - } - - private final List vertices = new ArrayList<>(); - - @Override - public VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, - float tx, float ty - ) { - vertices.add(new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, 1), - new Vec2(tx, ty) - )); - - return this; - } - - @Override - public VertexBuilder addVertex( - float x, float y, float z, - float r, float g, float b, float a, - float tx, float ty - ) { - vertices.add(new Vertex( - new Vec3(x, y, z), - new Vec4(r, g, b, a), - new Vec2(tx, ty) - )); - - return this; - } - - @Override - public VertexBuilder addVertex( - Vec3 position, - Vec4 colorMultiplier, - Vec2 textureCoords - ) { - vertices.add(new Vertex( - new Vec3(position), - new Vec4(colorMultiplier), - new Vec2(textureCoords) - )); - - return this; - } - - @Override - public ByteBuffer assemble() { - ByteBuffer result = BufferUtils.createByteBuffer( - DEFAULT_BYTES_PER_VERTEX * vertices.size() - ); - - for (Vertex v : vertices) { - result - .putFloat(v.position.x) - .putFloat(v.position.y) - .putFloat(v.position.z) - .putFloat(v.colorMultiplier.x) - .putFloat(v.colorMultiplier.y) - .putFloat(v.colorMultiplier.z) - .putFloat(v.colorMultiplier.w) - .putFloat(v.textureCoords.x) - .putFloat(v.textureCoords.y) - .putFloat(Float.NaN) - .putFloat(Float.NaN) - .putFloat(Float.NaN); - } - - result.flip(); - - return result; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.graphics.world; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; + +import com.google.common.collect.ObjectArrays; + +import glm.vec._2.Vec2; +import glm.vec._3.Vec3; +import glm.vec._4.Vec4; +import ru.windcorp.progressia.client.graphics.backend.VertexBufferObject; +import ru.windcorp.progressia.client.graphics.backend.shaders.attributes.*; +import ru.windcorp.progressia.client.graphics.backend.shaders.uniforms.*; +import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.common.util.Vectors; + +public class WorldRenderProgram extends ShapeRenderProgram { + + private static WorldRenderProgram def = null; + + public static void init() { + def = new WorldRenderProgram( + new String[] { "WorldDefault.vertex.glsl" }, + new String[] { "WorldDefault.fragment.glsl" } + ); + } + + public static WorldRenderProgram getDefault() { + return def; + } + + private static final int DEFAULT_BYTES_PER_VERTEX = 3 * Float.BYTES + // Position + 4 * Float.BYTES + // Color multiplier + 2 * Float.BYTES + // Texture coordinates + 3 * Float.BYTES; // Normals + + private static final String WORLD_VERTEX_SHADER_RESOURCE = "World.vertex.glsl"; + private static final String WORLD_FRAGMENT_SHADER_RESOURCE = "World.fragment.glsl"; + + private static final String WORLD_TRANSFORM_UNIFORM_NAME = "worldTransform", + NORMALS_ATTRIBUTE_NAME = "inputNormals"; + + private final Uniform4Matrix worldTransformUniform; + private final AttributeVertexArray normalsAttribute; + + public WorldRenderProgram( + String[] vertexShaderResources, + String[] fragmentShaderResources + ) { + super( + attachVertexShader(vertexShaderResources), + attachFragmentShader(fragmentShaderResources) + ); + + this.worldTransformUniform = getUniform(WORLD_TRANSFORM_UNIFORM_NAME) + .as4Matrix(); + + this.normalsAttribute = getAttribute(NORMALS_ATTRIBUTE_NAME) + .asVertexArray(); + } + + private static String[] attachVertexShader(String[] others) { + return ObjectArrays.concat(WORLD_VERTEX_SHADER_RESOURCE, others); + } + + private static String[] attachFragmentShader(String[] others) { + return ObjectArrays.concat(WORLD_FRAGMENT_SHADER_RESOURCE, others); + } + + @Override + protected void configure(ShapeRenderHelper helper) { + super.configure(helper); + worldTransformUniform.set(helper.getTransform()); + } + + @Override + protected int bindVertices(VertexBufferObject vertices) { + int vertexStride = getBytesPerVertex(); + int offset = super.bindVertices(vertices); + + normalsAttribute.set( + 3, + GL11.GL_FLOAT, + false, + vertexStride, + vertices, + offset + ); + offset += 3 * Float.BYTES; + + return offset; + } + + @Override + protected void enableAttributes() { + super.enableAttributes(); + normalsAttribute.enable(); + } + + @Override + protected void disableAttributes() { + super.disableAttributes(); + normalsAttribute.disable(); + } + + @Override + public int getBytesPerVertex() { + return super.getBytesPerVertex() + + 3 * Float.BYTES; // Normals + } + + @Override + public void preprocess(Shape shape) { + super.preprocess(shape); + + for (Face face : shape.getFaces()) { + computeNormals(face); + } + } + + private void computeNormals(Face face) { + Vec3 a = Vectors.grab3(); + Vec3 b = Vectors.grab3(); + Vec3 c = Vectors.grab3(); + Vec3 normal = Vectors.grab3(); + + for (int i = 0; i < face.getIndexCount(); i += 3) { + int indexA = face.getIndex(i + 0); + int indexB = face.getIndex(i + 1); + int indexC = face.getIndex(i + 2); + + loadVertexPosition(face, indexA, a); + loadVertexPosition(face, indexB, b); + loadVertexPosition(face, indexC, c); + + computeOneNormal(a, b, c, normal); + + saveVertexNormal(face, indexA, normal); + saveVertexNormal(face, indexB, normal); + saveVertexNormal(face, indexC, normal); + } + + Vectors.release(a); + Vectors.release(b); + Vectors.release(c); + Vectors.release(normal); + } + + private void computeOneNormal( + Vec3 a, + Vec3 b, + Vec3 c, + Vec3 normal + ) { + b.sub(a); + c.sub(a); + b.cross(c, normal); + normal.normalize(); + } + + private void loadVertexPosition(Face face, int index, Vec3 result) { + ByteBuffer vertices = face.getVertices(); + int offset = vertices.position() + index * getBytesPerVertex(); + + result.set( + vertices.getFloat(offset + 0 * Float.BYTES), + vertices.getFloat(offset + 1 * Float.BYTES), + vertices.getFloat(offset + 2 * Float.BYTES) + ); + } + + private void saveVertexNormal(Face face, int index, Vec3 normal) { + ByteBuffer vertices = face.getVertices(); + int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES + + 4 * Float.BYTES + + 2 * Float.BYTES); + + vertices.putFloat(offset + 0 * Float.BYTES, normal.x); + vertices.putFloat(offset + 1 * Float.BYTES, normal.y); + vertices.putFloat(offset + 2 * Float.BYTES, normal.z); + + face.markForVertexUpdate(); + } + + @Override + public VertexBuilder getVertexBuilder() { + return new WRPVertexBuilder(); + } + + private static class WRPVertexBuilder implements VertexBuilder { + // TODO Throw VertexBuilders out the window and rewrite completely. + // I want to _extend_ VBs, not re-implement them for children of SRP + + private static class Vertex { + final Vec3 position; + final Vec4 colorMultiplier; + final Vec2 textureCoords; + + Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { + this.position = position; + this.colorMultiplier = colorMultiplier; + this.textureCoords = textureCoords; + } + } + + private final List vertices = new ArrayList<>(); + + @Override + public VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float tx, + float ty + ) { + vertices.add( + new Vertex( + new Vec3(x, y, z), + new Vec4(r, g, b, 1), + new Vec2(tx, ty) + ) + ); + + return this; + } + + @Override + public VertexBuilder addVertex( + float x, + float y, + float z, + float r, + float g, + float b, + float a, + float tx, + float ty + ) { + vertices.add( + new Vertex( + new Vec3(x, y, z), + new Vec4(r, g, b, a), + new Vec2(tx, ty) + ) + ); + + return this; + } + + @Override + public VertexBuilder addVertex( + Vec3 position, + Vec4 colorMultiplier, + Vec2 textureCoords + ) { + vertices.add( + new Vertex( + new Vec3(position), + new Vec4(colorMultiplier), + new Vec2(textureCoords) + ) + ); + + return this; + } + + @Override + public ByteBuffer assemble() { + ByteBuffer result = BufferUtils.createByteBuffer( + DEFAULT_BYTES_PER_VERTEX * vertices.size() + ); + + for (Vertex v : vertices) { + result + .putFloat(v.position.x) + .putFloat(v.position.y) + .putFloat(v.position.z) + .putFloat(v.colorMultiplier.x) + .putFloat(v.colorMultiplier.y) + .putFloat(v.colorMultiplier.z) + .putFloat(v.colorMultiplier.w) + .putFloat(v.textureCoords.x) + .putFloat(v.textureCoords.y) + .putFloat(Float.NaN) + .putFloat(Float.NaN) + .putFloat(Float.NaN); + } + + result.flip(); + + return result; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java index 3e12801..b7c1f54 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java @@ -1,6 +1,24 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; @FunctionalInterface public interface LocaleListener { void onLocaleChanged(String newLanguage); -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java index cfed80a..b61d000 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; import java.lang.ref.WeakReference; @@ -16,8 +34,8 @@ public class Localizer { private Map fallBackData; private final Map langList; - private final Collection> listeners = - Collections.synchronizedCollection(new LinkedList<>()); + private final Collection> listeners = Collections + .synchronizedCollection(new LinkedList<>()); // lang list must be in the same folder as .lang files public Localizer(String langFolder) { @@ -59,7 +77,7 @@ public class Localizer { if (data == null) { throw new IllegalStateException("Localizer not yet initialized"); } - + if (data.containsKey(key)) { return data.get(key); } else if (fallBackData.containsKey(key)) { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java index 7ea617e..a96d804 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableString.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; import java.lang.ref.WeakReference; @@ -15,13 +33,13 @@ public abstract class MutableString { protected String data; - protected final Collection> listeners = - Collections.synchronizedCollection(new LinkedList<>()); - + protected final Collection> listeners = Collections + .synchronizedCollection(new LinkedList<>()); + private Collection myListeners = null; protected void pokeListeners() { - //TODO extract as weak bus listener class + // TODO extract as weak bus listener class synchronized (listeners) { Iterator> iterator = listeners.iterator(); while (iterator.hasNext()) { @@ -50,7 +68,7 @@ public abstract class MutableString { if (myListeners == null) { myListeners = new ArrayList<>(); } - + Listener listener = this::update; myListeners.add(listener); ((MutableString) obj).addListener(listener); @@ -77,6 +95,7 @@ public abstract class MutableString { data = compute(); pokeListeners(); } + protected abstract String compute(); public static MutableString formatted(Object format, Object... args) { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java index 3035f0d..f31fbca 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringConcat.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; public class MutableStringConcat extends MutableString { @@ -15,9 +33,9 @@ public class MutableStringConcat extends MutableString { } @Override - protected String compute() { + protected String compute() { StringBuilder sb = new StringBuilder(String.valueOf(part0)); - for (Object part : parts) { + for (Object part : parts) { sb.append(part); } return sb.toString(); diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java index 628bf06..fddba06 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFormatter.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; import java.util.IllegalFormatException; diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java index 971572d..d945618 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringFunc.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; import java.util.function.Function; diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java index 7ed8777..583d9e5 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringLocalized.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; public class MutableStringLocalized extends MutableString { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java index db9c499..d7b0fae 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/MutableStringParented.java @@ -1,6 +1,24 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; -public abstract class MutableStringParented extends MutableString { +public abstract class MutableStringParented extends MutableString { private final MutableString parent; public MutableStringParented(MutableString parent) { diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Parser.java b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java index 95fa83c..7d587dc 100644 --- a/src/main/java/ru/windcorp/progressia/client/localization/Parser.java +++ b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.localization; import ru.windcorp.jputil.chars.EscapeException; @@ -13,7 +31,7 @@ import java.util.Map; public class Parser { private String filePath; static private final Escaper ESCAPER = new Escaper.EscaperBuilder() - .withChars("n", "\n").build(); + .withChars("n", "\n").build(); public Parser(String filePath) { this.filePath = filePath; @@ -25,7 +43,8 @@ public class Parser { public Map parse() { Map parsedData = new HashMap<>(); - try (Reader rawData = ResourceManager + try ( + Reader rawData = ResourceManager .getResource(filePath) .getReader() ) { @@ -69,8 +88,10 @@ public class Parser { stringBuilder.append(c); } } - parsedData.put(ESCAPER.unescape(key), - ESCAPER.unescape(stringBuilder.toString())); + parsedData.put( + ESCAPER.unescape(key), + ESCAPER.unescape(stringBuilder.toString()) + ); stringBuilder.setLength(0); } } else if (c == '\n') { diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 5cf3555..a4c10c0 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -1,308 +1,311 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.WeakHashMap; -import java.util.stream.Collectors; - -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.client.graphics.model.Model; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.client.graphics.model.StaticModel; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.model.StaticModel.Builder; -import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.client.world.block.BlockRenderNone; -import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSupplier; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizers; -import ru.windcorp.progressia.client.world.tile.TileRender; -import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; -import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; - -public class ChunkRender -implements GenericChunk< - ChunkRender, - BlockRender, - TileRender, - TileRenderStack -> { - - private final WorldRender world; - private final ChunkData data; - - private Model model = null; - - private final Map tileRenderLists = - Collections.synchronizedMap(new WeakHashMap<>()); - - public ChunkRender(WorldRender world, ChunkData data) { - this.world = world; - this.data = data; - } - - @Override - public Vec3i getPosition() { - return getData().getPosition(); - } - - @Override - public BlockRender getBlock(Vec3i posInChunk) { - return BlockRenderRegistry.getInstance().get( - getData().getBlock(posInChunk).getId() - ); - } - - @Override - public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) { - return getTileStackWrapper(getData().getTiles(blockInChunk, face)); - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getData().hasTiles(blockInChunk, face); - } - - private TileRenderStack getTileStackWrapper(TileDataStack tileDataList) { - return tileRenderLists.computeIfAbsent( - tileDataList, - TileRenderStackImpl::new - ); - } - - public WorldRender getWorld() { - return world; - } - - public ChunkData getData() { - return data; - } - - public synchronized void markForUpdate() { - getWorld().markChunkForUpdate(getPosition()); - } - - public synchronized void render(ShapeRenderHelper renderer) { - if (model == null) { - return; - } - - renderer.pushTransform().translate( - data.getX() * ChunkData.BLOCKS_PER_CHUNK, - data.getY() * ChunkData.BLOCKS_PER_CHUNK, - data.getZ() * ChunkData.BLOCKS_PER_CHUNK - ); - - model.render(renderer); - - renderer.popTransform(); - } - - public synchronized void update() { - Collection optimizers = - ChunkRenderOptimizers.getAllSuppliers().stream() - .map(ChunkRenderOptimizerSupplier::createOptimizer) - .collect(Collectors.toList()); - - optimizers.forEach(bro -> bro.startRender(this)); - - StaticModel.Builder builder = StaticModel.builder(); - - Vec3i cursor = new Vec3i(); - for (int x = 0; x < ChunkData.BLOCKS_PER_CHUNK; ++x) { - for (int y = 0; y < ChunkData.BLOCKS_PER_CHUNK; ++y) { - for (int z = 0; z < ChunkData.BLOCKS_PER_CHUNK; ++z) { - cursor.set(x, y, z); - - buildBlock(cursor, optimizers, builder); - buildBlockTiles(cursor, optimizers, builder); - } - } - } - - optimizers.stream() - .map(ChunkRenderOptimizer::endRender) - .filter(Objects::nonNull) - .forEach(builder::addPart); - - model = new StaticModel(builder); - } - - private void buildBlock( - Vec3i cursor, - Collection optimizers, - Builder builder - ) { - BlockRender block = getBlock(cursor); - - if (block instanceof BlockRenderNone) { - return; - } - - forwardBlockToOptimizers(block, cursor, optimizers); - - if (!block.needsOwnRenderable()) { - return; - } - - addBlockRenderable(block, cursor, builder); - } - - private void forwardBlockToOptimizers( - BlockRender block, Vec3i cursor, - Collection optimizers - ) { - optimizers.forEach(cro -> cro.processBlock(block, cursor)); - } - - private void addBlockRenderable( - BlockRender block, - Vec3i cursor, - Builder builder - ) { - Renderable renderable = block.createRenderable(); - - if (renderable == null) { - renderable = block::render; - } - - builder.addPart( - renderable, - new Mat4().identity().translate(cursor.x, cursor.y, cursor.z) - ); - } - - private void buildBlockTiles( - Vec3i cursor, - Collection optimizers, - Builder builder - ) { - for (BlockFace face : BlockFace.getFaces()) { - buildFaceTiles(cursor, face, optimizers, builder); - } - } - - private void buildFaceTiles( - Vec3i cursor, BlockFace face, - Collection optimizers, - Builder builder - ) { - List tiles = getData().getTilesOrNull(cursor, face); - - if (tiles == null) { - return; - } - - for (int layer = 0; layer < tiles.size(); ++layer) { - - if (tiles.get(layer) == null) { - System.out.println(tiles.get(layer).getId()); - } - - buildTile( - cursor, face, - TileRenderRegistry.getInstance().get( - tiles.get(layer).getId() - ), - layer, - optimizers, builder - ); - } - } - - private void buildTile( - Vec3i cursor, BlockFace face, - TileRender tile, - int layer, - Collection optimizers, - Builder builder - ) { - // TODO implement - - Vec3 pos = new Vec3(cursor.x, cursor.y, cursor.z); - - optimizers.forEach(cro -> cro.processTile(tile, cursor, face)); - - if (!tile.needsOwnRenderable()) return; - - Vec3 offset = new Vec3( - face.getVector().x, face.getVector().y, face.getVector().z - ); - - pos.add(offset.mul(1f / 64)); - - builder.addPart( - tile.createRenderable(face), - new Mat4().identity().translate(pos) - ); - } - - private class TileRenderStackImpl extends TileRenderStack { - - private final TileDataStack parent; - - public TileRenderStackImpl(TileDataStack parent) { - this.parent = parent; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - return parent.getBlockInChunk(output); - } - - @Override - public ChunkRender getChunk() { - return ChunkRender.this; - } - - @Override - public BlockFace getFace() { - return parent.getFace(); - } - - @Override - public TileRender get(int index) { - return TileRenderRegistry.getInstance().get(parent.get(index).getId()); - } - - @Override - public int size() { - return parent.size(); - } - - @Override - public TileDataStack getData() { - return parent; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.WeakHashMap; +import java.util.stream.Collectors; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.graphics.model.Model; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.StaticModel; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.StaticModel.Builder; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.client.world.block.BlockRenderNone; +import ru.windcorp.progressia.client.world.block.BlockRenderRegistry; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerSupplier; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizers; +import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderRegistry; +import ru.windcorp.progressia.client.world.tile.TileRenderStack; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataStack; + +public class ChunkRender + implements GenericChunk { + + private final WorldRender world; + private final ChunkData data; + + private Model model = null; + + private final Map tileRenderLists = Collections + .synchronizedMap(new WeakHashMap<>()); + + public ChunkRender(WorldRender world, ChunkData data) { + this.world = world; + this.data = data; + } + + @Override + public Vec3i getPosition() { + return getData().getPosition(); + } + + @Override + public BlockRender getBlock(Vec3i posInChunk) { + return BlockRenderRegistry.getInstance().get( + getData().getBlock(posInChunk).getId() + ); + } + + @Override + public TileRenderStack getTiles(Vec3i blockInChunk, BlockFace face) { + return getTileStackWrapper(getData().getTiles(blockInChunk, face)); + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getData().hasTiles(blockInChunk, face); + } + + private TileRenderStack getTileStackWrapper(TileDataStack tileDataList) { + return tileRenderLists.computeIfAbsent( + tileDataList, + TileRenderStackImpl::new + ); + } + + public WorldRender getWorld() { + return world; + } + + public ChunkData getData() { + return data; + } + + public synchronized void markForUpdate() { + getWorld().markChunkForUpdate(getPosition()); + } + + public synchronized void render(ShapeRenderHelper renderer) { + if (model == null) { + return; + } + + renderer.pushTransform().translate( + data.getX() * ChunkData.BLOCKS_PER_CHUNK, + data.getY() * ChunkData.BLOCKS_PER_CHUNK, + data.getZ() * ChunkData.BLOCKS_PER_CHUNK + ); + + model.render(renderer); + + renderer.popTransform(); + } + + public synchronized void update() { + Collection optimizers = ChunkRenderOptimizers.getAllSuppliers().stream() + .map(ChunkRenderOptimizerSupplier::createOptimizer) + .collect(Collectors.toList()); + + optimizers.forEach(bro -> bro.startRender(this)); + + StaticModel.Builder builder = StaticModel.builder(); + + Vec3i cursor = new Vec3i(); + for (int x = 0; x < ChunkData.BLOCKS_PER_CHUNK; ++x) { + for (int y = 0; y < ChunkData.BLOCKS_PER_CHUNK; ++y) { + for (int z = 0; z < ChunkData.BLOCKS_PER_CHUNK; ++z) { + cursor.set(x, y, z); + + buildBlock(cursor, optimizers, builder); + buildBlockTiles(cursor, optimizers, builder); + } + } + } + + optimizers.stream() + .map(ChunkRenderOptimizer::endRender) + .filter(Objects::nonNull) + .forEach(builder::addPart); + + model = new StaticModel(builder); + } + + private void buildBlock( + Vec3i cursor, + Collection optimizers, + Builder builder + ) { + BlockRender block = getBlock(cursor); + + if (block instanceof BlockRenderNone) { + return; + } + + forwardBlockToOptimizers(block, cursor, optimizers); + + if (!block.needsOwnRenderable()) { + return; + } + + addBlockRenderable(block, cursor, builder); + } + + private void forwardBlockToOptimizers( + BlockRender block, + Vec3i cursor, + Collection optimizers + ) { + optimizers.forEach(cro -> cro.processBlock(block, cursor)); + } + + private void addBlockRenderable( + BlockRender block, + Vec3i cursor, + Builder builder + ) { + Renderable renderable = block.createRenderable(); + + if (renderable == null) { + renderable = block::render; + } + + builder.addPart( + renderable, + new Mat4().identity().translate(cursor.x, cursor.y, cursor.z) + ); + } + + private void buildBlockTiles( + Vec3i cursor, + Collection optimizers, + Builder builder + ) { + for (BlockFace face : BlockFace.getFaces()) { + buildFaceTiles(cursor, face, optimizers, builder); + } + } + + private void buildFaceTiles( + Vec3i cursor, + BlockFace face, + Collection optimizers, + Builder builder + ) { + List tiles = getData().getTilesOrNull(cursor, face); + + if (tiles == null) { + return; + } + + for (int layer = 0; layer < tiles.size(); ++layer) { + + if (tiles.get(layer) == null) { + System.out.println(tiles.get(layer).getId()); + } + + buildTile( + cursor, + face, + TileRenderRegistry.getInstance().get( + tiles.get(layer).getId() + ), + layer, + optimizers, + builder + ); + } + } + + private void buildTile( + Vec3i cursor, + BlockFace face, + TileRender tile, + int layer, + Collection optimizers, + Builder builder + ) { + // TODO implement + + Vec3 pos = new Vec3(cursor.x, cursor.y, cursor.z); + + optimizers.forEach(cro -> cro.processTile(tile, cursor, face)); + + if (!tile.needsOwnRenderable()) + return; + + Vec3 offset = new Vec3( + face.getVector().x, + face.getVector().y, + face.getVector().z + ); + + pos.add(offset.mul(1f / 64)); + + builder.addPart( + tile.createRenderable(face), + new Mat4().identity().translate(pos) + ); + } + + private class TileRenderStackImpl extends TileRenderStack { + + private final TileDataStack parent; + + public TileRenderStackImpl(TileDataStack parent) { + this.parent = parent; + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + return parent.getBlockInChunk(output); + } + + @Override + public ChunkRender getChunk() { + return ChunkRender.this; + } + + @Override + public BlockFace getFace() { + return parent.getFace(); + } + + @Override + public TileRender get(int index) { + return TileRenderRegistry.getInstance().get(parent.get(index).getId()); + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public TileDataStack getData() { + return parent; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java index d5fd908..d9e4ca1 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkUpdateListener.java @@ -1,12 +1,30 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.world; import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.ChunkDataListener; class ChunkUpdateListener implements ChunkDataListener { - + private final WorldRender world; - + public ChunkUpdateListener(WorldRender world) { this.world = world; } diff --git a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java index e80b798..8be08c2 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/WorldRender.java @@ -1,229 +1,227 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.WeakHashMap; - -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.client.Client; -import ru.windcorp.progressia.client.graphics.backend.FaceCulling; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; -import ru.windcorp.progressia.client.world.entity.EntityRenderable; -import ru.windcorp.progressia.client.world.tile.TileRender; -import ru.windcorp.progressia.client.world.tile.TileRenderStack; -import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.util.Vectors; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.ChunkSets; -import ru.windcorp.progressia.common.world.generic.GenericWorld; - -public class WorldRender -implements GenericWorld< - BlockRender, - TileRender, - TileRenderStack, - ChunkRender, - EntityRenderable -> { - - private final WorldData data; - private final Client client; - - private final Map chunks = - Collections.synchronizedMap(new HashMap<>()); - private final Map entityModels = - Collections.synchronizedMap(new WeakHashMap<>()); - - private final ChunkSet chunksToUpdate = ChunkSets.newSyncHashSet(); - - public WorldRender(WorldData data, Client client) { - this.data = data; - this.client = client; - - data.addListener(ChunkDataListeners.createAdder(new ChunkUpdateListener(this))); - data.addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { - addChunk(chunk); - } - - @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { - removeChunk(chunk); - } - }); - } - - protected void addChunk(ChunkData chunk) { - chunks.put(chunk, new ChunkRender(WorldRender.this, chunk)); - markChunkForUpdate(chunk.getPosition()); - } - - protected void removeChunk(ChunkData chunk) { - chunks.remove(chunk); - } - - public WorldData getData() { - return data; - } - - public Client getClient() { - return client; - } - - public ChunkRender getChunk(ChunkData chunkData) { - return chunks.get(chunkData); - } - - @Override - public ChunkRender getChunk(Vec3i pos) { - return chunks.get(getData().getChunk(pos)); - } - - @Override - public Collection getChunks() { - return chunks.values(); - } - - @Override - public Collection getEntities() { - return entityModels.values(); - } - - public void render(ShapeRenderHelper renderer) { - updateChunks(); - - getChunks().forEach(chunk -> chunk.render(renderer)); - renderEntities(renderer); - } - - private void updateChunks() { - synchronized (chunksToUpdate) { - if (chunksToUpdate.isEmpty()) return; - - int updates = updateChunksNearLocalPlayer(); - if (updates > 0 || chunksToUpdate.isEmpty()) return; - - updateRandomChunk(); - } - } - - private int updateChunksNearLocalPlayer() { - EntityData entity = getClient().getLocalPlayer().getEntity(); - if (entity == null) return 0; - - int[] updates = new int[] { 0 }; - - VectorUtil.iterateCuboidAround(entity.getChunkCoords(null), 3, chunkPos -> { - if (!chunksToUpdate.contains(chunkPos)) return; - - ChunkRender chunk = getChunk(chunkPos); - if (chunk == null) return; - - chunk.update(); - chunksToUpdate.remove(chunkPos); - updates[0]++; - }); - - return updates[0]; - } - - private void updateRandomChunk() { - EntityData entity = getClient().getLocalPlayer().getEntity(); - - Vec3 playerPos = entity == null ? Vectors.ZERO_3 : entity.getPosition(); - - ChunkRender nearest = null; - float nearestDistSq = Float.POSITIVE_INFINITY; - - Vec3 v = Vectors.grab3(); - - for (Iterator it = chunksToUpdate.iterator(); it.hasNext();) { - Vec3i chunkPos = it.next(); - ChunkRender chunk = getChunk(chunkPos); - - if (chunk == null) { - it.remove(); - continue; - } - - v.set(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()).sub(playerPos); - float distSq = v.x * v.x + v.y * v.y + v.z * v.z; - - if (nearest == null || distSq < nearestDistSq) { - nearest = chunk; - nearestDistSq = distSq; - } - } - - if (nearest != null) { - nearest.update(); - chunksToUpdate.remove(nearest.getPosition()); - } - - Vectors.release(v); - } - - public int getPendingChunkUpdates() { - return chunksToUpdate.size(); - } - - private void renderEntities(ShapeRenderHelper renderer) { - FaceCulling.push(false); - - getData().forEachEntity(entity -> { - renderer.pushTransform().translate(entity.getPosition()); - getEntityRenderable(entity).render(renderer); - renderer.popTransform(); - }); - - FaceCulling.pop(); - } - - public EntityRenderable getEntityRenderable(EntityData entity) { - return entityModels.computeIfAbsent( - entity, - WorldRender::createEntityRenderable - ); - } - - private static EntityRenderable createEntityRenderable(EntityData entity) { - return EntityRenderRegistry.getInstance().get(entity.getId()) - .createRenderable(entity); - } - - public void markChunkForUpdate(Vec3i chunkPos) { - if (getData().getChunk(chunkPos) != null) { - chunksToUpdate.add(chunkPos); - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.Client; +import ru.windcorp.progressia.client.graphics.backend.FaceCulling; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry; +import ru.windcorp.progressia.client.world.entity.EntityRenderable; +import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.client.world.tile.TileRenderStack; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.util.Vectors; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.ChunkDataListeners; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.WorldDataListener; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.ChunkSets; +import ru.windcorp.progressia.common.world.generic.GenericWorld; + +public class WorldRender + implements GenericWorld { + + private final WorldData data; + private final Client client; + + private final Map chunks = Collections.synchronizedMap(new HashMap<>()); + private final Map entityModels = Collections.synchronizedMap(new WeakHashMap<>()); + + private final ChunkSet chunksToUpdate = ChunkSets.newSyncHashSet(); + + public WorldRender(WorldData data, Client client) { + this.data = data; + this.client = client; + + data.addListener(ChunkDataListeners.createAdder(new ChunkUpdateListener(this))); + data.addListener(new WorldDataListener() { + @Override + public void onChunkLoaded(WorldData world, ChunkData chunk) { + addChunk(chunk); + } + + @Override + public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + removeChunk(chunk); + } + }); + } + + protected void addChunk(ChunkData chunk) { + chunks.put(chunk, new ChunkRender(WorldRender.this, chunk)); + markChunkForUpdate(chunk.getPosition()); + } + + protected void removeChunk(ChunkData chunk) { + chunks.remove(chunk); + } + + public WorldData getData() { + return data; + } + + public Client getClient() { + return client; + } + + public ChunkRender getChunk(ChunkData chunkData) { + return chunks.get(chunkData); + } + + @Override + public ChunkRender getChunk(Vec3i pos) { + return chunks.get(getData().getChunk(pos)); + } + + @Override + public Collection getChunks() { + return chunks.values(); + } + + @Override + public Collection getEntities() { + return entityModels.values(); + } + + public void render(ShapeRenderHelper renderer) { + updateChunks(); + + getChunks().forEach(chunk -> chunk.render(renderer)); + renderEntities(renderer); + } + + private void updateChunks() { + synchronized (chunksToUpdate) { + if (chunksToUpdate.isEmpty()) + return; + + int updates = updateChunksNearLocalPlayer(); + if (updates > 0 || chunksToUpdate.isEmpty()) + return; + + updateRandomChunk(); + } + } + + private int updateChunksNearLocalPlayer() { + EntityData entity = getClient().getLocalPlayer().getEntity(); + if (entity == null) + return 0; + + int[] updates = new int[] { 0 }; + + VectorUtil.iterateCuboidAround(entity.getChunkCoords(null), 3, chunkPos -> { + if (!chunksToUpdate.contains(chunkPos)) + return; + + ChunkRender chunk = getChunk(chunkPos); + if (chunk == null) + return; + + chunk.update(); + chunksToUpdate.remove(chunkPos); + updates[0]++; + }); + + return updates[0]; + } + + private void updateRandomChunk() { + EntityData entity = getClient().getLocalPlayer().getEntity(); + + Vec3 playerPos = entity == null ? Vectors.ZERO_3 : entity.getPosition(); + + ChunkRender nearest = null; + float nearestDistSq = Float.POSITIVE_INFINITY; + + Vec3 v = Vectors.grab3(); + + for (Iterator it = chunksToUpdate.iterator(); it.hasNext();) { + Vec3i chunkPos = it.next(); + ChunkRender chunk = getChunk(chunkPos); + + if (chunk == null) { + it.remove(); + continue; + } + + v.set(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ()).sub(playerPos); + float distSq = v.x * v.x + v.y * v.y + v.z * v.z; + + if (nearest == null || distSq < nearestDistSq) { + nearest = chunk; + nearestDistSq = distSq; + } + } + + if (nearest != null) { + nearest.update(); + chunksToUpdate.remove(nearest.getPosition()); + } + + Vectors.release(v); + } + + public int getPendingChunkUpdates() { + return chunksToUpdate.size(); + } + + private void renderEntities(ShapeRenderHelper renderer) { + FaceCulling.push(false); + + getData().forEachEntity(entity -> { + renderer.pushTransform().translate(entity.getPosition()); + getEntityRenderable(entity).render(renderer); + renderer.popTransform(); + }); + + FaceCulling.pop(); + } + + public EntityRenderable getEntityRenderable(EntityData entity) { + return entityModels.computeIfAbsent( + entity, + WorldRender::createEntityRenderable + ); + } + + private static EntityRenderable createEntityRenderable(EntityData entity) { + return EntityRenderRegistry.getInstance().get(entity.getId()) + .createRenderable(entity); + } + + public void markChunkForUpdate(Vec3i chunkPos) { + if (getData().getChunk(chunkPos) != null) { + chunksToUpdate.add(chunkPos); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java index 66dd99b..089da53 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRender.java @@ -1,45 +1,46 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericBlock; -import ru.windcorp.progressia.client.graphics.model.Renderable; - -public abstract class BlockRender extends Namespaced implements GenericBlock { - - public BlockRender(String id) { - super(id); - } - - public void render(ShapeRenderHelper renderer) { - throw new UnsupportedOperationException( - "BlockRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable() { - return null; - } - - public boolean needsOwnRenderable() { - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.generic.GenericBlock; +import ru.windcorp.progressia.client.graphics.model.Renderable; + +public abstract class BlockRender extends Namespaced implements GenericBlock { + + public BlockRender(String id) { + super(id); + } + + public void render(ShapeRenderHelper renderer) { + throw new UnsupportedOperationException( + "BlockRender.render() not implemented in " + this + ); + } + + public Renderable createRenderable() { + return null; + } + + public boolean needsOwnRenderable() { + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java index 24db070..e40b13b 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderNone.java @@ -1,39 +1,40 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import ru.windcorp.progressia.client.graphics.model.EmptyModel; -import ru.windcorp.progressia.client.graphics.model.Renderable; - -public class BlockRenderNone extends BlockRender { - - public BlockRenderNone(String id) { - super(id); - } - - @Override - public Renderable createRenderable() { - return EmptyModel.getInstance(); - } - - @Override - public boolean needsOwnRenderable() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import ru.windcorp.progressia.client.graphics.model.EmptyModel; +import ru.windcorp.progressia.client.graphics.model.Renderable; + +public class BlockRenderNone extends BlockRender { + + public BlockRenderNone(String id) { + super(id); + } + + @Override + public Renderable createRenderable() { + return EmptyModel.getInstance(); + } + + @Override + public boolean needsOwnRenderable() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java index 4f31089..06f2963 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderOpaqueCube.java @@ -1,63 +1,73 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { - - public BlockRenderOpaqueCube( - String id, - Texture topTexture, Texture bottomTexture, - Texture northTexture, Texture southTexture, - Texture eastTexture, Texture westTexture - ) { - super( - id, - topTexture, bottomTexture, - northTexture, southTexture, - eastTexture, westTexture - ); - } - - public BlockRenderOpaqueCube(String id, Texture texture) { - this( - id, - texture, texture, - texture, texture, - texture, texture - ); - } - - @Override - public boolean isOpaque(BlockFace face) { - return true; - } - - @Override - public boolean isBlockOpaque() { - return true; - } - - @Override - public boolean needsOwnRenderable() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class BlockRenderOpaqueCube extends BlockRenderTexturedCube { + + public BlockRenderOpaqueCube( + String id, + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture eastTexture, + Texture westTexture + ) { + super( + id, + topTexture, + bottomTexture, + northTexture, + southTexture, + eastTexture, + westTexture + ); + } + + public BlockRenderOpaqueCube(String id, Texture texture) { + this( + id, + texture, + texture, + texture, + texture, + texture, + texture + ); + } + + @Override + public boolean isOpaque(BlockFace face) { + return true; + } + + @Override + public boolean isBlockOpaque() { + return true; + } + + @Override + public boolean needsOwnRenderable() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java index 7392986..29bac40 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderRegistry.java @@ -1,52 +1,51 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import ru.windcorp.progressia.client.graphics.texture.Atlases; -import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup; -import ru.windcorp.progressia.client.graphics.texture.SimpleTexture; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.resource.ResourceManager; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class BlockRenderRegistry extends NamespacedInstanceRegistry { - - private static final BlockRenderRegistry INSTANCE = - new BlockRenderRegistry(); - - private static final AtlasGroup BLOCKS_ATLAS_GROUP = - new AtlasGroup("Blocks", 1 << 12); - - public static BlockRenderRegistry getInstance() { - return INSTANCE; - } - - public static Texture getBlockTexture(String name) { - return new SimpleTexture( - Atlases.getSprite( - ResourceManager.getTextureResource("blocks/" + name), - BLOCKS_ATLAS_GROUP - ) - ); - } - - public static AtlasGroup getBlocksAtlasGroup() { - return BLOCKS_ATLAS_GROUP; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import ru.windcorp.progressia.client.graphics.texture.Atlases; +import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup; +import ru.windcorp.progressia.client.graphics.texture.SimpleTexture; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class BlockRenderRegistry extends NamespacedInstanceRegistry { + + private static final BlockRenderRegistry INSTANCE = new BlockRenderRegistry(); + + private static final AtlasGroup BLOCKS_ATLAS_GROUP = new AtlasGroup("Blocks", 1 << 12); + + public static BlockRenderRegistry getInstance() { + return INSTANCE; + } + + public static Texture getBlockTexture(String name) { + return new SimpleTexture( + Atlases.getSprite( + ResourceManager.getTextureResource("blocks/" + name), + BLOCKS_ATLAS_GROUP + ) + ); + } + + public static AtlasGroup getBlocksAtlasGroup() { + return BLOCKS_ATLAS_GROUP; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java index 649ad2f..fd0c9d9 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTexturedCube.java @@ -1,69 +1,76 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import static ru.windcorp.progressia.common.world.block.BlockFace.*; - -import java.util.HashMap; -import java.util.Map; - -import ru.windcorp.progressia.client.graphics.model.Shapes; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueCube; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public abstract class BlockRenderTexturedCube -extends BlockRender -implements OpaqueCube { - - private final Map textures = new HashMap<>(); - - public BlockRenderTexturedCube( - String id, - Texture topTexture, Texture bottomTexture, - Texture northTexture, Texture southTexture, - Texture eastTexture, Texture westTexture - ) { - super(id); - - textures.put(TOP, topTexture); - textures.put(BOTTOM, bottomTexture); - textures.put(NORTH, northTexture); - textures.put(SOUTH, southTexture); - textures.put(EAST, eastTexture); - textures.put(WEST, westTexture); - } - - @Override - public Texture getTexture(BlockFace face) { - return textures.get(face); - } - - @Override - public Renderable createRenderable() { - return new Shapes.PppBuilder( - WorldRenderProgram.getDefault(), - getTexture(TOP), getTexture(BOTTOM), - getTexture(NORTH), getTexture(SOUTH), - getTexture(EAST), getTexture(WEST) - ).create(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import static ru.windcorp.progressia.common.world.block.BlockFace.*; + +import java.util.HashMap; +import java.util.Map; + +import ru.windcorp.progressia.client.graphics.model.Shapes; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueCube; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public abstract class BlockRenderTexturedCube + extends BlockRender + implements OpaqueCube { + + private final Map textures = new HashMap<>(); + + public BlockRenderTexturedCube( + String id, + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture eastTexture, + Texture westTexture + ) { + super(id); + + textures.put(TOP, topTexture); + textures.put(BOTTOM, bottomTexture); + textures.put(NORTH, northTexture); + textures.put(SOUTH, southTexture); + textures.put(EAST, eastTexture); + textures.put(WEST, westTexture); + } + + @Override + public Texture getTexture(BlockFace face) { + return textures.get(face); + } + + @Override + public Renderable createRenderable() { + return new Shapes.PppBuilder( + WorldRenderProgram.getDefault(), + getTexture(TOP), + getTexture(BOTTOM), + getTexture(NORTH), + getTexture(SOUTH), + getTexture(EAST), + getTexture(WEST) + ).create(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java index a478d2c..54a94e4 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/block/BlockRenderTransparentCube.java @@ -1,63 +1,73 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.block; - -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class BlockRenderTransparentCube extends BlockRenderTexturedCube { - - public BlockRenderTransparentCube( - String id, - Texture topTexture, Texture bottomTexture, - Texture northTexture, Texture southTexture, - Texture eastTexture, Texture westTexture - ) { - super( - id, - topTexture, bottomTexture, - northTexture, southTexture, - eastTexture, westTexture - ); - } - - public BlockRenderTransparentCube(String id, Texture texture) { - this( - id, - texture, texture, - texture, texture, - texture, texture - ); - } - - @Override - public boolean isOpaque(BlockFace face) { - return false; - } - - @Override - public boolean isBlockOpaque() { - return false; - } - - @Override - public boolean needsOwnRenderable() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.block; + +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class BlockRenderTransparentCube extends BlockRenderTexturedCube { + + public BlockRenderTransparentCube( + String id, + Texture topTexture, + Texture bottomTexture, + Texture northTexture, + Texture southTexture, + Texture eastTexture, + Texture westTexture + ) { + super( + id, + topTexture, + bottomTexture, + northTexture, + southTexture, + eastTexture, + westTexture + ); + } + + public BlockRenderTransparentCube(String id, Texture texture) { + this( + id, + texture, + texture, + texture, + texture, + texture, + texture + ); + } + + @Override + public boolean isOpaque(BlockFace face) { + return false; + } + + @Override + public boolean isBlockOpaque() { + return false; + } + + @Override + public boolean needsOwnRenderable() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java index 50a25ec..9117111 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizer.java @@ -1,43 +1,45 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.cro; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.world.ChunkRender; -import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.client.world.tile.TileRender; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public abstract class ChunkRenderOptimizer { - - public abstract void startRender(ChunkRender chunk); - - public abstract void processBlock( - BlockRender block, - Vec3i posInChunk - ); - - public abstract void processTile( - TileRender tile, - Vec3i posInChunk, BlockFace face - ); - - public abstract Shape endRender(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.cro; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public abstract class ChunkRenderOptimizer { + + public abstract void startRender(ChunkRender chunk); + + public abstract void processBlock( + BlockRender block, + Vec3i posInChunk + ); + + public abstract void processTile( + TileRender tile, + Vec3i posInChunk, + BlockFace face + ); + + public abstract Shape endRender(); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerCube.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerCube.java index 4012087..723549a 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerCube.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerCube.java @@ -1,271 +1,283 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.cro; - -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; -import static ru.windcorp.progressia.common.world.block.BlockFace.BLOCK_FACE_COUNT; -import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Consumer; - -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Face; -import ru.windcorp.progressia.client.graphics.model.Faces; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; -import ru.windcorp.progressia.client.world.ChunkRender; -import ru.windcorp.progressia.client.world.block.BlockRender; -import ru.windcorp.progressia.client.world.tile.TileRender; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer { - - public static interface OpaqueCube { - public Texture getTexture(BlockFace face); - public boolean isOpaque(BlockFace face); - public boolean isBlockOpaque(); - } - - public static interface OpaqueSurface { - public Texture getTexture(BlockFace face); - public boolean isOpaque(BlockFace face); - } - - private static class BlockInfo { - OpaqueCube block; - final FaceInfo[] faces = new FaceInfo[BLOCK_FACE_COUNT]; - - { - for (int i = 0; i < faces.length; ++i) { - faces[i] = new FaceInfo(); - } - } - } - - private static class FaceInfo { - static final int NO_OPAQUE_TILES = -1; - - int topOpaqueTile = NO_OPAQUE_TILES; - final OpaqueSurface[] tiles = new OpaqueSurface[TILES_PER_FACE]; - int tileCount = 0; - } - - private final BlockInfo[][][] data = - new BlockInfo[BLOCKS_PER_CHUNK] - [BLOCKS_PER_CHUNK] - [BLOCKS_PER_CHUNK]; - - { - for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) { - for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) { - for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) { - data[x][y][z] = new BlockInfo(); - } - } - } - } - - @Override - public void startRender(ChunkRender chunk) { - // Do nothing - } - - @Override - public void processBlock(BlockRender block, Vec3i pos) { - if (!(block instanceof OpaqueCube)) return; - OpaqueCube opaqueCube = (OpaqueCube) block; - addBlock(pos, opaqueCube); - } - - @Override - public void processTile(TileRender tile, Vec3i pos, BlockFace face) { - if (!(tile instanceof OpaqueSurface)) return; - OpaqueSurface opaqueTile = (OpaqueSurface) tile; - addTile(pos, face, opaqueTile); - } - - protected void addBlock(Vec3i pos, OpaqueCube cube) { - getBlock(pos).block = cube; - } - - private void addTile(Vec3i pos, BlockFace face, OpaqueSurface opaqueTile) { - FaceInfo faceInfo = getFace(pos, face); - - int index = faceInfo.tileCount; - faceInfo.tileCount++; - - faceInfo.tiles[index] = opaqueTile; - - if (opaqueTile.isOpaque(face)) { - faceInfo.topOpaqueTile = index; - } - } - - protected BlockInfo getBlock(Vec3i cursor) { - return data[cursor.x][cursor.y][cursor.z]; - } - - protected FaceInfo getFace(Vec3i cursor, BlockFace face) { - return getBlock(cursor).faces[face.getId()]; - } - - @Override - public Shape endRender() { - - Collection shapeFaces = new ArrayList<>( - BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 - ); - - Vec3i cursor = new Vec3i(); - - for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { - for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { - for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) { - processInnerFaces(cursor, shapeFaces::add); - processOuterFaces(cursor, shapeFaces::add); - } - } - } - - return new Shape( - Usage.STATIC, - WorldRenderProgram.getDefault(), - shapeFaces.toArray(new Face[shapeFaces.size()]) - ); - } - - private void processOuterFaces( - Vec3i cursor, - Consumer output - ) { - for (BlockFace face : BlockFace.getFaces()) { - if (!shouldRenderOuterFace(cursor, face)) continue; - - Vec3 faceOrigin = new Vec3(cursor.x, cursor.y, cursor.z); - Vec3 offset = new Vec3(face.getVector().x, face.getVector().y, face.getVector().z).mul(1f / 128); - - FaceInfo info = getFace(cursor, face); - - if (info.topOpaqueTile == FaceInfo.NO_OPAQUE_TILES) { - OpaqueCube block = getBlock(cursor).block; - - if (block != null) { - addFace( - faceOrigin, face, - getBlock(cursor).block.getTexture(face), - output - ); - - faceOrigin.add(offset); - } - } - - int startLayer = info.topOpaqueTile; - if (startLayer == FaceInfo.NO_OPAQUE_TILES) { - startLayer = 0; - } - - for (int layer = startLayer; layer < info.tileCount; ++layer) { - addFace( - faceOrigin, face, - info.tiles[layer].getTexture(face), - output - ); - - faceOrigin.add(offset); - } - } - } - - private void addFace( - Vec3 cursor, BlockFace face, - Texture texture, - Consumer output - ) { - if (texture == null) return; - - output.accept(Faces.createBlockFace( - WorldRenderProgram.getDefault(), - texture, - Colors.WHITE, - new Vec3(cursor), - face, - false - )); - } - - private boolean shouldRenderOuterFace(Vec3i cursor, BlockFace face) { - cursor.add(face.getVector()); - try { - - // TODO handle neighboring chunks properly - if (!isInBounds(cursor)) return true; - - OpaqueCube adjacent = getBlock(cursor).block; - - if (adjacent == null) return true; - if (adjacent.isOpaque(face)) return false; - - return true; - - } finally { - cursor.sub(face.getVector()); - } - } - - private void processInnerFaces( - Vec3i cursor, - Consumer output - ) { -// if (block.isBlockOpaque()) return; -// -// for (BlockFace face : BlockFace.getFaces()) { -// -// Texture texture = block.getTexture(face); -// if (texture == null) continue; -// -// output.accept(Faces.createBlockFace( -// WorldRenderProgram.getDefault(), -// texture, -// COLOR_MULTIPLIER, -// new Vec3(cursor.x, cursor.y, cursor.z), -// face, -// true -// )); -// -// } - } - - private boolean isInBounds(Vec3i cursor) { - return - isInBounds(cursor.x) && - isInBounds(cursor.y) && - isInBounds(cursor.z); - } - - private boolean isInBounds(int c) { - return c >= 0 && c < BLOCKS_PER_CHUNK; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.cro; + +import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; +import static ru.windcorp.progressia.common.world.block.BlockFace.BLOCK_FACE_COUNT; +import static ru.windcorp.progressia.common.world.generic.GenericTileStack.TILES_PER_FACE; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Consumer; + +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.model.Face; +import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.world.ChunkRender; +import ru.windcorp.progressia.client.world.block.BlockRender; +import ru.windcorp.progressia.client.world.tile.TileRender; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class ChunkRenderOptimizerCube extends ChunkRenderOptimizer { + + public static interface OpaqueCube { + public Texture getTexture(BlockFace face); + + public boolean isOpaque(BlockFace face); + + public boolean isBlockOpaque(); + } + + public static interface OpaqueSurface { + public Texture getTexture(BlockFace face); + + public boolean isOpaque(BlockFace face); + } + + private static class BlockInfo { + OpaqueCube block; + final FaceInfo[] faces = new FaceInfo[BLOCK_FACE_COUNT]; + + { + for (int i = 0; i < faces.length; ++i) { + faces[i] = new FaceInfo(); + } + } + } + + private static class FaceInfo { + static final int NO_OPAQUE_TILES = -1; + + int topOpaqueTile = NO_OPAQUE_TILES; + final OpaqueSurface[] tiles = new OpaqueSurface[TILES_PER_FACE]; + int tileCount = 0; + } + + private final BlockInfo[][][] data = new BlockInfo[BLOCKS_PER_CHUNK][BLOCKS_PER_CHUNK][BLOCKS_PER_CHUNK]; + + { + for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) { + for (int y = 0; y < BLOCKS_PER_CHUNK; ++y) { + for (int z = 0; z < BLOCKS_PER_CHUNK; ++z) { + data[x][y][z] = new BlockInfo(); + } + } + } + } + + @Override + public void startRender(ChunkRender chunk) { + // Do nothing + } + + @Override + public void processBlock(BlockRender block, Vec3i pos) { + if (!(block instanceof OpaqueCube)) + return; + OpaqueCube opaqueCube = (OpaqueCube) block; + addBlock(pos, opaqueCube); + } + + @Override + public void processTile(TileRender tile, Vec3i pos, BlockFace face) { + if (!(tile instanceof OpaqueSurface)) + return; + OpaqueSurface opaqueTile = (OpaqueSurface) tile; + addTile(pos, face, opaqueTile); + } + + protected void addBlock(Vec3i pos, OpaqueCube cube) { + getBlock(pos).block = cube; + } + + private void addTile(Vec3i pos, BlockFace face, OpaqueSurface opaqueTile) { + FaceInfo faceInfo = getFace(pos, face); + + int index = faceInfo.tileCount; + faceInfo.tileCount++; + + faceInfo.tiles[index] = opaqueTile; + + if (opaqueTile.isOpaque(face)) { + faceInfo.topOpaqueTile = index; + } + } + + protected BlockInfo getBlock(Vec3i cursor) { + return data[cursor.x][cursor.y][cursor.z]; + } + + protected FaceInfo getFace(Vec3i cursor, BlockFace face) { + return getBlock(cursor).faces[face.getId()]; + } + + @Override + public Shape endRender() { + + Collection shapeFaces = new ArrayList<>( + BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * 3 + ); + + Vec3i cursor = new Vec3i(); + + for (cursor.x = 0; cursor.x < BLOCKS_PER_CHUNK; ++cursor.x) { + for (cursor.y = 0; cursor.y < BLOCKS_PER_CHUNK; ++cursor.y) { + for (cursor.z = 0; cursor.z < BLOCKS_PER_CHUNK; ++cursor.z) { + processInnerFaces(cursor, shapeFaces::add); + processOuterFaces(cursor, shapeFaces::add); + } + } + } + + return new Shape( + Usage.STATIC, + WorldRenderProgram.getDefault(), + shapeFaces.toArray(new Face[shapeFaces.size()]) + ); + } + + private void processOuterFaces( + Vec3i cursor, + Consumer output + ) { + for (BlockFace face : BlockFace.getFaces()) { + if (!shouldRenderOuterFace(cursor, face)) + continue; + + Vec3 faceOrigin = new Vec3(cursor.x, cursor.y, cursor.z); + Vec3 offset = new Vec3(face.getVector().x, face.getVector().y, face.getVector().z).mul(1f / 128); + + FaceInfo info = getFace(cursor, face); + + if (info.topOpaqueTile == FaceInfo.NO_OPAQUE_TILES) { + OpaqueCube block = getBlock(cursor).block; + + if (block != null) { + addFace( + faceOrigin, + face, + getBlock(cursor).block.getTexture(face), + output + ); + + faceOrigin.add(offset); + } + } + + int startLayer = info.topOpaqueTile; + if (startLayer == FaceInfo.NO_OPAQUE_TILES) { + startLayer = 0; + } + + for (int layer = startLayer; layer < info.tileCount; ++layer) { + addFace( + faceOrigin, + face, + info.tiles[layer].getTexture(face), + output + ); + + faceOrigin.add(offset); + } + } + } + + private void addFace( + Vec3 cursor, + BlockFace face, + Texture texture, + Consumer output + ) { + if (texture == null) + return; + + output.accept( + Faces.createBlockFace( + WorldRenderProgram.getDefault(), + texture, + Colors.WHITE, + new Vec3(cursor), + face, + false + ) + ); + } + + private boolean shouldRenderOuterFace(Vec3i cursor, BlockFace face) { + cursor.add(face.getVector()); + try { + + // TODO handle neighboring chunks properly + if (!isInBounds(cursor)) + return true; + + OpaqueCube adjacent = getBlock(cursor).block; + + if (adjacent == null) + return true; + if (adjacent.isOpaque(face)) + return false; + + return true; + + } finally { + cursor.sub(face.getVector()); + } + } + + private void processInnerFaces( + Vec3i cursor, + Consumer output + ) { +// if (block.isBlockOpaque()) return; +// +// for (BlockFace face : BlockFace.getFaces()) { +// +// Texture texture = block.getTexture(face); +// if (texture == null) continue; +// +// output.accept(Faces.createBlockFace( +// WorldRenderProgram.getDefault(), +// texture, +// COLOR_MULTIPLIER, +// new Vec3(cursor.x, cursor.y, cursor.z), +// face, +// true +// )); +// +// } + } + + private boolean isInBounds(Vec3i cursor) { + return isInBounds(cursor.x) && + isInBounds(cursor.y) && + isInBounds(cursor.z); + } + + private boolean isInBounds(int c) { + return c >= 0 && c < BLOCKS_PER_CHUNK; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSupplier.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSupplier.java index 702282c..340ea6d 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSupplier.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizerSupplier.java @@ -1,44 +1,45 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.cro; - -import com.google.common.base.Supplier; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; - -public abstract class ChunkRenderOptimizerSupplier extends Namespaced { - - public ChunkRenderOptimizerSupplier(String id) { - super(id); - } - - public abstract ChunkRenderOptimizer createOptimizer(); - - public static ChunkRenderOptimizerSupplier of( - String id, - Supplier supplier - ) { - return new ChunkRenderOptimizerSupplier(id) { - @Override - public ChunkRenderOptimizer createOptimizer() { - return supplier.get(); - } - }; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.cro; + +import com.google.common.base.Supplier; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +public abstract class ChunkRenderOptimizerSupplier extends Namespaced { + + public ChunkRenderOptimizerSupplier(String id) { + super(id); + } + + public abstract ChunkRenderOptimizer createOptimizer(); + + public static ChunkRenderOptimizerSupplier of( + String id, + Supplier supplier + ) { + return new ChunkRenderOptimizerSupplier(id) { + @Override + public ChunkRenderOptimizer createOptimizer() { + return supplier.get(); + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizers.java b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizers.java index 22b33b2..442bdf5 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizers.java +++ b/src/main/java/ru/windcorp/progressia/client/world/cro/ChunkRenderOptimizers.java @@ -1,50 +1,53 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.cro; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -public class ChunkRenderOptimizers { - - private ChunkRenderOptimizers() {} - - private static final Map SUPPLIERS = - new HashMap<>(); - - static { - register(ChunkRenderOptimizerSupplier.of( - "Default:OpaqueCube", - ChunkRenderOptimizerCube::new - )); - } - - public static ChunkRenderOptimizerSupplier getSupplier(String id) { - return SUPPLIERS.get(id); - } - - public static void register(ChunkRenderOptimizerSupplier supplier) { - SUPPLIERS.put(supplier.getId(), supplier); - } - - public static Collection getAllSuppliers() { - return SUPPLIERS.values(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.cro; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class ChunkRenderOptimizers { + + private ChunkRenderOptimizers() { + } + + private static final Map SUPPLIERS = new HashMap<>(); + + static { + register( + ChunkRenderOptimizerSupplier.of( + "Default:OpaqueCube", + ChunkRenderOptimizerCube::new + ) + ); + } + + public static ChunkRenderOptimizerSupplier getSupplier(String id) { + return SUPPLIERS.get(id); + } + + public static void register(ChunkRenderOptimizerSupplier supplier) { + SUPPLIERS.put(supplier.getId(), supplier); + } + + public static Collection getAllSuppliers() { + return SUPPLIERS.values(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java index bb53974..13a2b24 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRender.java @@ -1,14 +1,32 @@ -package ru.windcorp.progressia.client.world.entity; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.entity.EntityData; - -public abstract class EntityRender extends Namespaced { - - public EntityRender(String id) { - super(id); - } - - public abstract EntityRenderable createRenderable(EntityData entity); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.entity; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public abstract class EntityRender extends Namespaced { + + public EntityRender(String id) { + super(id); + } + + public abstract EntityRenderable createRenderable(EntityData entity); + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java index df67f94..60b7bf6 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderRegistry.java @@ -1,36 +1,53 @@ -package ru.windcorp.progressia.client.world.entity; - -import java.io.IOException; - -import ru.windcorp.progressia.client.graphics.texture.TextureLoader; -import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; -import ru.windcorp.progressia.client.graphics.texture.TextureSettings; -import ru.windcorp.progressia.common.resource.ResourceManager; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class EntityRenderRegistry extends NamespacedInstanceRegistry { - - private static final EntityRenderRegistry INSTANCE = - new EntityRenderRegistry(); - - public static EntityRenderRegistry getInstance() { - return INSTANCE; - } - - public static TexturePrimitive getEntityTexture(String name) { - try { - return new TexturePrimitive( - TextureLoader.loadPixels( - ResourceManager.getTextureResource( - "entities/" + name - ), - new TextureSettings(false) - ).getData() - ); - } catch (IOException e) { - throw CrashReports.report(e, "Could not load entity texture %s", name); - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.entity; + +import java.io.IOException; + +import ru.windcorp.progressia.client.graphics.texture.TextureLoader; +import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive; +import ru.windcorp.progressia.client.graphics.texture.TextureSettings; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class EntityRenderRegistry extends NamespacedInstanceRegistry { + + private static final EntityRenderRegistry INSTANCE = new EntityRenderRegistry(); + + public static EntityRenderRegistry getInstance() { + return INSTANCE; + } + + public static TexturePrimitive getEntityTexture(String name) { + try { + return new TexturePrimitive( + TextureLoader.loadPixels( + ResourceManager.getTextureResource( + "entities/" + name + ), + new TextureSettings(false) + ).getData() + ); + } catch (IOException e) { + throw CrashReports.report(e, "Could not load entity texture %s", name); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java index 067b640..eecaa16 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/EntityRenderable.java @@ -1,34 +1,52 @@ -package ru.windcorp.progressia.client.world.entity; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericEntity; - -public abstract class EntityRenderable implements Renderable, GenericEntity { - - private final EntityData data; - - public EntityRenderable(EntityData data) { - this.data = data; - } - - public EntityData getData() { - return data; - } - - @Override - public Vec3 getPosition() { - return getData().getPosition(); - } - - @Override - public String getId() { - return getData().getId(); - } - - public void getViewPoint(Vec3 output) { - output.set(0, 0, 0); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.entity; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.GenericEntity; + +public abstract class EntityRenderable implements Renderable, GenericEntity { + + private final EntityData data; + + public EntityRenderable(EntityData data) { + this.data = data; + } + + public EntityData getData() { + return data; + } + + @Override + public Vec3 getPosition() { + return getData().getPosition(); + } + + @Override + public String getId() { + return getData().getId(); + } + + public void getViewPoint(Vec3 output) { + output.set(0, 0, 0); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java index d902cf3..1609bfc 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/HumanoidModel.java @@ -1,116 +1,140 @@ -package ru.windcorp.progressia.client.world.entity; - -import static java.lang.Math.*; -import static ru.windcorp.progressia.common.util.FloatMathUtil.*; - -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.common.world.entity.EntityData; - -public class HumanoidModel extends NPedModel { - - protected static abstract class Limb extends BodyPart { - private final float animationOffset; - - public Limb( - Renderable renderable, Vec3 joint, - float animationOffset - ) { - super(renderable, joint); - this.animationOffset = animationOffset; - } - - @Override - protected void applyTransform(Mat4 mat, NPedModel model) { - float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; - float value = sin(phase); - float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter(); - mat.rotateY(value * amplitude); - } - - protected abstract float getSwingAmplitude(HumanoidModel model); - - } - - public static class Leg extends Limb { - public Leg( - Renderable renderable, Vec3 joint, - float animationOffset - ) { - super(renderable, joint, animationOffset); - } - - @Override - protected float getSwingAmplitude(HumanoidModel model) { - return model.walkingLegSwing; - } - } - - public static class Arm extends Limb { - public Arm( - Renderable renderable, Vec3 joint, - float animationOffset - ) { - super(renderable, joint, animationOffset); - } - - @Override - protected float getSwingAmplitude(HumanoidModel model) { - return model.walkingArmSwing; - } - } - - private final Arm leftArm; - private final Arm rightArm; - private final Leg leftLeg; - private final Leg rightLeg; - - private float walkingLegSwing; - private float walkingArmSwing; - - public HumanoidModel( - EntityData entity, - - Body body, Head head, - Arm leftArm, Arm rightArm, - Leg leftLeg, Leg rightLeg, - - float scale - ) { - super(entity, body, head, scale); - this.leftArm = leftArm; - this.rightArm = rightArm; - this.leftLeg = leftLeg; - this.rightLeg = rightLeg; - } - - @Override - protected void renderBodyParts(ShapeRenderHelper renderer) { - super.renderBodyParts(renderer); - leftArm.render(renderer, this); - rightArm.render(renderer, this); - leftLeg.render(renderer, this); - rightLeg.render(renderer, this); - } - - public float getWalkingArmSwing() { - return walkingArmSwing; - } - - public float getWalkingLegSwing() { - return walkingLegSwing; - } - - public HumanoidModel setWalkingLegSwing(float walkingLegSwing) { - this.walkingLegSwing = walkingLegSwing; - return this; - } - - public HumanoidModel setWalkingArmSwing(float walkingArmSwing) { - this.walkingArmSwing = walkingArmSwing; - return this; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.entity; + +import static java.lang.Math.*; +import static ru.windcorp.progressia.common.util.FloatMathUtil.*; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public class HumanoidModel extends NPedModel { + + protected static abstract class Limb extends BodyPart { + private final float animationOffset; + + public Limb( + Renderable renderable, + Vec3 joint, + float animationOffset + ) { + super(renderable, joint); + this.animationOffset = animationOffset; + } + + @Override + protected void applyTransform(Mat4 mat, NPedModel model) { + float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; + float value = sin(phase); + float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter(); + mat.rotateY(value * amplitude); + } + + protected abstract float getSwingAmplitude(HumanoidModel model); + + } + + public static class Leg extends Limb { + public Leg( + Renderable renderable, + Vec3 joint, + float animationOffset + ) { + super(renderable, joint, animationOffset); + } + + @Override + protected float getSwingAmplitude(HumanoidModel model) { + return model.walkingLegSwing; + } + } + + public static class Arm extends Limb { + public Arm( + Renderable renderable, + Vec3 joint, + float animationOffset + ) { + super(renderable, joint, animationOffset); + } + + @Override + protected float getSwingAmplitude(HumanoidModel model) { + return model.walkingArmSwing; + } + } + + private final Arm leftArm; + private final Arm rightArm; + private final Leg leftLeg; + private final Leg rightLeg; + + private float walkingLegSwing; + private float walkingArmSwing; + + public HumanoidModel( + EntityData entity, + + Body body, + Head head, + Arm leftArm, + Arm rightArm, + Leg leftLeg, + Leg rightLeg, + + float scale + ) { + super(entity, body, head, scale); + this.leftArm = leftArm; + this.rightArm = rightArm; + this.leftLeg = leftLeg; + this.rightLeg = rightLeg; + } + + @Override + protected void renderBodyParts(ShapeRenderHelper renderer) { + super.renderBodyParts(renderer); + leftArm.render(renderer, this); + rightArm.render(renderer, this); + leftLeg.render(renderer, this); + rightLeg.render(renderer, this); + } + + public float getWalkingArmSwing() { + return walkingArmSwing; + } + + public float getWalkingLegSwing() { + return walkingLegSwing; + } + + public HumanoidModel setWalkingLegSwing(float walkingLegSwing) { + this.walkingLegSwing = walkingLegSwing; + return this; + } + + public HumanoidModel setWalkingArmSwing(float walkingArmSwing) { + this.walkingArmSwing = walkingArmSwing; + return this; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java index e766fae..ead6565 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/NPedModel.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.world.entity; import static java.lang.Math.atan2; @@ -19,39 +37,39 @@ import ru.windcorp.progressia.common.world.entity.EntityData; public abstract class NPedModel extends EntityRenderable { protected static abstract class BodyPart { - private final Renderable renderable; - private final Vec3 translation = new Vec3(); - - public BodyPart(Renderable renderable, Vec3 joint) { - this.renderable = renderable; - if (joint != null) { - this.translation.set(joint); - } - } - - - protected void render( - ShapeRenderHelper renderer, NPedModel model - ) { - renderer.pushTransform().translate(translation); - applyTransform(renderer.pushTransform(), model); - renderable.render(renderer); - renderer.popTransform(); - renderer.popTransform(); - } - - protected abstract void applyTransform(Mat4 mat, NPedModel model); - - public Vec3 getTranslation() { - return translation; + private final Renderable renderable; + private final Vec3 translation = new Vec3(); + + public BodyPart(Renderable renderable, Vec3 joint) { + this.renderable = renderable; + if (joint != null) { + this.translation.set(joint); } } + protected void render( + ShapeRenderHelper renderer, + NPedModel model + ) { + renderer.pushTransform().translate(translation); + applyTransform(renderer.pushTransform(), model); + renderable.render(renderer); + renderer.popTransform(); + renderer.popTransform(); + } + + protected abstract void applyTransform(Mat4 mat, NPedModel model); + + public Vec3 getTranslation() { + return translation; + } + } + public static class Body extends BodyPart { public Body(Renderable renderable) { super(renderable, null); } - + @Override protected void applyTransform(Mat4 mat, NPedModel model) { // Do nothing @@ -61,25 +79,27 @@ public abstract class NPedModel extends EntityRenderable { public static class Head extends BodyPart { private final float maxYaw; private final float maxPitch; - + private final Vec3 viewPoint; - + public Head( - Renderable renderable, Vec3 joint, - double maxYawDegrees, double maxPitchDegrees, - Vec3 viewPoint + Renderable renderable, + Vec3 joint, + double maxYawDegrees, + double maxPitchDegrees, + Vec3 viewPoint ) { super(renderable, joint); this.maxYaw = (float) toRadians(maxYawDegrees); this.maxPitch = (float) toRadians(maxPitchDegrees); this.viewPoint = viewPoint; } - + @Override protected void applyTransform(Mat4 mat, NPedModel model) { mat.rotateZ(model.getHeadYaw()).rotateY(model.getHeadPitch()); } - + public Vec3 getViewPoint() { return viewPoint; } @@ -87,26 +107,27 @@ public abstract class NPedModel extends EntityRenderable { protected final Body body; protected final Head head; - + private float walkingParameter = 0; private float velocityParameter = 0; private float velocity = 0; - + /** - * If {@link #velocity} is greater than this value, {@link #velocityParameter} is 1.0. + * If {@link #velocity} is greater than this value, + * {@link #velocityParameter} is 1.0. */ private float maxEffectiveVelocity = 5 * Units.METERS_PER_SECOND; - + /** * If {@link #velocity} is less than {@link #maxEffectiveVelocity}, then * {@code velocityCoeff = exp(velocity / maxEffectiveVelocity, velocityCoeffPower)}. */ private float velocityCoeffPower = 1; - + private final float scale; - + private float walkingFrequency; - + private float bodyYaw = Float.NaN; private float headYaw; private float headPitch; @@ -116,7 +137,7 @@ public abstract class NPedModel extends EntityRenderable { this.body = body; this.head = head; this.scale = scale; - + evaluateAngles(); } @@ -125,7 +146,7 @@ public abstract class NPedModel extends EntityRenderable { renderer.pushTransform().scale(scale).rotateZ(bodyYaw); renderBodyParts(renderer); renderer.popTransform(); - + accountForVelocity(); evaluateAngles(); } @@ -137,13 +158,13 @@ public abstract class NPedModel extends EntityRenderable { private void evaluateAngles() { float globalYaw = normalizeAngle(getData().getYaw()); - + if (Float.isNaN(bodyYaw)) { bodyYaw = globalYaw; headYaw = 0; } else { headYaw = normalizeAngle(globalYaw - bodyYaw); - + if (headYaw > +head.maxYaw) { bodyYaw += headYaw - +head.maxYaw; headYaw = +head.maxYaw; @@ -152,28 +173,29 @@ public abstract class NPedModel extends EntityRenderable { headYaw = -head.maxYaw; } } - + bodyYaw = normalizeAngle(bodyYaw); - + headPitch = Glm.clamp( - getData().getPitch(), - -head.maxPitch, head.maxPitch + getData().getPitch(), + -head.maxPitch, + head.maxPitch ); } private void accountForVelocity() { Vec3 horizontal = new Vec3(getData().getVelocity()); horizontal.z = 0; - + velocity = horizontal.length(); - + evaluateVelocityCoeff(); - + // TODO switch to world time walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000; - + bodyYaw += velocityParameter * normalizeAngle( - (float) (atan2(horizontal.y, horizontal.x) - bodyYaw) + (float) (atan2(horizontal.y, horizontal.x) - bodyYaw) ) * min(1, GraphicsInterface.getFrameLength() * 10); } @@ -189,91 +211,97 @@ public abstract class NPedModel extends EntityRenderable { public void getViewPoint(Vec3 output) { Mat4 m = new Mat4(); Vec4 v = new Vec4(); - + m.identity() - .scale(scale) - .rotateZ(bodyYaw) - .translate(head.getTranslation()) - .rotateZ(headYaw) - .rotateY(headPitch); - + .scale(scale) + .rotateZ(bodyYaw) + .translate(head.getTranslation()) + .rotateZ(headYaw) + .rotateY(headPitch); + v.set(head.getViewPoint(), 1); m.mul(v); - + output.set(v.x, v.y, v.z); } - + public Body getBody() { return body; } - + public Head getHead() { return head; } - + public float getBodyYaw() { return bodyYaw; } - + public float getHeadYaw() { return headYaw; } - + public float getHeadPitch() { return headPitch; } - + /** - * Returns a number in the range [0; 1] that can be used to scale animation effects that depend on speed. - * This parameter is 0 when the entity is not moving and 1 when it's moving "fast". + * Returns a number in the range [0; 1] that can be used to scale animation + * effects that depend on speed. + * This parameter is 0 when the entity is not moving and 1 when it's moving + * "fast". + * * @return velocity parameter */ protected float getVelocityParameter() { return velocityParameter; } - + /** - * Returns a number that can be used to parameterize animation effects that depend on walking. - * This parameter increases when the entity moves (e.g. this can be total traveled distance). + * Returns a number that can be used to parameterize animation effects that + * depend on walking. + * This parameter increases when the entity moves (e.g. this can be total + * traveled distance). + * * @return walking parameter */ protected float getWalkingParameter() { return walkingParameter; } - + protected float getVelocity() { return velocity; } - + public float getScale() { return scale; } - + protected float getWalkingFrequency() { return walkingFrequency; } - + public NPedModel setWalkingFrequency(float walkingFrequency) { this.walkingFrequency = walkingFrequency; return this; } - + public float getMaxEffectiveVelocity() { return maxEffectiveVelocity; } - + public float getVelocityCoeffPower() { return velocityCoeffPower; } - + public NPedModel setMaxEffectiveVelocity(float maxEffectiveVelocity) { this.maxEffectiveVelocity = maxEffectiveVelocity; return this; } - + public NPedModel setVelocityCoeffPower(float velocityCoeffPower) { this.velocityCoeffPower = velocityCoeffPower; return this; } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java index 124234e..8755b08 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java +++ b/src/main/java/ru/windcorp/progressia/client/world/entity/QuadripedModel.java @@ -1,76 +1,98 @@ -package ru.windcorp.progressia.client.world.entity; - -import static java.lang.Math.*; -import static ru.windcorp.progressia.common.util.FloatMathUtil.*; -import static ru.windcorp.progressia.common.util.FloatMathUtil.sin; - -import glm.mat._4.Mat4; -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.common.world.entity.EntityData; - -public class QuadripedModel extends NPedModel { - - public static class Leg extends BodyPart { - private final float animationOffset; - - public Leg( - Renderable renderable, Vec3 joint, - float animationOffset - ) { - super(renderable, joint); - this.animationOffset = animationOffset; - } - - @Override - protected void applyTransform(Mat4 mat, NPedModel model) { - float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; - float value = sin(phase); - float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter(); - mat.rotateY(value * amplitude); - } - - } - - private final Leg leftForeLeg, rightForeLeg; - private final Leg leftHindLeg, rightHindLeg; - - private float walkingSwing = (float) toRadians(30); - - public QuadripedModel( - EntityData entity, - - Body body, Head head, - Leg leftForeLeg, Leg rightForeLeg, - Leg leftHindLeg, Leg rightHindLeg, - - float scale - ) { - super(entity, body, head, scale); - - this.leftForeLeg = leftForeLeg; - this.rightForeLeg = rightForeLeg; - this.leftHindLeg = leftHindLeg; - this.rightHindLeg = rightHindLeg; - } - - @Override - protected void renderBodyParts(ShapeRenderHelper renderer) { - super.renderBodyParts(renderer); - this.leftForeLeg.render(renderer, this); - this.rightForeLeg.render(renderer, this); - this.leftHindLeg.render(renderer, this); - this.rightHindLeg.render(renderer, this); - } - - public float getWalkingSwing() { - return walkingSwing; - } - - public QuadripedModel setWalkingSwing(float walkingSwing) { - this.walkingSwing = walkingSwing; - return this; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.entity; + +import static java.lang.Math.*; +import static ru.windcorp.progressia.common.util.FloatMathUtil.*; +import static ru.windcorp.progressia.common.util.FloatMathUtil.sin; + +import glm.mat._4.Mat4; +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.common.world.entity.EntityData; + +public class QuadripedModel extends NPedModel { + + public static class Leg extends BodyPart { + private final float animationOffset; + + public Leg( + Renderable renderable, + Vec3 joint, + float animationOffset + ) { + super(renderable, joint); + this.animationOffset = animationOffset; + } + + @Override + protected void applyTransform(Mat4 mat, NPedModel model) { + float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset; + float value = sin(phase); + float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter(); + mat.rotateY(value * amplitude); + } + + } + + private final Leg leftForeLeg, rightForeLeg; + private final Leg leftHindLeg, rightHindLeg; + + private float walkingSwing = (float) toRadians(30); + + public QuadripedModel( + EntityData entity, + + Body body, + Head head, + Leg leftForeLeg, + Leg rightForeLeg, + Leg leftHindLeg, + Leg rightHindLeg, + + float scale + ) { + super(entity, body, head, scale); + + this.leftForeLeg = leftForeLeg; + this.rightForeLeg = rightForeLeg; + this.leftHindLeg = leftHindLeg; + this.rightHindLeg = rightHindLeg; + } + + @Override + protected void renderBodyParts(ShapeRenderHelper renderer) { + super.renderBodyParts(renderer); + this.leftForeLeg.render(renderer, this); + this.rightForeLeg.render(renderer, this); + this.leftHindLeg.render(renderer, this); + this.rightHindLeg.render(renderer, this); + } + + public float getWalkingSwing() { + return walkingSwing; + } + + public QuadripedModel setWalkingSwing(float walkingSwing) { + this.walkingSwing = walkingSwing; + return this; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java index 3e78ee9..99f3f9a 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRender.java @@ -1,34 +1,52 @@ -package ru.windcorp.progressia.client.world.tile; - -import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericTile; - -public class TileRender extends Namespaced implements GenericTile { - - public TileRender(String id) { - super(id); - } - - public void render(ShapeRenderHelper renderer, BlockFace face) { - throw new UnsupportedOperationException( - "TileRender.render() not implemented in " + this - ); - } - - public Renderable createRenderable(BlockFace face) { - return null; - } - - public boolean canBeOptimized(ChunkRenderOptimizer optimizer) { - return true; - } - - public boolean needsOwnRenderable() { - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.tile; + +import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizer; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericTile; + +public class TileRender extends Namespaced implements GenericTile { + + public TileRender(String id) { + super(id); + } + + public void render(ShapeRenderHelper renderer, BlockFace face) { + throw new UnsupportedOperationException( + "TileRender.render() not implemented in " + this + ); + } + + public Renderable createRenderable(BlockFace face) { + return null; + } + + public boolean canBeOptimized(ChunkRenderOptimizer optimizer) { + return true; + } + + public boolean needsOwnRenderable() { + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java index ed71936..98c5fa4 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderGrass.java @@ -1,57 +1,81 @@ -package ru.windcorp.progressia.client.world.tile; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Faces; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueSurface; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public class TileRenderGrass extends TileRender implements OpaqueSurface { - - private final Texture topTexture; - private final Texture sideTexture; - - public TileRenderGrass( - String id, - Texture top, Texture side - ) { - super(id); - this.topTexture = top; - this.sideTexture = side; - } - - @Override - public Texture getTexture(BlockFace face) { - return (face == BlockFace.TOP) ? topTexture : sideTexture; - } - - @Override - public boolean isOpaque(BlockFace face) { - return face == BlockFace.TOP; - } - - @Override - public Renderable createRenderable(BlockFace face) { - ShapeRenderProgram program = WorldRenderProgram.getDefault(); - - return new Shape( - Usage.STATIC, WorldRenderProgram.getDefault(), - Faces.createBlockFace( - program, getTexture(face), Colors.WHITE, - new Vec3(0, 0, 0), face, false - ) - ); - } - - @Override - public boolean needsOwnRenderable() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.tile; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueSurface; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public class TileRenderGrass extends TileRender implements OpaqueSurface { + + private final Texture topTexture; + private final Texture sideTexture; + + public TileRenderGrass( + String id, + Texture top, + Texture side + ) { + super(id); + this.topTexture = top; + this.sideTexture = side; + } + + @Override + public Texture getTexture(BlockFace face) { + return (face == BlockFace.TOP) ? topTexture : sideTexture; + } + + @Override + public boolean isOpaque(BlockFace face) { + return face == BlockFace.TOP; + } + + @Override + public Renderable createRenderable(BlockFace face) { + ShapeRenderProgram program = WorldRenderProgram.getDefault(); + + return new Shape( + Usage.STATIC, + WorldRenderProgram.getDefault(), + Faces.createBlockFace( + program, + getTexture(face), + Colors.WHITE, + new Vec3(0, 0, 0), + face, + false + ) + ); + } + + @Override + public boolean needsOwnRenderable() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java index 05f1900..e4990e8 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderOpaqueSurface.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java index 4c11c01..b240933 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderRegistry.java @@ -1,51 +1,51 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.client.world.tile; - -import ru.windcorp.progressia.client.graphics.texture.Atlases; -import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup; -import ru.windcorp.progressia.client.graphics.texture.SimpleTexture; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.common.resource.ResourceManager; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class TileRenderRegistry extends NamespacedInstanceRegistry { - - private static final TileRenderRegistry INSTANCE = new TileRenderRegistry(); - - private static final AtlasGroup TILES_ATLAS_GROUP = - new AtlasGroup("Tiles", 1 << 12); - - public static TileRenderRegistry getInstance() { - return INSTANCE; - } - - public static AtlasGroup getTilesAtlasGroup() { - return TILES_ATLAS_GROUP; - } - - public static Texture getTileTexture(String name) { - return new SimpleTexture( - Atlases.getSprite( - ResourceManager.getTextureResource("tiles/" + name), - TILES_ATLAS_GROUP - ) - ); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.tile; + +import ru.windcorp.progressia.client.graphics.texture.Atlases; +import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup; +import ru.windcorp.progressia.client.graphics.texture.SimpleTexture; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.common.resource.ResourceManager; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class TileRenderRegistry extends NamespacedInstanceRegistry { + + private static final TileRenderRegistry INSTANCE = new TileRenderRegistry(); + + private static final AtlasGroup TILES_ATLAS_GROUP = new AtlasGroup("Tiles", 1 << 12); + + public static TileRenderRegistry getInstance() { + return INSTANCE; + } + + public static AtlasGroup getTilesAtlasGroup() { + return TILES_ATLAS_GROUP; + } + + public static Texture getTileTexture(String name) { + return new SimpleTexture( + Atlases.getSprite( + ResourceManager.getTextureResource("tiles/" + name), + TILES_ATLAS_GROUP + ) + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java index 2d81c11..6bb8fb0 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderStack.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.world.ChunkRender; @@ -5,12 +23,8 @@ import ru.windcorp.progressia.common.world.generic.GenericTileStack; import ru.windcorp.progressia.common.world.tile.TileDataStack; public abstract class TileRenderStack -extends GenericTileStack< - TileRenderStack, - TileRender, - ChunkRender -> { - + extends GenericTileStack { + public abstract TileDataStack getData(); - + } diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java index 43719ee..ea942ed 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderSurface.java @@ -1,47 +1,70 @@ -package ru.windcorp.progressia.client.world.tile; - -import glm.vec._3.Vec3; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.backend.Usage; -import ru.windcorp.progressia.client.graphics.model.Faces; -import ru.windcorp.progressia.client.graphics.model.Shape; -import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; -import ru.windcorp.progressia.client.graphics.model.Renderable; -import ru.windcorp.progressia.client.graphics.texture.Texture; -import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; -import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueSurface; -import ru.windcorp.progressia.common.world.block.BlockFace; - -public abstract class TileRenderSurface extends TileRender implements OpaqueSurface { - - private final Texture texture; - - public TileRenderSurface(String id, Texture texture) { - super(id); - this.texture = texture; - } - - @Override - public Texture getTexture(BlockFace face) { - return texture; - } - - @Override - public Renderable createRenderable(BlockFace face) { - ShapeRenderProgram program = WorldRenderProgram.getDefault(); - - return new Shape( - Usage.STATIC, WorldRenderProgram.getDefault(), - Faces.createBlockFace( - program, getTexture(face), Colors.WHITE, - new Vec3(0, 0, 0), face, false - ) - ); - } - - @Override - public boolean needsOwnRenderable() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.client.world.tile; + +import glm.vec._3.Vec3; +import ru.windcorp.progressia.client.graphics.Colors; +import ru.windcorp.progressia.client.graphics.backend.Usage; +import ru.windcorp.progressia.client.graphics.model.Faces; +import ru.windcorp.progressia.client.graphics.model.Shape; +import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram; +import ru.windcorp.progressia.client.graphics.model.Renderable; +import ru.windcorp.progressia.client.graphics.texture.Texture; +import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; +import ru.windcorp.progressia.client.world.cro.ChunkRenderOptimizerCube.OpaqueSurface; +import ru.windcorp.progressia.common.world.block.BlockFace; + +public abstract class TileRenderSurface extends TileRender implements OpaqueSurface { + + private final Texture texture; + + public TileRenderSurface(String id, Texture texture) { + super(id); + this.texture = texture; + } + + @Override + public Texture getTexture(BlockFace face) { + return texture; + } + + @Override + public Renderable createRenderable(BlockFace face) { + ShapeRenderProgram program = WorldRenderProgram.getDefault(); + + return new Shape( + Usage.STATIC, + WorldRenderProgram.getDefault(), + Faces.createBlockFace( + program, + getTexture(face), + Colors.WHITE, + new Vec3(0, 0, 0), + face, + false + ) + ); + } + + @Override + public boolean needsOwnRenderable() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java index 6239d47..b35986e 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java +++ b/src/main/java/ru/windcorp/progressia/client/world/tile/TileRenderTransparentSurface.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.client.world.tile; import ru.windcorp.progressia.client.graphics.texture.Texture; diff --git a/src/main/java/ru/windcorp/progressia/common/Units.java b/src/main/java/ru/windcorp/progressia/common/Units.java index d224829..842e378 100644 --- a/src/main/java/ru/windcorp/progressia/common/Units.java +++ b/src/main/java/ru/windcorp/progressia/common/Units.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common; import java.lang.annotation.ElementType; @@ -19,144 +37,152 @@ import ru.windcorp.jputil.chars.StringUtil; import ru.windcorp.progressia.common.util.crash.CrashReports; public class Units { - + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public static @interface RegisteredUnit { String[] value(); } - + // Base units // We're SI. @RegisteredUnit("m") - public static final float METERS = 1; - public static final float KILOGRAMS = 1; + public static final float METERS = 1; + public static final float KILOGRAMS = 1; @RegisteredUnit("s") - public static final float SECONDS = 1; + public static final float SECONDS = 1; // Length - public static final float CENTIMETERS = METERS / 100; - public static final float MILLIMETERS = METERS / 1000; - public static final float KILOMETERS = METERS * 1000; - + public static final float CENTIMETERS = METERS / 100; + public static final float MILLIMETERS = METERS / 1000; + public static final float KILOMETERS = METERS * 1000; + // Surface - public static final float SQUARE_CENTIMETERS = CENTIMETERS * CENTIMETERS; - public static final float SQUARE_METERS = METERS * METERS; - public static final float SQUARE_MILLIMETERS = MILLIMETERS * MILLIMETERS; - public static final float SQUARE_KILOMETERS = KILOMETERS * KILOMETERS; - + public static final float SQUARE_CENTIMETERS = CENTIMETERS * CENTIMETERS; + public static final float SQUARE_METERS = METERS * METERS; + public static final float SQUARE_MILLIMETERS = MILLIMETERS * MILLIMETERS; + public static final float SQUARE_KILOMETERS = KILOMETERS * KILOMETERS; + // Volume - public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS; - public static final float CUBIC_METERS = METERS * METERS * METERS; - public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS; - public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS; + public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS; + public static final float CUBIC_METERS = METERS * METERS * METERS; + public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS; + public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS; // Mass @RegisteredUnit("g") - public static final float GRAMS = KILOGRAMS / 1000; + public static final float GRAMS = KILOGRAMS / 1000; @RegisteredUnit("t") - public static final float TONNES = KILOGRAMS * 1000; - + public static final float TONNES = KILOGRAMS * 1000; + // Density - public static final float KILOGRAMS_PER_CUBIC_METER = KILOGRAMS / CUBIC_METERS; + public static final float KILOGRAMS_PER_CUBIC_METER = KILOGRAMS / CUBIC_METERS; public static final float GRAMS_PER_CUBIC_CENTIMETER = GRAMS / CUBIC_CENTIMETERS; // Time - public static final float MILLISECONDS = SECONDS / 1000; - @RegisteredUnit({"min", "mins", "minute", "minutes"}) - public static final float MINUTES = SECONDS * 60; - @RegisteredUnit({"h", "hr", "hrs", "hour", "hours"}) - public static final float HOURS = MINUTES * 60; - @RegisteredUnit({"d", "day", "days"}) - public static final float DAYS = HOURS * 24; - + public static final float MILLISECONDS = SECONDS / 1000; + @RegisteredUnit({ "min", "mins", "minute", "minutes" }) + public static final float MINUTES = SECONDS * 60; + @RegisteredUnit({ "h", "hr", "hrs", "hour", "hours" }) + public static final float HOURS = MINUTES * 60; + @RegisteredUnit({ "d", "day", "days" }) + public static final float DAYS = HOURS * 24; + // Frequency @RegisteredUnit("Hz") - public static final float HERTZ = 1 / SECONDS; - public static final float KILOHERTZ = HERTZ * 1000; + public static final float HERTZ = 1 / SECONDS; + public static final float KILOHERTZ = HERTZ * 1000; // Velocity - public static final float METERS_PER_SECOND = METERS / SECONDS; - public static final float KILOMETERS_PER_HOUR = KILOMETERS / HOURS; + public static final float METERS_PER_SECOND = METERS / SECONDS; + public static final float KILOMETERS_PER_HOUR = KILOMETERS / HOURS; // Acceleration - public static final float METERS_PER_SECOND_SQUARED = METERS_PER_SECOND / SECONDS; + public static final float METERS_PER_SECOND_SQUARED = METERS_PER_SECOND / SECONDS; // Force @RegisteredUnit("N") - public static final float NEWTONS = METERS_PER_SECOND_SQUARED * KILOGRAMS; - + public static final float NEWTONS = METERS_PER_SECOND_SQUARED * KILOGRAMS; + /* * Utilities */ - + private static final TObjectFloatMap UNITS_BY_NAME = createMap(); - + private static final TCharFloatMap PREFIXES_BY_CHAR; static { TCharFloatMap prefixes = new TCharFloatHashMap( - gnu.trove.impl.Constants.DEFAULT_CAPACITY, - gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, - gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE, - Float.NaN + gnu.trove.impl.Constants.DEFAULT_CAPACITY, + gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, + gnu.trove.impl.Constants.DEFAULT_CHAR_NO_ENTRY_VALUE, + Float.NaN ); - + prefixes.put('G', 1e+9f); prefixes.put('M', 1e+6f); prefixes.put('k', 1e+3f); prefixes.put('c', 1e-2f); prefixes.put('m', 1e-3f); - prefixes.put('u', 1e-6f); // not using U+00B5 MICRO SIGN for ease of input - - + prefixes.put('u', 1e-6f); // not using U+00B5 MICRO SIGN for ease of + // input + PREFIXES_BY_CHAR = TCollections.unmodifiableMap(prefixes); } - + private static final TObjectFloatMap KNOWN_UNITS = createMap(); - + private static TObjectFloatMap createMap() { return TCollections.synchronizedMap( - new TObjectFloatHashMap<>( - gnu.trove.impl.Constants.DEFAULT_CAPACITY, - gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, - Float.NaN - ) + new TObjectFloatHashMap<>( + gnu.trove.impl.Constants.DEFAULT_CAPACITY, + gnu.trove.impl.Constants.DEFAULT_LOAD_FACTOR, + Float.NaN + ) ); } - + public static void registerUnits(Class source) throws IllegalAccessException { for (Field field : source.getDeclaredFields()) { int mods = field.getModifiers(); - - if (!Modifier.isPublic(mods)) continue; - if (!Modifier.isStatic(mods)) continue; - if (!Modifier.isFinal(mods)) continue; - if (field.getType() != Float.TYPE) continue; - + + if (!Modifier.isPublic(mods)) + continue; + if (!Modifier.isStatic(mods)) + continue; + if (!Modifier.isFinal(mods)) + continue; + if (field.getType() != Float.TYPE) + continue; + RegisteredUnit request = field.getAnnotation(RegisteredUnit.class); - if (request == null) continue; - - float value = field.getFloat(null); // adding throws since we might not have accounted for something + if (request == null) + continue; + + float value = field.getFloat(null); // adding throws since we might + // not have accounted for + // something registerUnit(value, request.value()); } } - + public static void registerUnit(float value, String... names) { for (String name : names) { float previous = UNITS_BY_NAME.put(name, value); - + if (!Float.isNaN(previous)) { throw new IllegalArgumentException("Duplicate unit name " + name); } } - + LogManager.getLogger().debug("Registered unit {} with value {}", Arrays.toString(names), value); } - + /** * Returns the value of the unit described by {@code declar}. + *

+ * The general form of a declaration is: * - *

The general form of a declaration is: *

 	 * unit_declar       ::= [ws]unit_declar_part[[ws]"/"[ws]unit_declar_part][ws]
 	 * unit_declar_part  ::= unit_name_and_exp[[ws]"*"[ws]unit_name_and_exp]+
@@ -166,7 +192,8 @@ public class Units {
 	 * prefix            ::= "G" | "M" | "k" | "c" | "m" | "µ" (\u00B5) | "u"
 	 * special_unit      ::= "1"
 	 * exponent          ::= <any float>
-	 * ws                ::= <any character <= 'U+0020'>+
+ * ws ::= <any character <= 'U+0020'>+ + * * * Examples: *
    @@ -175,30 +202,36 @@ public class Units { *
  • kilonewtons = {@code "kN"}
  • *
  • square meters = {@code "m^2"}
  • *
  • units per meter = {@code "1/m"}
  • - *
  • units of gravitational constant G = {@code "m^3/kg*s^2"} [sic] (see below)
  • + *
  • units of gravitational constant G = {@code "m^3/kg*s^2"} [sic] (see + * below)
  • *
  • units (dimensionless) = {@code "1"}
  • *
- * - * Note that no more than one {@code '/'} is allowed per declaration, and no parenthesis are allowed at all. As such, + * Note that no more than one {@code '/'} is allowed per declaration, and no + * parenthesis are allowed at all. As such, *
    - *
  • Multiple units under the division bar should be located after the single {@code '/'} and separated by {@code '*'}: - * gas constant ought to have {@code "J/K*mol"} units.
  • - *
  • Exponentiation of parenthesis should be expanded: (m/s)² = {@code "m^2/s^2"}.
  • - *
  • Exponents should also be used for expressing roots: √s = {@code "s^0.5"}.
  • - *
  • Exponents can be used to express division, but such use is generally discouraged.
  • + *
  • Multiple units under the division bar should be located after the + * single {@code '/'} and separated by {@code '*'}: + * gas constant ought + * to have {@code "J/K*mol"} units.
  • + *
  • Exponentiation of parenthesis should be expanded: (m/s)² = + * {@code "m^2/s^2"}.
  • + *
  • Exponents should also be used for expressing roots: √s = + * {@code "s^0.5"}.
  • + *
  • Exponents can be used to express division, but such use is generally + * discouraged.
  • *
* * @param unit unit declaration * @throws IllegalArgumentException if the declaration is invalid * @return the value of the unit - * * @see #get(String) get(String) * @see #registerUnit(float, String...) */ public static final float getUnitValue(String unit) { float cached = KNOWN_UNITS.get(unit); - if (!Float.isNaN(cached)) return cached; - + if (!Float.isNaN(cached)) + return cached; + float computed = computeUnitValue(unit); KNOWN_UNITS.put(unit, computed); return computed; @@ -206,9 +239,9 @@ public class Units { private static float computeUnitValue(String unit) { String[] parts = StringUtil.split(unit, '/'); - + assert parts != null && parts.length != 0; - + switch (parts.length) { case 1: return parseUnitValue(parts[0]); @@ -221,13 +254,13 @@ public class Units { private static float parseUnitValue(String declar) { String[] unitsAndExponents = StringUtil.split(declar, '*'); - + float result = 1; for (String unitAndExponent : unitsAndExponents) { String[] parts = StringUtil.split(unitAndExponent, '^'); - + float exponent; - + assert parts != null && parts.length != 0; switch (parts.length) { case 1: @@ -239,18 +272,21 @@ public class Units { default: throw invalidUnit(unitAndExponent, "unit declaration contains more than one '^'"); } - + String unitName = parts[0].trim(); - + float value = parseUnitAsNamed(unitName); - if (Float.isNaN(value)) value = parseUnitAsNamedAndPrefixed(unitName); - if (Float.isNaN(value)) value = parseUnitAsSpecial(unitName); - if (Float.isNaN(value)) throw invalidUnit(unitName, "unknown unit name or unknown prefix or unknown special unit"); - + if (Float.isNaN(value)) + value = parseUnitAsNamedAndPrefixed(unitName); + if (Float.isNaN(value)) + value = parseUnitAsSpecial(unitName); + if (Float.isNaN(value)) + throw invalidUnit(unitName, "unknown unit name or unknown prefix or unknown special unit"); + if (exponent != 1) { value = (float) Math.pow(value, exponent); } - + result *= value; } return result; @@ -261,10 +297,12 @@ public class Units { } private static float parseUnitAsNamedAndPrefixed(String namedUnit) { - if (namedUnit.length() < 2) return Float.NaN; - + if (namedUnit.length() < 2) + return Float.NaN; + float value = PREFIXES_BY_CHAR.get(namedUnit.charAt(0)); - if (!Float.isNaN(value)) value *= parseUnitAsNamed(namedUnit.substring(1)); + if (!Float.isNaN(value)) + value *= parseUnitAsNamed(namedUnit.substring(1)); return value; } @@ -279,27 +317,29 @@ public class Units { public static double get(double amount, String unit) { return amount * getUnitValue(unit); } - + public static float get(float amount, String unit) { return amount * getUnitValue(unit); } - + public static float get(String declar) { String[] parts = StringUtil.split(declar, ' ', 2); assert parts != null && parts.length != 0; - if (parts[1] == null) throw new IllegalArgumentException("No space (' ') found"); + if (parts[1] == null) + throw new IllegalArgumentException("No space (' ') found"); assert parts[0] == parts[0].trim(); return Float.parseFloat(parts[0]) * getUnitValue(parts[1]); } - + public static double getd(String declar) { String[] parts = StringUtil.split(declar, ' ', 2); assert parts != null && parts.length != 0; - if (parts[1] == null) throw new IllegalArgumentException("No space (' ') found"); + if (parts[1] == null) + throw new IllegalArgumentException("No space (' ') found"); assert parts[0] == parts[0].trim(); return Double.parseDouble(parts[0]) * getUnitValue(parts[1]); } - + static { try { registerUnits(Units.class); diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java index e141673..fd8ffe9 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABB.java @@ -1,24 +1,51 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; /** * An implementation of an - * Axis-Aligned Bounding Box. + * Axis-Aligned + * Bounding Box. + * * @author javapony */ public class AABB implements AABBoid { - + private class AABBWallImpl implements Wall { - + private final Vec3 originOffset = new Vec3(); private final Vec3 widthSelector = new Vec3(); private final Vec3 heightSelector = new Vec3(); public AABBWallImpl( - float ox, float oy, float oz, - float wx, float wy, float wz, - float hx, float hy, float hz + float ox, + float oy, + float oz, + float wx, + float wy, + float wz, + float hx, + float hy, + float hz ) { this.originOffset.set(ox, oy, oz); this.widthSelector.set(wx, wy, wz); @@ -29,45 +56,49 @@ public class AABB implements AABBoid { public void getOrigin(Vec3 output) { output.set(originOffset).mul(AABB.this.getSize()).add(AABB.this.getOrigin()); } - + @Override public void getWidth(Vec3 output) { output.set(AABB.this.getSize()).mul(widthSelector); } - + @Override public void getHeight(Vec3 output) { output.set(AABB.this.getSize()).mul(heightSelector); } - + } - + public static final AABB UNIT_CUBE = new AABB(0, 0, 0, 1, 1, 1); - + private final Wall[] walls = new Wall[] { - new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top - new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom - new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North - new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South - new AABBWallImpl(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1), // West - new AABBWallImpl(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1) // East + new AABBWallImpl(-0.5f, -0.5f, +0.5f, +1, 0, 0, 0, +1, 0), // Top + new AABBWallImpl(-0.5f, -0.5f, -0.5f, 0, +1, 0, +1, 0, 0), // Bottom + new AABBWallImpl(+0.5f, -0.5f, -0.5f, 0, +1, 0, 0, 0, +1), // North + new AABBWallImpl(-0.5f, +0.5f, -0.5f, 0, -1, 0, 0, 0, +1), // South + new AABBWallImpl(+0.5f, +0.5f, -0.5f, -1, 0, 0, 0, 0, +1), // West + new AABBWallImpl(-0.5f, -0.5f, -0.5f, +1, 0, 0, 0, 0, +1) // East }; - + private final Vec3 origin = new Vec3(); private final Vec3 size = new Vec3(); - + public AABB(Vec3 origin, Vec3 size) { this(origin.x, origin.y, origin.z, size.x, size.y, size.z); } - + public AABB( - float ox, float oy, float oz, - float xSize, float ySize, float zSize + float ox, + float oy, + float oz, + float xSize, + float ySize, + float zSize ) { this.origin.set(ox, oy, oz); this.size.set(xSize, ySize, zSize); } - + public Vec3 getOrigin() { return origin; } @@ -76,17 +107,17 @@ public class AABB implements AABBoid { public void getOrigin(Vec3 output) { output.set(origin); } - + @Override public void setOrigin(Vec3 origin) { this.origin.set(origin); } - + @Override public void moveOrigin(Vec3 displacement) { this.origin.add(displacement); } - + public Vec3 getSize() { return size; } @@ -95,11 +126,11 @@ public class AABB implements AABBoid { public void getSize(Vec3 output) { output.set(size); } - + public void setSize(Vec3 size) { setSize(size.x, size.y, size.z); } - + public void setSize(float xSize, float ySize, float zSize) { this.size.set(xSize, ySize, zSize); } @@ -109,5 +140,5 @@ public class AABB implements AABBoid { // No, we don't support Apple. return walls[faceId]; } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java index 6e1d384..ab2cd80 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/AABBoid.java @@ -1,17 +1,36 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.world.block.BlockFace; public interface AABBoid extends CollisionModel { - + void getOrigin(Vec3 output); + void getSize(Vec3 output); - + default Wall getWall(BlockFace face) { return getWall(face.getId()); } - + Wall getWall(int faceId); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java b/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java index 9b6d5e6..8db7805 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/Collideable.java @@ -1,30 +1,53 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; import ru.windcorp.progressia.common.collision.colliders.Collider; public interface Collideable { - + CollisionModel getCollisionModel(); - + /** * Invoked by {@link Collider} when two entities are about to collide. * The world is at the moment of collision. + * * @param other the colliding object - * @return {@code true} iff the collision should not be handled normally (e.g. this object has disappeared) + * @return {@code true} iff the collision should not be handled normally + * (e.g. this object has disappeared) */ boolean onCollision(Collideable other); - + /** - * Returns the mass of this {@link Collideable} that should be used to calculate collisions. + * Returns the mass of this {@link Collideable} that should be used to + * calculate collisions. * Collision mass must be a positive number. Positive infinity is allowed. + * * @return this object's collision mass */ float getCollisionMass(); - + void moveAsCollideable(Vec3 displacement); - + void getCollideableVelocity(Vec3 output); + void changeVelocityOnCollision(Vec3 velocityChange); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java index 39f7ab7..9ade6af 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionModel.java @@ -1,10 +1,29 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; public interface CollisionModel { - + public void setOrigin(Vec3 origin); + public void moveOrigin(Vec3 displacement); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java index dd752dd..4826bce 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CollisionPathComputer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import java.util.function.Consumer; @@ -9,27 +27,27 @@ import ru.windcorp.progressia.common.util.Vectors; import static java.lang.Math.*; public class CollisionPathComputer { - + private static final float PADDING = 0.5f; - + public static void forEveryBlockInCollisionPath( - Collideable coll, - float maxTime, - Consumer action + Collideable coll, + float maxTime, + Consumer action ) { Vec3 displacement = Vectors.grab3(); coll.getCollideableVelocity(displacement); displacement.mul(maxTime); - + handleModel(coll.getCollisionModel(), displacement, action); - + Vectors.release(displacement); } private static void handleModel( - CollisionModel model, - Vec3 displacement, - Consumer action + CollisionModel model, + Vec3 displacement, + Consumer action ) { if (model instanceof CompoundCollisionModel) { for (CollisionModel subModel : ((CompoundCollisionModel) model).getModels()) { @@ -45,34 +63,34 @@ public class CollisionPathComputer { private static void handleAABBoid(AABBoid model, Vec3 displacement, Consumer action) { Vec3 size = Vectors.grab3(); Vec3 origin = Vectors.grab3(); - + model.getOrigin(origin); model.getSize(size); - + origin.mul(2).sub(size).div(2); // Subtract 0.5*size - + Vec3i pos = Vectors.grab3i(); - + for ( - pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); - pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); - pos.x += 1 + pos.x = (int) floor(origin.x + min(0, size.x) + min(0, displacement.x) - PADDING); + pos.x <= (int) ceil(origin.x + max(0, size.x) + max(0, displacement.x) + PADDING); + pos.x += 1 ) { for ( - pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); - pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); - pos.y += 1 + pos.y = (int) floor(origin.y + min(0, size.y) + min(0, displacement.y) - PADDING); + pos.y <= (int) ceil(origin.y + max(0, size.y) + max(0, displacement.y) + PADDING); + pos.y += 1 ) { for ( - pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); - pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); - pos.z += 1 + pos.z = (int) floor(origin.z + min(0, size.z) + min(0, displacement.z) - PADDING); + pos.z <= (int) ceil(origin.z + max(0, size.z) + max(0, displacement.z) + PADDING); + pos.z += 1 ) { action.accept(pos); } } } - + Vectors.release(origin); Vectors.release(size); Vectors.release(pos); diff --git a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java index ab5e766..6f5ec24 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/CompoundCollisionModel.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import java.util.Collection; @@ -7,17 +25,17 @@ import com.google.common.collect.ImmutableList; import glm.vec._3.Vec3; public class CompoundCollisionModel implements CollisionModel { - + private final Collection models; public CompoundCollisionModel(Collection models) { this.models = models; } - + public CompoundCollisionModel(CollisionModel... models) { this(ImmutableList.copyOf(models)); } - + public Collection getModels() { return models; } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java b/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java index 13681b0..96bfbee 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TransformedCollisionModel.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import java.util.function.Consumer; @@ -8,27 +26,27 @@ import ru.windcorp.progressia.common.util.VectorUtil; import ru.windcorp.progressia.common.util.Vectors; public class TransformedCollisionModel implements CollisionModel { - + private final CollisionModel parent; - + private final Mat4 transform = new Mat4(); private final Mat4 inverseTransform = new Mat4(); - + public TransformedCollisionModel(CollisionModel parent, Mat4 transform) { this.parent = parent; setTransform(transform); } - + public TransformedCollisionModel(CollisionModel parent, Consumer transform) { this.parent = parent; transform.accept(this.transform); this.inverseTransform.set(this.transform).inverse(); } - + public Mat4 getTransform() { return transform; } - + public void setTransform(Mat4 newTransform) { this.transform.set(newTransform); this.inverseTransform.set(newTransform).inverse(); diff --git a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java index a22c330..4c33ad2 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/TranslatedAABB.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; @@ -5,10 +23,10 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockFace; public class TranslatedAABB implements AABBoid { - + private class TranslatedAABBWall implements Wall { private final int id; - + public TranslatedAABBWall(int id) { this.id = id; } @@ -18,38 +36,38 @@ public class TranslatedAABB implements AABBoid { parent.getWall(id).getOrigin(output); output.add(translation); } - + @Override public void getWidth(Vec3 output) { parent.getWall(id).getWidth(output); } - + @Override public void getHeight(Vec3 output) { parent.getWall(id).getHeight(output); } } - + private AABBoid parent; private final Vec3 translation = new Vec3(); - + private final TranslatedAABBWall[] walls = new TranslatedAABBWall[BlockFace.BLOCK_FACE_COUNT]; - + { for (int id = 0; id < walls.length; ++id) { walls[id] = new TranslatedAABBWall(id); } } - + public TranslatedAABB(AABBoid parent, float tx, float ty, float tz) { setParent(parent); setTranslation(tx, ty, tz); } - + public TranslatedAABB(AABBoid parent, Vec3 translation) { this(parent, translation.x, translation.y, translation.z); } - + public TranslatedAABB() { this(null, 0, 0, 0); } @@ -81,23 +99,23 @@ public class TranslatedAABB implements AABBoid { public Wall getWall(int faceId) { return walls[faceId]; } - + public AABBoid getParent() { return parent; } - + public void setParent(AABBoid parent) { this.parent = parent; } - + public Vec3 getTranslation() { return translation; } - + public void setTranslation(Vec3 translation) { setTranslation(translation.x, translation.y, translation.z); } - + public void setTranslation(float tx, float ty, float tz) { this.translation.set(tx, ty, tz); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/Wall.java b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java index 9549f04..91ca006 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/Wall.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/Wall.java @@ -1,12 +1,31 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import glm.vec._3.Vec3; public interface Wall { - + void getOrigin(Vec3 output); - + void getWidth(Vec3 output); + void getHeight(Vec3 output); } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java index ebf2c0b..69d2d4a 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/WorldCollisionHelper.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision; import java.util.ArrayList; @@ -9,63 +27,68 @@ import ru.windcorp.progressia.common.util.LowOverheadCache; import ru.windcorp.progressia.common.world.WorldData; public class WorldCollisionHelper { - + private final Collideable collideable = new Collideable() { @Override public boolean onCollision(Collideable other) { return false; } - + @Override public void moveAsCollideable(Vec3 displacement) { // Ignore assert displacement.length() < 1e-3f; } - + @Override public CollisionModel getCollisionModel() { return WorldCollisionHelper.this.model; } - + @Override public float getCollisionMass() { return Float.POSITIVE_INFINITY; } - + @Override public void getCollideableVelocity(Vec3 output) { output.set(0); } - + @Override public void changeVelocityOnCollision(Vec3 velocityChange) { // Ignore assert velocityChange.length() < 1e-3f; } }; - + private final Collection activeBlockModels = new ArrayList<>(); private final CollisionModel model = new CompoundCollisionModel(activeBlockModels); private final LowOverheadCache blockModelCache = new LowOverheadCache<>(TranslatedAABB::new); - + /** - * Changes the state of this helper's {@link #getCollideable()} so it is ready to adequately handle - * collisions with the {@code collideable} that might happen in the next {@code maxTime} seconds. - * This helper is only valid for checking collisions with the given Collideable and only within + * Changes the state of this helper's {@link #getCollideable()} so it is + * ready to adequately handle + * collisions with the {@code collideable} that might happen in the next + * {@code maxTime} seconds. + * This helper is only valid for checking collisions with the given + * Collideable and only within * the given time limit. - * @param collideable the {@link Collideable} that collisions will be checked against - * @param maxTime maximum collision time + * + * @param collideable the {@link Collideable} that collisions will be + * checked against + * @param maxTime maximum collision time */ public void tuneToCollideable(WorldData world, Collideable collideable, float maxTime) { activeBlockModels.forEach(blockModelCache::release); activeBlockModels.clear(); CollisionPathComputer.forEveryBlockInCollisionPath( - collideable, - maxTime, - v -> addModel(world.getCollisionModelOfBlock(v), v) + collideable, + maxTime, + v -> addModel(world.getCollisionModelOfBlock(v), v) ); } - + private void addModel(CollisionModel model, Vec3i pos) { if (model == null) { // Ignore @@ -79,7 +102,7 @@ public class WorldCollisionHelper { throw new RuntimeException("not supported"); } } - + private void addAABBoidModel(AABBoid model, Vec3i pos) { TranslatedAABB translator = blockModelCache.grab(); translator.setParent(model); diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java index f440761..5fab3d8 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AABBoidCollider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision.colliders; import glm.mat._3.Mat3; @@ -10,72 +28,77 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.block.BlockFace; class AABBoidCollider { - + static Collider.Collision computeModelCollision( - Collideable aBody, Collideable bBody, - AABBoid aModel, AABBoid bModel, - float tickLength, - ColliderWorkspace workspace + Collideable aBody, + Collideable bBody, + AABBoid aModel, + AABBoid bModel, + float tickLength, + ColliderWorkspace workspace ) { Collideable obstacleBody = bBody; Collideable colliderBody = aBody; AABBoid obstacleModel = bModel; AABBoid colliderModel = aModel; - + Collision result = null; - - AABB originCollisionSpace = - createOriginCollisionSpace(obstacleModel, colliderModel, workspace.dummyAABB); - + + AABB originCollisionSpace = createOriginCollisionSpace(obstacleModel, colliderModel, workspace.dummyAABB); + Vec3 collisionVelocity = Vectors.grab3(); computeCollisionVelocity(collisionVelocity, obstacleBody, colliderBody); - + // For every wall of collision space for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { Wall wall = originCollisionSpace.getWall(i); - + Collision collision = computeWallCollision( - wall, colliderModel, - collisionVelocity, - tickLength, workspace, - aBody, bBody + wall, + colliderModel, + collisionVelocity, + tickLength, + workspace, + aBody, + bBody ); - + // Update result if (collision != null) { Collision second; - + if (result == null || collision.time < result.time) { second = result; result = collision; } else { second = collision; } - + // Release Collision that is no longer used - if (second != null) workspace.release(second); + if (second != null) + workspace.release(second); } - + } - + Vectors.release(collisionVelocity); - + return result; } - + private static void computeCollisionVelocity( - Vec3 output, - Collideable obstacleBody, - Collideable colliderBody + Vec3 output, + Collideable obstacleBody, + Collideable colliderBody ) { Vec3 obstacleVelocity = Vectors.grab3(); Vec3 colliderVelocity = Vectors.grab3(); - + obstacleBody.getCollideableVelocity(obstacleVelocity); colliderBody.getCollideableVelocity(colliderVelocity); - + output.set(colliderVelocity).sub(obstacleVelocity); - + Vectors.release(obstacleVelocity); Vectors.release(colliderVelocity); } @@ -84,70 +107,69 @@ class AABBoidCollider { Vec3 obstacleOrigin = Vectors.grab3(); Vec3 obstacleSize = Vectors.grab3(); Vec3 colliderSize = Vectors.grab3(); - + obstacle.getOrigin(obstacleOrigin); output.setOrigin(obstacleOrigin); - + obstacle.getSize(obstacleSize); collider.getSize(colliderSize); output.setSize(obstacleSize.add(colliderSize)); - + Vectors.release(obstacleOrigin); Vectors.release(obstacleSize); Vectors.release(colliderSize); - + return output; } /* - * Here we determine whether a collision has actually happened, and if it did, at what moment. - * - * The basic idea is to compute the moment of collision and impact coordinates in wall coordinate space. - * Then, we can check impact coordinates to determine if we actually hit the wall or flew by and then - * check time to make sure the collision is not too far in the future and not in the past. - * + * Here we determine whether a collision has actually happened, and if it + * did, at what moment. + * The basic idea is to compute the moment of collision and impact + * coordinates in wall coordinate space. + * Then, we can check impact coordinates to determine if we actually hit the + * wall or flew by and then + * check time to make sure the collision is not too far in the future and + * not in the past. * DETAILED EXPLANATION: - * - * Consider a surface defined by an origin r_wall and two noncollinear nonzero vectors w and h. + * Consider a surface defined by an origin r_wall and two noncollinear + * nonzero vectors w and h. * Consider a line defined by an origin r_line and a nonzero vector v. - * * Then, a collision occurs if there exist x, y and t such that - * ______ _ - * r_line + v * t - * + * ______ _ + * r_line + v * t * and - * ______ _ _ - * r_wall + w * x + h * y - * - * describe the same location (indeed, this corresponds to a collision at moment t0 + t - * with a point on the wall with coordinates (x; y) in (w; h) coordinate system). - * + * ______ _ _ + * r_wall + w * x + h * y + * describe the same location (indeed, this corresponds to a collision at + * moment t0 + t + * with a point on the wall with coordinates (x; y) in (w; h) coordinate + * system). * Therefore, - * ______ _ ______ _ _ - * r_line + v*t = r_wall + w*x + h*y; - * - * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ - * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; - * ⎣w_z h_z -v_z⎦ ⎣t⎦ - * - * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ - * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. - * ⎣t⎦ ⎣w_z h_z -v_z⎦ - * + * ______ _ ______ _ _ + * r_line + v*t = r_wall + w*x + h*y; + * _ ⎡w_x h_x -v_x⎤ ⎡x⎤ _ ______ ______ + * r = ⎢w_y h_y -v_y⎥ * ⎢y⎥, where r = r_line - r_wall; + * ⎣w_z h_z -v_z⎦ ⎣t⎦ + * ⎡x⎤ ⎡w_x h_x -v_x⎤ -1 _ + * ⎢y⎥ = ⎢w_y h_y -v_y⎥ * r, if the matrix is invertible. + * ⎣t⎦ ⎣w_z h_z -v_z⎦ * Then, one only needs to ensure that: - * 0 < x < 1, - * 0 < y < 1, and - * 0 < t < T, where T is remaining tick time. - * - * If the matrix is not invertible or any of the conditions are not met, no collision happened. + * 0 < x < 1, + * 0 < y < 1, and + * 0 < t < T, where T is remaining tick time. + * If the matrix is not invertible or any of the conditions are not met, no + * collision happened. * If all conditions are satisfied, then the moment of impact is t0 + t. */ private static Collision computeWallCollision( - Wall obstacleWall, - AABBoid colliderModel, - Vec3 collisionVelocity, - float tickLength, ColliderWorkspace workspace, - Collideable aBody, Collideable bBody + Wall obstacleWall, + AABBoid colliderModel, + Vec3 collisionVelocity, + float tickLength, + ColliderWorkspace workspace, + Collideable aBody, + Collideable bBody ) { Vec3 w = Vectors.grab3(); Vec3 h = Vectors.grab3(); @@ -157,42 +179,42 @@ class AABBoidCollider { Vec3 r_line = Vectors.grab3(); Vec3 r_wall = Vectors.grab3(); Vec3 xyt = Vectors.grab3(); - + try { obstacleWall.getWidth(w); obstacleWall.getHeight(h); - + v.set(collisionVelocity); - + if (isExiting(v, w, h)) { return null; } - + obstacleWall.getOrigin(r_wall); colliderModel.getOrigin(r_line); r.set(r_line).sub(r_wall); m.c0(w).c1(h).c2(v.negate()); - + if (Math.abs(m.det()) < 1e-6) { return null; } - + m.inverse().mul(r, xyt); - + float x = xyt.x; float y = xyt.y; float t = xyt.z; - + if (x <= 0 || x >= 1 || y <= 0 || y >= 1) { // We're missing the wall return null; } - + if (t < 0 || t > tickLength) { // We're colliding at the wrong moment return null; } - + return workspace.grab().set(aBody, bBody, obstacleWall, t); } finally { Vectors.release(w); @@ -213,6 +235,7 @@ class AABBoidCollider { return result; } - private AABBoidCollider() {} + private AABBoidCollider() { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java index 5efcb00..559de13 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/AnythingWithCompoundCollider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision.colliders; import ru.windcorp.progressia.common.collision.Collideable; @@ -7,40 +25,46 @@ import ru.windcorp.progressia.common.collision.colliders.Collider.ColliderWorksp import ru.windcorp.progressia.common.collision.colliders.Collider.Collision; class AnythingWithCompoundCollider { - + static Collider.Collision computeModelCollision( - Collideable aBody, Collideable bBody, - CompoundCollisionModel aModel, CollisionModel bModel, - float tickLength, - ColliderWorkspace workspace + Collideable aBody, + Collideable bBody, + CompoundCollisionModel aModel, + CollisionModel bModel, + float tickLength, + ColliderWorkspace workspace ) { Collision result = null; - + for (CollisionModel aModelPart : aModel.getModels()) { - + Collision collision = Collider.getCollision( - aBody, bBody, - aModelPart, bModel, - tickLength, workspace + aBody, + bBody, + aModelPart, + bModel, + tickLength, + workspace ); - + // Update result if (collision != null) { Collision second; - + if (result == null || collision.time < result.time) { second = result; result = collision; } else { second = collision; } - + // Release Collision that is no longer used - if (second != null) workspace.release(second); + if (second != null) + workspace.release(second); } - + } - + return result; } diff --git a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java index f6372ee..56bc8ad 100644 --- a/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java +++ b/src/main/java/ru/windcorp/progressia/common/collision/colliders/Collider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.collision.colliders; import java.util.Collection; @@ -12,236 +30,247 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.WorldData; public class Collider { - + private static final int MAX_COLLISIONS_PER_ENTITY = 64; - + /** * Dear Princess Celestia, *

- * When {@linkplain #advanceTime(Collection, Collision, WorldData, float) advancing time}, - * time step for all entities except currently colliding bodies is the current - * collisions's timestamp relative to now. However, currently colliding bodies - * (Collision.a and Collision.b) have a smaller time step. This is done to make sure + * When {@linkplain #advanceTime(Collection, Collision, WorldData, float) + * advancing time}, + * time step for all entities except currently colliding bodies is + * the current + * collisions's timestamp relative to now. However, currently colliding + * bodies + * (Collision.a and Collision.b) have a smaller time step. This is done to + * make sure * they don't intersect due to rounding errors. *

- * Today I learned that bad code has nothing to do with friendship, although lemme tell ya: + * Today I learned that bad code has nothing to do with friendship, although + * lemme tell ya: * it's got some dank magic. *

* Your faithful student,
* Kostyl. */ - private static final float TIME_STEP_COEFFICIENT_FOR_CURRENTLY_COLLIDING_BODIES = 1f/*1e-1f*/; - + private static final float TIME_STEP_COEFFICIENT_FOR_CURRENTLY_COLLIDING_BODIES = 1f/* + * 1e + * - + * 1f + */; + public static void performCollisions( - List colls, - WorldData world, - float tickLength, - ColliderWorkspace workspace + List colls, + WorldData world, + float tickLength, + ColliderWorkspace workspace ) { int collisionCount = 0; int maxCollisions = colls.size() * MAX_COLLISIONS_PER_ENTITY; - + while (true) { if (collisionCount > maxCollisions) { LogManager.getLogger().warn( - "Attempted to handle more than {} collisions", - maxCollisions + "Attempted to handle more than {} collisions", + maxCollisions ); return; } - + Collision firstCollision = getFirstCollision(colls, tickLength, world, workspace); - + if (firstCollision == null) { break; } else { collide(firstCollision, colls, world, tickLength, workspace); workspace.release(firstCollision); collisionCount++; - + tickLength -= firstCollision.time; } } - + advanceTime(colls, null, world, tickLength); } private static Collision getFirstCollision( - List colls, - float tickLength, - WorldData world, - ColliderWorkspace workspace + List colls, + float tickLength, + WorldData world, + ColliderWorkspace workspace ) { Collision result = null; Collideable worldColl = workspace.worldCollisionHelper.getCollideable(); - + // For every pair of colls for (int i = 0; i < colls.size(); ++i) { Collideable a = colls.get(i); - + tuneWorldCollisionHelper(a, tickLength, world, workspace); - + result = workspace.updateLatestCollision( - result, - getCollision(a, worldColl, tickLength, workspace) + result, + getCollision(a, worldColl, tickLength, workspace) ); - + for (int j = i + 1; j < colls.size(); ++j) { Collideable b = colls.get(j); Collision collision = getCollision(a, b, tickLength, workspace); result = workspace.updateLatestCollision(result, collision); } } - + return result; } - + private static void tuneWorldCollisionHelper( - Collideable coll, - float tickLength, - WorldData world, - ColliderWorkspace workspace + Collideable coll, + float tickLength, + WorldData world, + ColliderWorkspace workspace ) { WorldCollisionHelper wch = workspace.worldCollisionHelper; wch.tuneToCollideable(world, coll, tickLength); } static Collision getCollision( - Collideable a, - Collideable b, - float tickLength, - ColliderWorkspace workspace + Collideable a, + Collideable b, + float tickLength, + ColliderWorkspace workspace ) { CollisionModel aModel = a.getCollisionModel(); CollisionModel bModel = b.getCollisionModel(); return getCollision(a, b, aModel, bModel, tickLength, workspace); } - + static Collision getCollision( - Collideable aBody, - Collideable bBody, - CollisionModel aModel, - CollisionModel bModel, - float tickLength, - ColliderWorkspace workspace + Collideable aBody, + Collideable bBody, + CollisionModel aModel, + CollisionModel bModel, + float tickLength, + ColliderWorkspace workspace ) { if (aModel instanceof AABBoid && bModel instanceof AABBoid) { return AABBoidCollider.computeModelCollision( - aBody, bBody, - (AABBoid) aModel, (AABBoid) bModel, - tickLength, - workspace + aBody, + bBody, + (AABBoid) aModel, + (AABBoid) bModel, + tickLength, + workspace ); } - + if (aModel instanceof CompoundCollisionModel) { return AnythingWithCompoundCollider.computeModelCollision( - aBody, bBody, - (CompoundCollisionModel) aModel, bModel, - tickLength, - workspace + aBody, + bBody, + (CompoundCollisionModel) aModel, + bModel, + tickLength, + workspace ); } - + if (bModel instanceof CompoundCollisionModel) { return AnythingWithCompoundCollider.computeModelCollision( - bBody, aBody, - (CompoundCollisionModel) bModel, aModel, - tickLength, - workspace + bBody, + aBody, + (CompoundCollisionModel) bModel, + aModel, + tickLength, + workspace ); } - + throw new UnsupportedOperationException( - "Collisions between " + aModel + " and " + bModel + " are not yet implemented" + "Collisions between " + aModel + " and " + bModel + " are not yet implemented" ); } private static void collide( - Collision collision, - - Collection colls, - WorldData world, - float tickLength, - ColliderWorkspace workspace + Collision collision, + + Collection colls, + WorldData world, + float tickLength, + ColliderWorkspace workspace ) { advanceTime(colls, collision, world, collision.time); - + boolean doNotHandle = false; - + doNotHandle |= collision.a.onCollision(collision.b); doNotHandle |= collision.b.onCollision(collision.a); - + if (doNotHandle) { return; } - + handlePhysics(collision); } /* * Here we compute the change in body velocities due to a collision. - * * We make the following simplifications: - * 1) The bodies are perfectly rigid; - * 2) The collision is perfectly inelastic - * (no bouncing); - * 3) The bodies are spherical; - * 4) No tangential friction exists - * (bodies do not experience friction when sliding against each other); - * 5) Velocities are not relativistic. - * + * 1) The bodies are perfectly rigid; + * 2) The collision is perfectly inelastic + * (no bouncing); + * 3) The bodies are spherical; + * 4) No tangential friction exists + * (bodies do not experience friction when sliding against each other); + * 5) Velocities are not relativistic. * Angular momentum is ignored per 3) and 4), - * e.g. when something pushes an end of a long stick, the stick does not rotate. - * + * e.g. when something pushes an end of a long stick, the stick does not + * rotate. * DETAILED EXPLANATION: - * - * Two spherical (sic) bodies, a and b, experience a perfectly inelastic collision + * Two spherical (sic) bodies, a and b, experience a perfectly inelastic + * collision * along a unit vector - * _ _ _ _ _ - * n = (w ⨯ h) / (|w ⨯ h|), - * _ _ + * _ _ _ _ _ + * n = (w ⨯ h) / (|w ⨯ h|), + * _ _ * where w and h are two noncollinear nonzero vectors on the dividing plane. - * ___ ___ + * ___ ___ * Body masses and velocities are M_a, M_b and v_a, v_b, respectively. - * ___ ___ + * ___ ___ * After the collision desired velocities are u_a and u_b, respectively. - * _ - * (Notation convention: suffix 'n' denotes a vector projection onto vector n, + * _ + * (Notation convention: suffix 'n' denotes a vector projection onto vector + * n, * and suffix 't' denotes a vector projection onto the dividing plane.) - * - * Consider the law of conservation of momentum for axis n and the dividing plane: - * ____________ ____________ ________________ - * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; - * ⎨ ___________ ____________ - * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. - * + * Consider the law of conservation of momentum for axis n and the dividing + * plane: + * ____________ ____________ ________________ + * n: ⎧ p_a_before_n + p_b_before_n = p_common_after_n; + * ⎨ ___________ ____________ + * t: ⎩ p_i_after_t = p_i_before_t for any i in {a, b}. * Expressing all p_* in given terms: - * ___ _ ___ _ ___ ___ ____ ____ - * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ u_an = u_bn; - * ⎨ ____ ___ _ ___ _ - * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. - * + * ___ _ ___ _ ___ ___ ____ ____ + * n: ⎧ M_a * (v_a ⋅ n) + M_b * (v_b ⋅ n) = (M_a + M_b) * u_n, where u_n ≡ + * u_an = u_bn; + * ⎨ ____ ___ _ ___ _ + * t: ⎩ u_it = v_i - n * (v_i ⋅ n) for any i in {a, b}. * Therefore: - * ___ _ ___ _ ___ _ - * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); - * + * ___ _ ___ _ ___ _ + * u_n = n * ( M_a/(M_a + M_b) * v_a ⋅ n + M_b/(M_a + M_b) * v_b ⋅ n ); * or, equivalently, - * ___ _ ___ _ ___ _ - * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), - * + * ___ _ ___ _ ___ _ + * u_n = n * ( m_a * v_a ⋅ n + m_b * v_b ⋅ n ), * where m_a and m_b are relative masses (see below). - * * Finally, - * ___ ____ ___ - * u_i = u_it + u_n for any i in {a, b}. - * - * The usage of relative masses m_i permits a convenient generalization of the algorithm - * for infinite masses, signifying masses "significantly greater" than finite masses: - * - * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i in {a, b}. - * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. - * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. + * ___ ____ ___ + * u_i = u_it + u_n for any i in {a, b}. + * The usage of relative masses m_i permits a convenient generalization of + * the algorithm + * for infinite masses, signifying masses "significantly greater" than + * finite masses: + * 1) If both M_a and M_b are finite, let m_i = M_i / (M_a + M_b) for any i + * in {a, b}. + * 2) If M_i is finite but M_j is infinite, let m_i = 0 and m_j = 1. + * 3) If both M_a and M_b are infinite, let m_i = 1/2 for any i in {a, b}. */ private static void handlePhysics(Collision collision) { // Fuck JGLM @@ -253,16 +282,16 @@ public class Collider { Vec3 u_bt = Vectors.grab3(); Vec3 du_a = Vectors.grab3(); Vec3 du_b = Vectors.grab3(); - + n.set(collision.wallWidth).cross(collision.wallHeight).normalize(); collision.a.getCollideableVelocity(v_a); collision.b.getCollideableVelocity(v_b); - + float M_a = collision.a.getCollisionMass(); float M_b = collision.b.getCollisionMass(); - + float m_a, m_b; - + if (Float.isFinite(M_a)) { if (Float.isFinite(M_b)) { float sum = M_a + M_b; @@ -281,18 +310,18 @@ public class Collider { m_b = 0.5f; } } - + u_n.set(n).mul(m_a * Vec3.dot(v_a, n) + m_b * Vec3.dot(v_b, n)); u_at.set(n).mul(Vec3.dot(v_a, n)).negate().add(v_a); u_bt.set(n).mul(Vec3.dot(v_b, n)).negate().add(v_b); du_a.set(u_n).add(u_at).sub(v_a); du_b.set(u_n).add(u_bt).sub(v_b); - + collision.a.changeVelocityOnCollision(du_a); collision.b.changeVelocityOnCollision(du_b); - + separate(collision, n, m_a, m_b); - + // JGML is still to fuck Vectors.release(n); Vectors.release(v_a); @@ -303,10 +332,12 @@ public class Collider { Vectors.release(du_a); Vectors.release(du_b); } - + private static void separate( - Collision collision, - Vec3 normal, float aRelativeMass, float bRelativeMass + Collision collision, + Vec3 normal, + float aRelativeMass, + float bRelativeMass ) { final float margin = 1e-4f; @@ -322,38 +353,37 @@ public class Collider { } private static void advanceTime( - Collection colls, - Collision exceptions, - WorldData world, - float step + Collection colls, + Collision exceptions, + WorldData world, + float step ) { world.advanceTime(step); - + Vec3 tmp = Vectors.grab3(); - + for (Collideable coll : colls) { coll.getCollideableVelocity(tmp); - + float currentStep = step; - + if (exceptions != null && (exceptions.a == coll || exceptions.b == coll)) { currentStep *= TIME_STEP_COEFFICIENT_FOR_CURRENTLY_COLLIDING_BODIES; } - + tmp.mul(currentStep); coll.moveAsCollideable(tmp); } - + Vectors.release(tmp); } public static class ColliderWorkspace { - - private final LowOverheadCache collisionCache = - new LowOverheadCache<>(Collision::new); - + + private final LowOverheadCache collisionCache = new LowOverheadCache<>(Collision::new); + AABB dummyAABB = new AABB(0, 0, 0, 1, 1, 1); - + WorldCollisionHelper worldCollisionHelper = new WorldCollisionHelper(); Collision grab() { @@ -363,16 +393,16 @@ public class Collider { void release(Collision object) { collisionCache.release(object); } - + Collision updateLatestCollision(Collision a, Collision b) { if (a == null) { return b; // may be null } else if (b == null) { return a; } - + Collision first, second; - + if (a.time > b.time) { first = b; second = a; @@ -380,41 +410,43 @@ public class Collider { first = a; second = b; } - + release(second); return first; } - + } - + static class Collision { public Collideable a; public Collideable b; - + public final Vec3 wallWidth = new Vec3(); public final Vec3 wallHeight = new Vec3(); - + /** * Time offset from the start of the tick. * 0 means right now, tickLength means at the end of the tick. */ public float time; - + public Collision set( - Collideable a, Collideable b, - Wall wall, - float time + Collideable a, + Collideable b, + Wall wall, + float time ) { this.a = a; this.b = b; wall.getWidth(wallWidth); wall.getHeight(wallHeight); this.time = time; - + return this; } } - - private Collider() {} + + private Collider() { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java b/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java index 4b51eff..288b5dd 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/CommsChannel.java @@ -1,115 +1,133 @@ -package ru.windcorp.progressia.common.comms; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - -import ru.windcorp.progressia.common.comms.packets.Packet; - -public abstract class CommsChannel { - - public static enum State { - /** - * Client is currently establishing connection. - */ - CONNECTING, - - /** - * Client is ready to receive and send packets. - */ - CONNECTED, - - /** - * Client is being disconnected. - */ - DISCONNECTING, - - /** - * Communication is not possible. The client may have been disconnected - * after connecting or may have never connected. - */ - DISCONNECTED - } - - private State state = State.CONNECTING; - - private final Collection listeners = - Collections.synchronizedCollection(new ArrayList<>()); - - protected abstract void doSendPacket(Packet packet) throws IOException; - - private synchronized void sendPacket( - Packet packet, - State expectedState, String errorMessage - ) { - if (getState() != expectedState) { - throw new IllegalStateException( - String.format(errorMessage, this, getState()) - ); - } - - try { - doSendPacket(packet); - } catch (IOException e) { - onIOError(e, "Could not send packet"); - } - } - - public synchronized void sendPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTED, - "Client %s is in state %s and cannot receive packets normally" - ); - } - - public synchronized void sendConnectingPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTING, - "Client %s is in state %s and is no longer connecting" - ); - } - - public synchronized void sendDisconnectingPacket(Packet packet) { - sendPacket( - packet, - State.CONNECTING, - "Client %s is in state %s and is no longer disconnecting" - ); - } - - public abstract void disconnect(); - - protected void onPacketReceived(Packet packet) { - listeners.forEach(l -> l.onPacketReceived(packet)); - } - - public void addListener(CommsListener listener) { - listeners.add(listener); - } - - public void removeListener(CommsListener listener) { - listeners.remove(listener); - } - - protected void onIOError(IOException e, String string) { - // TODO implement - e.printStackTrace(); - listeners.forEach(l -> l.onIOError(e)); - } - - public synchronized State getState() { - return state; - } - - public boolean isReady() { - return getState() == State.CONNECTED; - } - - public synchronized void setState(State state) { - this.state = state; - } - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import ru.windcorp.progressia.common.comms.packets.Packet; + +public abstract class CommsChannel { + + public static enum State { + /** + * Client is currently establishing connection. + */ + CONNECTING, + + /** + * Client is ready to receive and send packets. + */ + CONNECTED, + + /** + * Client is being disconnected. + */ + DISCONNECTING, + + /** + * Communication is not possible. The client may have been disconnected + * after connecting or may have never connected. + */ + DISCONNECTED + } + + private State state = State.CONNECTING; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + protected abstract void doSendPacket(Packet packet) throws IOException; + + private synchronized void sendPacket( + Packet packet, + State expectedState, + String errorMessage + ) { + if (getState() != expectedState) { + throw new IllegalStateException( + String.format(errorMessage, this, getState()) + ); + } + + try { + doSendPacket(packet); + } catch (IOException e) { + onIOError(e, "Could not send packet"); + } + } + + public synchronized void sendPacket(Packet packet) { + sendPacket( + packet, + State.CONNECTED, + "Client %s is in state %s and cannot receive packets normally" + ); + } + + public synchronized void sendConnectingPacket(Packet packet) { + sendPacket( + packet, + State.CONNECTING, + "Client %s is in state %s and is no longer connecting" + ); + } + + public synchronized void sendDisconnectingPacket(Packet packet) { + sendPacket( + packet, + State.CONNECTING, + "Client %s is in state %s and is no longer disconnecting" + ); + } + + public abstract void disconnect(); + + protected void onPacketReceived(Packet packet) { + listeners.forEach(l -> l.onPacketReceived(packet)); + } + + public void addListener(CommsListener listener) { + listeners.add(listener); + } + + public void removeListener(CommsListener listener) { + listeners.remove(listener); + } + + protected void onIOError(IOException e, String string) { + // TODO implement + e.printStackTrace(); + listeners.forEach(l -> l.onIOError(e)); + } + + public synchronized State getState() { + return state; + } + + public boolean isReady() { + return getState() == State.CONNECTED; + } + + public synchronized void setState(State state) { + this.state = state; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java b/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java index 5ad2c72..7445e93 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/CommsListener.java @@ -1,13 +1,31 @@ -package ru.windcorp.progressia.common.comms; - -import java.io.IOException; - -import ru.windcorp.progressia.common.comms.packets.Packet; - -public interface CommsListener { - - void onPacketReceived(Packet packet); - - void onIOError(IOException reason); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms; + +import java.io.IOException; + +import ru.windcorp.progressia.common.comms.packets.Packet; + +public interface CommsListener { + + void onPacketReceived(Packet packet); + + void onIOError(IOException reason); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java index 0f27553..46e4e94 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlData.java @@ -1,11 +1,29 @@ -package ru.windcorp.progressia.common.comms.controls; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; - -public class ControlData extends Namespaced { - - public ControlData(String id) { - super(id); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms.controls; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +public class ControlData extends Namespaced { + + public ControlData(String id) { + super(id); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java index 5e38b90..cd884e8 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/ControlDataRegistry.java @@ -1,13 +1,31 @@ -package ru.windcorp.progressia.common.comms.controls; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; - -public class ControlDataRegistry extends NamespacedFactoryRegistry { - - private static final ControlDataRegistry INSTANCE = new ControlDataRegistry(); - - public static ControlDataRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms.controls; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedFactoryRegistry; + +public class ControlDataRegistry extends NamespacedFactoryRegistry { + + private static final ControlDataRegistry INSTANCE = new ControlDataRegistry(); + + public static ControlDataRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java b/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java index 98448be..d5abd39 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/controls/PacketControl.java @@ -1,33 +1,51 @@ -package ru.windcorp.progressia.common.comms.controls; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.common.world.DecodingException; - -public class PacketControl extends Packet { - - private final ControlData control; - - public PacketControl(String id, ControlData control) { - super(id); - this.control = control; - } - - public ControlData getControl() { - return control; - } - - @Override - public void read(DataInput input) throws IOException, DecodingException { - // TODO implement controls - } - - @Override - public void write(DataOutput output) throws IOException { - // implement controls - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms.controls; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.common.world.DecodingException; + +public class PacketControl extends Packet { + + private final ControlData control; + + public PacketControl(String id, ControlData control) { + super(id); + this.control = control; + } + + public ControlData getControl() { + return control; + } + + @Override + public void read(DataInput input) throws IOException, DecodingException { + // TODO implement controls + } + + @Override + public void write(DataOutput output) throws IOException { + // implement controls + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java b/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java index 941b157..5421028 100644 --- a/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java +++ b/src/main/java/ru/windcorp/progressia/common/comms/packets/Packet.java @@ -1,19 +1,38 @@ -package ru.windcorp.progressia.common.comms.packets; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.DecodingException; - -public abstract class Packet extends Namespaced { - - public Packet(String id) { - super(id); - } - - public abstract void read(DataInput input) throws IOException, DecodingException; - public abstract void write(DataOutput output) throws IOException; - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.comms.packets; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.DecodingException; + +public abstract class Packet extends Namespaced { + + public Packet(String id) { + super(id); + } + + public abstract void read(DataInput input) throws IOException, DecodingException; + + public abstract void write(DataOutput output) throws IOException; + +} diff --git a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java index 48ffade..6bc7901 100644 --- a/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java +++ b/src/main/java/ru/windcorp/progressia/common/hacks/GuavaEventBusHijacker.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.hacks; import java.lang.reflect.Constructor; @@ -11,45 +29,54 @@ import com.google.common.util.concurrent.MoreExecutors; import ru.windcorp.progressia.common.util.crash.CrashReports; /** - * This class had to be written because there is not legal way to instantiate a non-async - * {@link EventBus} with both a custom identifier and a custom exception handler. Which - * is a shame. Guava maintainers know about the issue but have rejected solutions multiple - * times without a clearly stated reason; looks like some dirty reflection will + * This class had to be written because there is not legal way to instantiate a + * non-async + * {@link EventBus} with both a custom identifier and a custom exception + * handler. Which + * is a shame. Guava maintainers know about the issue but have rejected + * solutions multiple + * times without a clearly stated reason; looks like some dirty + * reflection will * have to do. + * * @author javapony */ public class GuavaEventBusHijacker { public static final Constructor THE_CONSTRUCTOR; public static final Method DISPATCHER__PER_THREAD_DISPATCH_QUEUE; - + static { try { Class dispatcherClass = Class.forName("com.google.common.eventbus.Dispatcher"); - + THE_CONSTRUCTOR = EventBus.class.getDeclaredConstructor( - String.class, Executor.class, dispatcherClass, SubscriberExceptionHandler.class + String.class, + Executor.class, + dispatcherClass, + SubscriberExceptionHandler.class ); THE_CONSTRUCTOR.setAccessible(true); - + DISPATCHER__PER_THREAD_DISPATCH_QUEUE = dispatcherClass.getDeclaredMethod("perThreadDispatchQueue"); DISPATCHER__PER_THREAD_DISPATCH_QUEUE.setAccessible(true); } catch (Exception e) { - throw CrashReports.report(e, "Something went horribly wrong when setting up EventBus hijacking. Has Guava updated?"); + throw CrashReports + .report(e, "Something went horribly wrong when setting up EventBus hijacking. Has Guava updated?"); } } - + public static EventBus newEventBus(String identifier, SubscriberExceptionHandler exceptionHandler) { try { return THE_CONSTRUCTOR.newInstance( - identifier, - MoreExecutors.directExecutor(), - DISPATCHER__PER_THREAD_DISPATCH_QUEUE.invoke(null), - exceptionHandler + identifier, + MoreExecutors.directExecutor(), + DISPATCHER__PER_THREAD_DISPATCH_QUEUE.invoke(null), + exceptionHandler ); } catch (Exception e) { throw CrashReports.report(e, "Something went horribly wrong when hijacking EventBus. Has Guava updated?"); } } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java index dece4ee..90acc5b 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/Resource.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/Resource.java @@ -1,83 +1,84 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.resource; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; - -import org.lwjgl.BufferUtils; - -import com.google.common.io.ByteStreams; -import com.google.common.io.CharStreams; - -import ru.windcorp.progressia.Progressia; -import ru.windcorp.progressia.common.util.Named; -import ru.windcorp.progressia.common.util.crash.CrashReports; - -public class Resource extends Named { - - public Resource(String name) { - super(name); - } - - public InputStream getInputStream() { - // TODO Do proper resource lookup - return Progressia.class.getClassLoader().getResourceAsStream(getName()); - } - - public Reader getReader() { - return new InputStreamReader(getInputStream(), StandardCharsets.UTF_8); - } - - public String readAsString() { - try (Reader reader = getReader()) { - return CharStreams.toString(reader); - } catch (IOException e) { - throw CrashReports.report(e, "Could not read resource %s as text", this); - } - } - - public ByteBuffer readAsBytes(ByteBuffer output) { - byte[] byteArray; - try (InputStream stream = getInputStream()) { - byteArray = ByteStreams.toByteArray(stream); - } catch (IOException e) { - throw CrashReports.report(e, "Could not read resource %s as bytes", this); - } - - if (output == null || output.remaining() < byteArray.length) { - output = BufferUtils.createByteBuffer(byteArray.length); - } - - int position = output.position(); - output.put(byteArray); - output.limit(output.position()); - output.position(position); - - return output; - } - - public ByteBuffer readAsBytes() { - return readAsBytes(null); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import org.lwjgl.BufferUtils; + +import com.google.common.io.ByteStreams; +import com.google.common.io.CharStreams; + +import ru.windcorp.progressia.Progressia; +import ru.windcorp.progressia.common.util.Named; +import ru.windcorp.progressia.common.util.crash.CrashReports; + +public class Resource extends Named { + + public Resource(String name) { + super(name); + } + + public InputStream getInputStream() { + // TODO Do proper resource lookup + return Progressia.class.getClassLoader().getResourceAsStream(getName()); + } + + public Reader getReader() { + return new InputStreamReader(getInputStream(), StandardCharsets.UTF_8); + } + + public String readAsString() { + try (Reader reader = getReader()) { + return CharStreams.toString(reader); + } catch (IOException e) { + throw CrashReports.report(e, "Could not read resource %s as text", this); + } + } + + public ByteBuffer readAsBytes(ByteBuffer output) { + byte[] byteArray; + try (InputStream stream = getInputStream()) { + byteArray = ByteStreams.toByteArray(stream); + } catch (IOException e) { + throw CrashReports.report(e, "Could not read resource %s as bytes", this); + } + + if (output == null || output.remaining() < byteArray.length) { + output = BufferUtils.createByteBuffer(byteArray.length); + } + + int position = output.position(); + output.put(byteArray); + output.limit(output.position()); + output.position(position); + + return output; + } + + public ByteBuffer readAsBytes() { + return readAsBytes(null); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java index 86471b4..60b1698 100644 --- a/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java +++ b/src/main/java/ru/windcorp/progressia/common/resource/ResourceManager.java @@ -1,32 +1,34 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.resource; - -public class ResourceManager { - - public static Resource getResource(String name) { - return new Resource(name); - } - - public static Resource getTextureResource(String name) { - return getResource("assets/textures/" + name + ".png"); - } - - private ResourceManager() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.resource; + +public class ResourceManager { + + public static Resource getResource(String name) { + return new Resource(name); + } + + public static Resource getTextureResource(String name) { + return getResource("assets/textures/" + name + ".png"); + } + + private ResourceManager() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java index 3a19e04..b2feb80 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/AbstractStatefulObjectLayout.java @@ -1,83 +1,107 @@ -package ru.windcorp.progressia.common.state; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public abstract class AbstractStatefulObjectLayout -extends StatefulObjectLayout { - - public AbstractStatefulObjectLayout(String objectId) { - super(objectId); - } - - protected abstract int getFieldCount(); - protected abstract StateField getField(int fieldIndex); - - @Override - public void read( - StatefulObject object, - DataInput input, - IOContext context - ) throws IOException { - - int fieldCount = getFieldCount(); - for (int i = 0; i < fieldCount; ++i) { - - StateField field = getField(i); - if (context == IOContext.COMMS && field.isLocal()) continue; - field.read(object, input, context); - - } - } - - @Override - public void write( - StatefulObject object, - DataOutput output, - IOContext context - ) throws IOException { - - int fieldCount = getFieldCount(); - for (int i = 0; i < fieldCount; ++i) { - - StateField field = getField(i); - if (context == IOContext.COMMS && field.isLocal()) continue; - field.write(object, output, context); - - } - } - - @Override - public void copy(StatefulObject from, StatefulObject to) { - int fieldCount = getFieldCount(); - for (int i = 0; i < fieldCount; ++i) { - getField(i).copy(from, to); - } - } - - @Override - public int computeHashCode(StatefulObject object) { - int result = 1; - - int fieldCount = getFieldCount(); - for (int i = 0; i < fieldCount; ++i) { - - result = 31 * result + getField(i).computeHashCode(object); - - } - - return result; - } - - @Override - public boolean areEqual(StatefulObject a, StatefulObject b) { - int fieldCount = getFieldCount(); - for (int i = 0; i < fieldCount; ++i) { - if (!getField(i).areEqual(a, b)) return false; - } - - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public abstract class AbstractStatefulObjectLayout + extends StatefulObjectLayout { + + public AbstractStatefulObjectLayout(String objectId) { + super(objectId); + } + + protected abstract int getFieldCount(); + + protected abstract StateField getField(int fieldIndex); + + @Override + public void read( + StatefulObject object, + DataInput input, + IOContext context + ) + throws IOException { + + int fieldCount = getFieldCount(); + for (int i = 0; i < fieldCount; ++i) { + + StateField field = getField(i); + if (context == IOContext.COMMS && field.isLocal()) + continue; + field.read(object, input, context); + + } + } + + @Override + public void write( + StatefulObject object, + DataOutput output, + IOContext context + ) + throws IOException { + + int fieldCount = getFieldCount(); + for (int i = 0; i < fieldCount; ++i) { + + StateField field = getField(i); + if (context == IOContext.COMMS && field.isLocal()) + continue; + field.write(object, output, context); + + } + } + + @Override + public void copy(StatefulObject from, StatefulObject to) { + int fieldCount = getFieldCount(); + for (int i = 0; i < fieldCount; ++i) { + getField(i).copy(from, to); + } + } + + @Override + public int computeHashCode(StatefulObject object) { + int result = 1; + + int fieldCount = getFieldCount(); + for (int i = 0; i < fieldCount; ++i) { + + result = 31 * result + getField(i).computeHashCode(object); + + } + + return result; + } + + @Override + public boolean areEqual(StatefulObject a, StatefulObject b) { + int fieldCount = getFieldCount(); + for (int i = 0; i < fieldCount; ++i) { + if (!getField(i).areEqual(a, b)) + return false; + } + + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java index 2c37b23..52d446f 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/HashMapStateStorage.java @@ -1,20 +1,38 @@ -package ru.windcorp.progressia.common.state; - -import gnu.trove.map.TIntIntMap; -import gnu.trove.map.hash.TIntIntHashMap; - -public class HashMapStateStorage extends StateStorage { - - private final TIntIntMap ints = new TIntIntHashMap(); - - @Override - public int getInt(int index) { - return ints.get(index); - } - - @Override - public void setInt(int index, int value) { - ints.put(index, value); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import gnu.trove.map.TIntIntMap; +import gnu.trove.map.hash.TIntIntHashMap; + +public class HashMapStateStorage extends StateStorage { + + private final TIntIntMap ints = new TIntIntHashMap(); + + @Override + public int getInt(int index) { + return ints.get(index); + } + + @Override + public void setInt(int index, int value) { + ints.put(index, value); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/IOContext.java b/src/main/java/ru/windcorp/progressia/common/state/IOContext.java index c88759b..b18f875 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/IOContext.java +++ b/src/main/java/ru/windcorp/progressia/common/state/IOContext.java @@ -1,9 +1,27 @@ -package ru.windcorp.progressia.common.state; - -public enum IOContext { - - COMMS, - SAVE, - INTERNAL; - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +public enum IOContext { + + COMMS, + SAVE, + INTERNAL; + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java index 767c1f1..8b0a9fe 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/InspectingStatefulObjectLayout.java @@ -1,97 +1,117 @@ -package ru.windcorp.progressia.common.state; - -import java.util.ArrayList; -import java.util.List; - -public class InspectingStatefulObjectLayout -extends AbstractStatefulObjectLayout { - - private final List fields = new ArrayList<>(); - - private final PrimitiveCounters fieldIndexCounters = - new PrimitiveCounters(); - - public InspectingStatefulObjectLayout(String objectId) { - super(objectId); - } - - @Override - public StateStorage createStorage() { - return new HashMapStateStorage(); - } - - @Override - protected int getFieldCount() { - return fields.size(); - } - - @Override - protected StateField getField(int fieldIndex) { - return fields.get(fieldIndex); - } - - public StatefulObjectLayout compile() { - return new OptimizedStatefulObjectLayout( - getObjectId(), - fields, fieldIndexCounters - ); - } - - private T registerField(T field) { - fields.add(field); - return field; - } - - @Override - public StateFieldBuilder getBuilder(String id) { - return new InspectingStateFieldBuilder(id); - } - - private class InspectingStateFieldBuilder implements StateFieldBuilder { - - private class Int implements StateFieldBuilder.Int { - - @Override - public IntStateField build() { - return registerField(new IntStateField( - id, - isLocal, - fieldIndexCounters.getIntsThenIncrement() - )); - } - - } - - private final String id; - - private boolean isLocal = true; - - public InspectingStateFieldBuilder(String id) { - this.id = id; - } - - @Override - public Int ofInt() { - return new Int(); - } - - @Override - public StateFieldBuilder setLocal(boolean isLocal) { - this.isLocal = isLocal; - return this; - } - - @Override - public void setOrdinal(int ordinal) { - if (ordinal != fields.size()) { - throw new IllegalStateException( - "This field is going to receive ordinal " - + fields.size() + ", requested ordinal " - + ordinal - ); - } - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.util.ArrayList; +import java.util.List; + +public class InspectingStatefulObjectLayout + extends AbstractStatefulObjectLayout { + + private final List fields = new ArrayList<>(); + + private final PrimitiveCounters fieldIndexCounters = new PrimitiveCounters(); + + public InspectingStatefulObjectLayout(String objectId) { + super(objectId); + } + + @Override + public StateStorage createStorage() { + return new HashMapStateStorage(); + } + + @Override + protected int getFieldCount() { + return fields.size(); + } + + @Override + protected StateField getField(int fieldIndex) { + return fields.get(fieldIndex); + } + + public StatefulObjectLayout compile() { + return new OptimizedStatefulObjectLayout( + getObjectId(), + fields, + fieldIndexCounters + ); + } + + private T registerField(T field) { + fields.add(field); + return field; + } + + @Override + public StateFieldBuilder getBuilder(String id) { + return new InspectingStateFieldBuilder(id); + } + + private class InspectingStateFieldBuilder implements StateFieldBuilder { + + private class Int implements StateFieldBuilder.Int { + + @Override + public IntStateField build() { + return registerField( + new IntStateField( + id, + isLocal, + fieldIndexCounters.getIntsThenIncrement() + ) + ); + } + + } + + private final String id; + + private boolean isLocal = true; + + public InspectingStateFieldBuilder(String id) { + this.id = id; + } + + @Override + public Int ofInt() { + return new Int(); + } + + @Override + public StateFieldBuilder setLocal(boolean isLocal) { + this.isLocal = isLocal; + return this; + } + + @Override + public void setOrdinal(int ordinal) { + if (ordinal != fields.size()) { + throw new IllegalStateException( + "This field is going to receive ordinal " + + fields.size() + ", requested ordinal " + + ordinal + ); + } + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java b/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java index 3ce0165..abf8573 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java +++ b/src/main/java/ru/windcorp/progressia/common/state/IntStateField.java @@ -1,62 +1,82 @@ -package ru.windcorp.progressia.common.state; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public class IntStateField extends StateField { - - public IntStateField( - String id, - boolean isLocal, - int index - ) { - super(id, isLocal, index); - } - - public int get(StatefulObject object) { - return object.getStorage().getInt(getIndex()); - } - - public void setNow(StatefulObject object, int value) { - object.getStorage().setInt(getIndex(), value); - } - - public void set(StateChanger changer, int value) { - changer.setInt(this, value); - } - - @Override - public void read( - StatefulObject object, - DataInput input, - IOContext context - ) throws IOException { - object.getStorage().setInt(getIndex(), input.readInt()); - } - - @Override - public void write( - StatefulObject object, - DataOutput output, - IOContext context - ) throws IOException { - output.writeInt(object.getStorage().getInt(getIndex())); - } - - @Override - public void copy(StatefulObject from, StatefulObject to) { - setNow(to, get(from)); - } - - @Override - public int computeHashCode(StatefulObject object) { - return get(object); - } - - @Override - public boolean areEqual(StatefulObject a, StatefulObject b) { - return get(a) == get(b); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class IntStateField extends StateField { + + public IntStateField( + String id, + boolean isLocal, + int index + ) { + super(id, isLocal, index); + } + + public int get(StatefulObject object) { + return object.getStorage().getInt(getIndex()); + } + + public void setNow(StatefulObject object, int value) { + object.getStorage().setInt(getIndex(), value); + } + + public void set(StateChanger changer, int value) { + changer.setInt(this, value); + } + + @Override + public void read( + StatefulObject object, + DataInput input, + IOContext context + ) + throws IOException { + object.getStorage().setInt(getIndex(), input.readInt()); + } + + @Override + public void write( + StatefulObject object, + DataOutput output, + IOContext context + ) + throws IOException { + output.writeInt(object.getStorage().getInt(getIndex())); + } + + @Override + public void copy(StatefulObject from, StatefulObject to) { + setNow(to, get(from)); + } + + @Override + public int computeHashCode(StatefulObject object) { + return get(object); + } + + @Override + public boolean areEqual(StatefulObject a, StatefulObject b) { + return get(a) == get(b); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java index 234e399..478fbac 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStateStorage.java @@ -1,21 +1,39 @@ -package ru.windcorp.progressia.common.state; - -public class OptimizedStateStorage extends StateStorage { - - private final int[] ints; - - public OptimizedStateStorage(PrimitiveCounters sizes) { - this.ints = new int[sizes.getInts()]; - } - - @Override - public int getInt(int index) { - return ints[index]; - } - - @Override - public void setInt(int index, int value) { - ints[index] = value; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +public class OptimizedStateStorage extends StateStorage { + + private final int[] ints; + + public OptimizedStateStorage(PrimitiveCounters sizes) { + this.ints = new int[sizes.getInts()]; + } + + @Override + public int getInt(int index) { + return ints[index]; + } + + @Override + public void setInt(int index, int value) { + ints[index] = value; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java index 05abaec..1158ab0 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/OptimizedStatefulObjectLayout.java @@ -1,68 +1,87 @@ -package ru.windcorp.progressia.common.state; - -import java.util.List; - -import com.google.common.collect.ImmutableList; - -public class OptimizedStatefulObjectLayout -extends AbstractStatefulObjectLayout { - - private final List fields; - private final PrimitiveCounters sizes; - - public OptimizedStatefulObjectLayout( - String objectId, - List fields, PrimitiveCounters counters - ) { - super(objectId); - this.fields = ImmutableList.copyOf(fields); - this.sizes = new PrimitiveCounters(counters); - } - - @Override - protected int getFieldCount() { - return fields.size(); - } - - @Override - protected StateField getField(int fieldIndex) { - return fields.get(fieldIndex); - } - - @Override - public StateStorage createStorage() { - return new OptimizedStateStorage(sizes); - } - - @Override - public StateFieldBuilder getBuilder(String id) { - return new RetrieverStateFieldBuilder(); - } - - private class RetrieverStateFieldBuilder implements StateFieldBuilder { - - private StateField result; - - @Override - public Int ofInt() { - return new Int() { - @Override - public IntStateField build() { - return (IntStateField) result; - } - }; - } - - @Override - public StateFieldBuilder setLocal(boolean isLocal) { - return this; - } - - @Override - public void setOrdinal(int ordinal) { - this.result = fields.get(ordinal); - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.util.List; + +import com.google.common.collect.ImmutableList; + +public class OptimizedStatefulObjectLayout + extends AbstractStatefulObjectLayout { + + private final List fields; + private final PrimitiveCounters sizes; + + public OptimizedStatefulObjectLayout( + String objectId, + List fields, + PrimitiveCounters counters + ) { + super(objectId); + this.fields = ImmutableList.copyOf(fields); + this.sizes = new PrimitiveCounters(counters); + } + + @Override + protected int getFieldCount() { + return fields.size(); + } + + @Override + protected StateField getField(int fieldIndex) { + return fields.get(fieldIndex); + } + + @Override + public StateStorage createStorage() { + return new OptimizedStateStorage(sizes); + } + + @Override + public StateFieldBuilder getBuilder(String id) { + return new RetrieverStateFieldBuilder(); + } + + private class RetrieverStateFieldBuilder implements StateFieldBuilder { + + private StateField result; + + @Override + public Int ofInt() { + return new Int() { + @Override + public IntStateField build() { + return (IntStateField) result; + } + }; + } + + @Override + public StateFieldBuilder setLocal(boolean isLocal) { + return this; + } + + @Override + public void setOrdinal(int ordinal) { + this.result = fields.get(ordinal); + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java b/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java index 6331338..d3e2dbb 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java +++ b/src/main/java/ru/windcorp/progressia/common/state/PrimitiveCounters.java @@ -1,21 +1,40 @@ -package ru.windcorp.progressia.common.state; - -class PrimitiveCounters { - - private int ints = 0; - - public PrimitiveCounters() {} - - public PrimitiveCounters(PrimitiveCounters copyFrom) { - this.ints = copyFrom.ints; - } - - public int getInts() { - return ints; - } - - public int getIntsThenIncrement() { - return this.ints++; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +class PrimitiveCounters { + + private int ints = 0; + + public PrimitiveCounters() { + } + + public PrimitiveCounters(PrimitiveCounters copyFrom) { + this.ints = copyFrom.ints; + } + + public int getInts() { + return ints; + } + + public int getIntsThenIncrement() { + return this.ints++; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java b/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java index 9ef7b83..cc8cd5a 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateChanger.java @@ -1,7 +1,25 @@ -package ru.windcorp.progressia.common.state; - -public interface StateChanger { - - void setInt(IntStateField field, int value); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +public interface StateChanger { + + void setInt(IntStateField field, int value); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateField.java b/src/main/java/ru/windcorp/progressia/common/state/StateField.java index 837f661..ca88c4f 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateField.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateField.java @@ -1,50 +1,70 @@ -package ru.windcorp.progressia.common.state; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; - -public abstract class StateField extends Namespaced { - - private final boolean isLocal; - private final int index; - - public StateField( - String id, - boolean isLocal, - int index - ) { - super(id); - this.isLocal = isLocal; - this.index = index; - } - - public boolean isLocal() { - return isLocal; - } - - protected int getIndex() { - return index; - } - - public abstract void read( - StatefulObject object, - DataInput input, - IOContext context - ) throws IOException; - - public abstract void write( - StatefulObject object, - DataOutput output, - IOContext context - ) throws IOException; - - public abstract void copy(StatefulObject from, StatefulObject to); - - public abstract int computeHashCode(StatefulObject object); - - public abstract boolean areEqual(StatefulObject a, StatefulObject b); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +public abstract class StateField extends Namespaced { + + private final boolean isLocal; + private final int index; + + public StateField( + String id, + boolean isLocal, + int index + ) { + super(id); + this.isLocal = isLocal; + this.index = index; + } + + public boolean isLocal() { + return isLocal; + } + + protected int getIndex() { + return index; + } + + public abstract void read( + StatefulObject object, + DataInput input, + IOContext context + ) + throws IOException; + + public abstract void write( + StatefulObject object, + DataOutput output, + IOContext context + ) + throws IOException; + + public abstract void copy(StatefulObject from, StatefulObject to); + + public abstract int computeHashCode(StatefulObject object); + + public abstract boolean areEqual(StatefulObject a, StatefulObject b); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java b/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java index 1c8a5aa..97c7176 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateFieldBuilder.java @@ -1,24 +1,41 @@ -package ru.windcorp.progressia.common.state; - -public interface StateFieldBuilder { - - public static interface Int { - IntStateField build(); - } - - Int ofInt(); - - StateFieldBuilder setLocal(boolean isLocal); - - default StateFieldBuilder setLocal() { - return setLocal(true); - } - - default StateFieldBuilder setShared() { - return setLocal(false); - } - - void setOrdinal(int ordinal); - - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +public interface StateFieldBuilder { + + public static interface Int { + IntStateField build(); + } + + Int ofInt(); + + StateFieldBuilder setLocal(boolean isLocal); + + default StateFieldBuilder setLocal() { + return setLocal(true); + } + + default StateFieldBuilder setShared() { + return setLocal(false); + } + + void setOrdinal(int ordinal); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java b/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java index 5a134c9..2f999f0 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StateStorage.java @@ -1,9 +1,27 @@ -package ru.windcorp.progressia.common.state; - -public abstract class StateStorage { - - public abstract int getInt(int index); - - public abstract void setInt(int index, int value); - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +public abstract class StateStorage { + + public abstract int getInt(int index); + + public abstract void setInt(int index, int value); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java index 65bac14..39f5b58 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObject.java @@ -1,223 +1,242 @@ -package ru.windcorp.progressia.common.state; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Objects; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; - -/** - * An abstract class describing objects that have trackable state, - * such as blocks, tiles or entities. This class contains the declaration of - * the state mechanics - * (implementation of which is mostly delegated to - * {@link StatefulObjectLayout}). - * - *

Structure

- * - * Stateful objects are characterized by their likeness and state. - *

- * An object's likeness is the combination of the object's runtime class (as in - * {@link #getClass()}) and its ID. Objects that are "alike" share the same - * internal structure, represented by a common - * {@linkplain StatefulObjectLayout layout}. Likeness can be tested with - * {@link #isLike(Object)}. - *

- * An object's state is the combination of the values of an object's - * {@linkplain StateField state fields}. State fields are different from object - * fields as described by the Java language: not every object field is a part - * of its state, although state fields are usually implemented as object fields. - * Each state field is, in its turn, has the following characteristics: - *

    - *
  • ID, distinct from the ID of the stateful object to which it belongs. - * State field IDs are only unique within fields of one likeness.
  • - *
  • data type, which is one of Java primitive types or a compound (Object) - * type.
  • - *
- */ -public abstract class StatefulObject extends Namespaced { - - private final StatefulObjectLayout layout; - - private final StateStorage storage; - - public StatefulObject( - StatefulObjectRegistry type, - String id - ) { - super(id); - this.layout = type.getLayout(getId()); - this.storage = getLayout().createStorage(); - } - - /** - * Returns the {@link StatefulObjectLayout} describing objects that are - * {@linkplain #isLike(Object) "like"} this object. - * You probably don't need this. - * - * @return this object's field layout - */ - public StatefulObjectLayout getLayout() { - return layout; - } - - /** - * Returns a {@link StateStorage} used by this object to store its state in - * memory. You probably don't need this. - * - * @return this object's state storage - */ - public StateStorage getStorage() { - return storage; - } - - /* - * Field construction - */ - - /** - * Used to keep track of the ordinal number of the next field to be - * requested. - */ - private int fieldOrdinal = 0; - - /** - * Returns a {@link StateFieldBuilder} set up to construct a field with the - * specified ID. - *

- * This method must only be called from the constructor, and the same - * sequence of invocations must occur during construction of each object - * with the same ID. - * - * @param namespace the namespace of the new field - * @param name the name of the new field - * - * @return a configured builder - */ - protected StateFieldBuilder field(String id) { - StateFieldBuilder builder = getLayout().getBuilder(id); - - builder.setOrdinal(fieldOrdinal); - fieldOrdinal++; - - return builder; - } - - /* - * IO - */ - - /** - * Sets the state of this object according to the binary representation read - * from {@code input}. If {@code context == COMMS}, the state of local - * fields is unspecified after this operation. - * - * @param input a {@link DataInput} that a state can be read from - * @param context the context - * - * @throws IOException if the state is encoded poorly or an error occurs - * in {@code input} - */ - public void read(DataInput input, IOContext context) throws IOException { - getLayout().read(this, input, context); - } - - /** - * Writes the binary representation of the state of this object to the - * {@code output}. - * - * @param output a {@link DataOutput} that a state can be written to - * @param context the context - * - * @throws IOException if an error occurs in {@code output} - */ - public void write(DataOutput output, IOContext context) throws IOException { - getLayout().write(this, output, context); - } - - /* - * Identity operations - */ - - /** - * Turns {@code destination} into a deep copy of this object. - *

- * Changes the provided object so that: - *

    - *
  • the provided object equals this object according to - * {@link StatefulObject#equals(Object)}; and
  • - *
  • the provided object is independent of this object, meaning no change - * to {@code destination} can affect this object.
  • - *
- * - * @param destination the object to copy this object into. - */ - public StatefulObject copy(StatefulObject destination) { - Objects.requireNonNull(destination, "destination"); - - if (destination == this) { - throw new IllegalArgumentException( - "Cannot copy an object into itself" - ); - } - - if (destination.getClass() != this.getClass()) { - throw new IllegalArgumentException( - "Cannot copy from " + getClass() - + " (ID " + getId() + ") to " + destination.getClass() - ); - } - - getLayout().copy(this, destination); - return destination; - } - - /** - * @see #equals(Object) - */ - @Override - public int hashCode() { - return getLayout().computeHashCode(this); - } - - /** - * Determines whether this object and {@code obj} have equal states. - * Stateful objects are considered equal iff they are - * {@linkplain #isLike(Object) "like"} and their binary representations - * match exactly. - * - * @param obj the object to examine - * @return {@code true} if {@code obj != null} and this object is equal to - * {@code obj} - */ - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (!this.isLike(obj)) return false; - - return getLayout().areEqual(this, (StatefulObject) obj); - } - - /** - * Checks whether the provided object is "like" this object. - *

- * Returns {@code true} iff this object and {@code obj} have the same ID and - * are instances of the same class. - * - * @param obj the object to examine - * @return {@code true} if {@code obj} is "like" this object - */ - public boolean isLike(Object obj) { - if (obj == null) return false; - if (obj == this) return true; - if (obj.getClass() != this.getClass()) return false; - - StatefulObject statefulObj = (StatefulObject) obj; - - if (statefulObj.getId().equals(this.getId())) return false; - - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Objects; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; + +/** + * An abstract class describing objects that have trackable state, + * such as blocks, tiles or entities. This class contains the declaration of + * the state mechanics + * (implementation of which is mostly delegated to + * {@link StatefulObjectLayout}). + *

Structure

+ * Stateful objects are characterized by their likeness and state. + *

+ * An object's likeness is the combination of the object's runtime class (as in + * {@link #getClass()}) and its ID. Objects that are "alike" share the same + * internal structure, represented by a common + * {@linkplain StatefulObjectLayout layout}. Likeness can be tested with + * {@link #isLike(Object)}. + *

+ * An object's state is the combination of the values of an object's + * {@linkplain StateField state fields}. State fields are different from object + * fields as described by the Java language: not every object field is a part + * of its state, although state fields are usually implemented as object fields. + * Each state field is, in its turn, has the following characteristics: + *

    + *
  • ID, distinct from the ID of the stateful object to which it belongs. + * State field IDs are only unique within fields of one likeness.
  • + *
  • data type, which is one of Java primitive types or a compound (Object) + * type.
  • + *
+ */ +public abstract class StatefulObject extends Namespaced { + + private final StatefulObjectLayout layout; + + private final StateStorage storage; + + public StatefulObject( + StatefulObjectRegistry type, + String id + ) { + super(id); + this.layout = type.getLayout(getId()); + this.storage = getLayout().createStorage(); + } + + /** + * Returns the {@link StatefulObjectLayout} describing objects that are + * {@linkplain #isLike(Object) "like"} this object. + * You probably don't need this. + * + * @return this object's field layout + */ + public StatefulObjectLayout getLayout() { + return layout; + } + + /** + * Returns a {@link StateStorage} used by this object to store its state in + * memory. You probably don't need this. + * + * @return this object's state storage + */ + public StateStorage getStorage() { + return storage; + } + + /* + * Field construction + */ + + /** + * Used to keep track of the ordinal number of the next field to be + * requested. + */ + private int fieldOrdinal = 0; + + /** + * Returns a {@link StateFieldBuilder} set up to construct a field with the + * specified ID. + *

+ * This method must only be called from the constructor, and the same + * sequence of invocations must occur during construction of each object + * with the same ID. + * + * @param namespace the namespace of the new field + * @param name the name of the new field + * @return a configured builder + */ + protected StateFieldBuilder field(String id) { + StateFieldBuilder builder = getLayout().getBuilder(id); + + builder.setOrdinal(fieldOrdinal); + fieldOrdinal++; + + return builder; + } + + /* + * IO + */ + + /** + * Sets the state of this object according to the binary representation read + * from {@code input}. If {@code context == COMMS}, the state of local + * fields is unspecified after this operation. + * + * @param input a {@link DataInput} that a state can be read from + * @param context the context + * @throws IOException if the state is encoded poorly or an error occurs + * in {@code input} + */ + public void read(DataInput input, IOContext context) throws IOException { + getLayout().read(this, input, context); + } + + /** + * Writes the binary representation of the state of this object to the + * {@code output}. + * + * @param output a {@link DataOutput} that a state can be written to + * @param context the context + * @throws IOException if an error occurs in {@code output} + */ + public void write(DataOutput output, IOContext context) throws IOException { + getLayout().write(this, output, context); + } + + /* + * Identity operations + */ + + /** + * Turns {@code destination} into a deep copy of this object. + *

+ * Changes the provided object so that: + *

    + *
  • the provided object equals this object according to + * {@link StatefulObject#equals(Object)}; and
  • + *
  • the provided object is independent of this object, meaning no change + * to {@code destination} can affect this object.
  • + *
+ * + * @param destination the object to copy this object into. + */ + public StatefulObject copy(StatefulObject destination) { + Objects.requireNonNull(destination, "destination"); + + if (destination == this) { + throw new IllegalArgumentException( + "Cannot copy an object into itself" + ); + } + + if (destination.getClass() != this.getClass()) { + throw new IllegalArgumentException( + "Cannot copy from " + getClass() + + " (ID " + getId() + ") to " + destination.getClass() + ); + } + + getLayout().copy(this, destination); + return destination; + } + + /** + * @see #equals(Object) + */ + @Override + public int hashCode() { + return getLayout().computeHashCode(this); + } + + /** + * Determines whether this object and {@code obj} have equal states. + * Stateful objects are considered equal iff they are + * {@linkplain #isLike(Object) "like"} and their binary representations + * match exactly. + * + * @param obj the object to examine + * @return {@code true} if {@code obj != null} and this object is equal to + * {@code obj} + */ + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!this.isLike(obj)) + return false; + + return getLayout().areEqual(this, (StatefulObject) obj); + } + + /** + * Checks whether the provided object is "like" this object. + *

+ * Returns {@code true} iff this object and {@code obj} have the same ID and + * are instances of the same class. + * + * @param obj the object to examine + * @return {@code true} if {@code obj} is "like" this object + */ + public boolean isLike(Object obj) { + if (obj == null) + return false; + if (obj == this) + return true; + if (obj.getClass() != this.getClass()) + return false; + + StatefulObject statefulObj = (StatefulObject) obj; + + if (statefulObj.getId().equals(this.getId())) + return false; + + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java index 5165662..4490cdf 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectLayout.java @@ -1,48 +1,69 @@ -package ru.windcorp.progressia.common.state; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public abstract class StatefulObjectLayout { - - private final String objectId; - - public StatefulObjectLayout(String objectId) { - this.objectId = objectId; - } - - public String getObjectId() { - return objectId; - } - - public abstract StateStorage createStorage(); - - protected void checkObject(StatefulObject object) { - if (!object.getId().equals(getObjectId())) { - throw new IllegalArgumentException( - object.getId() + " is not " + getObjectId() - ); - } - } - - public abstract void read( - StatefulObject object, - DataInput input, - IOContext context - ) throws IOException; - - public abstract void write( - StatefulObject object, - DataOutput output, - IOContext context - ) throws IOException; - - public abstract void copy(StatefulObject from, StatefulObject to); - - public abstract int computeHashCode(StatefulObject object); - public abstract boolean areEqual(StatefulObject a, StatefulObject b); - - public abstract StateFieldBuilder getBuilder(String id); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public abstract class StatefulObjectLayout { + + private final String objectId; + + public StatefulObjectLayout(String objectId) { + this.objectId = objectId; + } + + public String getObjectId() { + return objectId; + } + + public abstract StateStorage createStorage(); + + protected void checkObject(StatefulObject object) { + if (!object.getId().equals(getObjectId())) { + throw new IllegalArgumentException( + object.getId() + " is not " + getObjectId() + ); + } + } + + public abstract void read( + StatefulObject object, + DataInput input, + IOContext context + ) + throws IOException; + + public abstract void write( + StatefulObject object, + DataOutput output, + IOContext context + ) + throws IOException; + + public abstract void copy(StatefulObject from, StatefulObject to); + + public abstract int computeHashCode(StatefulObject object); + + public abstract boolean areEqual(StatefulObject a, StatefulObject b); + + public abstract StateFieldBuilder getBuilder(String id); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java index 42028cf..aa082a6 100644 --- a/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/state/StatefulObjectRegistry.java @@ -1,98 +1,114 @@ -package ru.windcorp.progressia.common.state; - -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -/** - * Registry-like object for identification of various {@link StatefulObject} - * types, such as blocks vs tiles. This object stores and manages various - * {@linkplain StatefulObjectLayout layouts}. - */ -public class StatefulObjectRegistry { - - @FunctionalInterface - public static interface Factory { - /** - * Initializes a new, independent instance of the stateful object. - * @return the created object - */ - T build(); - } - - protected static class Type extends Namespaced { - - private final Factory factory; - - private final AtomicBoolean isRegistered = new AtomicBoolean(false); - - public Type(String id, Factory factory) { - super(id); - this.factory = factory; - } - - public T build() { - return factory.build(); - } - - public AtomicBoolean getRegistrationFlag() { - return isRegistered; - } - - } - - private final NamespacedInstanceRegistry> registry = - new NamespacedInstanceRegistry>() { - @Override - public void register(Type element) { - super.register(element); - StatefulObjectRegistry.this.register(element); - }; - }; - - private final Map layouts = - Collections.synchronizedMap(new WeakHashMap<>()); - - public StatefulObjectLayout getLayout(String id) { - StatefulObjectLayout layout = layouts.get(id); - - if (layout == null) { - throw new IllegalArgumentException( - "ID " + id + " has not been registered" - ); - } - - return layout; - } - - protected void register(Type type) { - if (!type.getRegistrationFlag().compareAndSet(false, true)) { - throw new IllegalStateException( - "ID " + type.getId() + " is already registered" - ); - } - - InspectingStatefulObjectLayout inspector = - new InspectingStatefulObjectLayout(type.getId()); - - layouts.put(type.getId(), inspector); - - // During initialization inspector collects necessary data - type.build(); - - layouts.put(type.getId(), inspector.compile()); - } - - public T create(String id) { - return registry.get(id).build(); - } - - public void register(String id, Factory factory) { - registry.register(new Type<>(id, factory)); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.state; + +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +/** + * Registry-like object for identification of various {@link StatefulObject} + * types, such as blocks vs tiles. This object stores and manages various + * {@linkplain StatefulObjectLayout layouts}. + */ +public class StatefulObjectRegistry { + + @FunctionalInterface + public static interface Factory { + /** + * Initializes a new, independent instance of the stateful object. + * + * @return the created object + */ + T build(); + } + + protected static class Type extends Namespaced { + + private final Factory factory; + + private final AtomicBoolean isRegistered = new AtomicBoolean(false); + + public Type(String id, Factory factory) { + super(id); + this.factory = factory; + } + + public T build() { + return factory.build(); + } + + public AtomicBoolean getRegistrationFlag() { + return isRegistered; + } + + } + + private final NamespacedInstanceRegistry> registry = new NamespacedInstanceRegistry>() { + @Override + public void register(Type element) { + super.register(element); + StatefulObjectRegistry.this.register(element); + }; + }; + + private final Map layouts = Collections.synchronizedMap(new WeakHashMap<>()); + + public StatefulObjectLayout getLayout(String id) { + StatefulObjectLayout layout = layouts.get(id); + + if (layout == null) { + throw new IllegalArgumentException( + "ID " + id + " has not been registered" + ); + } + + return layout; + } + + protected void register(Type type) { + if (!type.getRegistrationFlag().compareAndSet(false, true)) { + throw new IllegalStateException( + "ID " + type.getId() + " is already registered" + ); + } + + InspectingStatefulObjectLayout inspector = new InspectingStatefulObjectLayout(type.getId()); + + layouts.put(type.getId(), inspector); + + // During initialization inspector collects necessary data + type.build(); + + layouts.put(type.getId(), inspector.compile()); + } + + public T create(String id) { + return registry.get(id).build(); + } + + public void register(String id, Factory factory) { + registry.register(new Type<>(id, factory)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java b/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java index 0a23d22..ffc8a43 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/BinUtil.java @@ -1,39 +1,40 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -public class BinUtil { - - public static int closestGreaterPowerOf2(int x) { - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x + 1; - } - - public static int roundToGreaterPowerOf2(int x) { - return closestGreaterPowerOf2(x - 1); - } - - public static boolean isPowerOf2(int x) { - return (x > 0) && ((x & (x - 1)) == 0); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +public class BinUtil { + + public static int closestGreaterPowerOf2(int x) { + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; + } + + public static int roundToGreaterPowerOf2(int x) { + return closestGreaterPowerOf2(x - 1); + } + + public static boolean isPowerOf2(int x) { + return (x > 0) && ((x & (x - 1)) == 0); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java index bdb1f14..6b317a7 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java +++ b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferInputStream.java @@ -1,54 +1,55 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import java.io.InputStream; -import java.nio.ByteBuffer; - -/** - * @author Mike - * Houston, adapted by Javapony - */ -public class ByteBufferInputStream extends InputStream { - - private final ByteBuffer buffer; - - public ByteBufferInputStream(ByteBuffer buffer) { - this.buffer = buffer; - } - - @Override - public int read() { - if (!buffer.hasRemaining()) { - return -1; - } - return buffer.get() & 0xFF; - } - - @Override - public int read(byte[] bytes, int off, int len) { - if (!buffer.hasRemaining()) { - return -1; - } - - len = Math.min(len, buffer.remaining()); - buffer.get(bytes, off, len); - return len; - } - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * @author Mike + * Houston, adapted by Javapony + */ +public class ByteBufferInputStream extends InputStream { + + private final ByteBuffer buffer; + + public ByteBufferInputStream(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public int read() { + if (!buffer.hasRemaining()) { + return -1; + } + return buffer.get() & 0xFF; + } + + @Override + public int read(byte[] bytes, int off, int len) { + if (!buffer.hasRemaining()) { + return -1; + } + + len = Math.min(len, buffer.remaining()); + buffer.get(bytes, off, len); + return len; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java index 1f1323e..8931c75 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java +++ b/src/main/java/ru/windcorp/progressia/common/util/ByteBufferOutputStream.java @@ -1,51 +1,52 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; - -public class ByteBufferOutputStream extends OutputStream { - - private final ByteBuffer buffer; - - public ByteBufferOutputStream(ByteBuffer buffer) { - this.buffer = buffer; - } - - @Override - public void write(int b) throws IOException { - try { - buffer.put((byte) b); - } catch (BufferOverflowException e) { - throw new IOException(e); - } - } - - @Override - public void write(byte[] bytes, int off, int len) throws IOException { - try { - buffer.put(bytes, off, len); - } catch (BufferOverflowException e) { - throw new IOException(e); - } - } - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; + +public class ByteBufferOutputStream extends OutputStream { + + private final ByteBuffer buffer; + + public ByteBufferOutputStream(ByteBuffer buffer) { + this.buffer = buffer; + } + + @Override + public void write(int b) throws IOException { + try { + buffer.put((byte) b); + } catch (BufferOverflowException e) { + throw new IOException(e); + } + } + + @Override + public void write(byte[] bytes, int off, int len) throws IOException { + try { + buffer.put(bytes, off, len); + } catch (BufferOverflowException e) { + throw new IOException(e); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java b/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java index 5efe66b..0ef2413 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java +++ b/src/main/java/ru/windcorp/progressia/common/util/CoordinatePacker.java @@ -1,128 +1,123 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import glm.vec._2.i.Vec2i; -import glm.vec._3.i.Vec3i; - -public class CoordinatePacker { - - private static final int BITS_3_INTS_INTO_LONG; - private static final long MASK_3_INTS_INTO_LONG; - - private static final int BITS_2_INTS_INTO_LONG; - private static final long MASK_2_INTS_INTO_LONG; - - static { - BITS_3_INTS_INTO_LONG = 64 / 3; - - /* - * What happens below: - * - * 1. 1 << BITS_3_INTS_INTO_LONG: - * 0000 ... 00100 ... 0000 - * \_________/ - BITS_3_INTS_INTO_LONG zeros - * - * 2. (1 << BITS_3_INTS_INTO_LONG) - 1: - * 0000 ... 00011 ... 1111 - * \_________/ - BITS_3_INTS_INTO_LONG ones - WIN - */ - - MASK_3_INTS_INTO_LONG = (1l << BITS_3_INTS_INTO_LONG) - 1; - - BITS_2_INTS_INTO_LONG = 64 / 2; - MASK_2_INTS_INTO_LONG = (1l << BITS_2_INTS_INTO_LONG) - 1; - } - - public static long pack3IntsIntoLong(int a, int b, int c) { - return - ((a & MASK_3_INTS_INTO_LONG) << (2 * BITS_3_INTS_INTO_LONG)) | - ((b & MASK_3_INTS_INTO_LONG) << (1 * BITS_3_INTS_INTO_LONG)) | - ((c & MASK_3_INTS_INTO_LONG) << (0 * BITS_3_INTS_INTO_LONG)); - } - - public static long pack3IntsIntoLong(Vec3i v) { - return pack3IntsIntoLong(v.x, v.y, v.z); - } - - public static int unpack3IntsFromLong(long packed, int index) { - if (index < 0 || index >= 3) { - throw new IllegalArgumentException("Invalid index " + index); - } - - int result = (int) ( - (packed >>> ((2 - index) * BITS_3_INTS_INTO_LONG)) - & MASK_3_INTS_INTO_LONG - ); - - final long signMask = ((MASK_3_INTS_INTO_LONG + 1) >> 1); - - if ((result & signMask) != 0) { - result |= ~MASK_3_INTS_INTO_LONG; - } - - return result; - } - - public static Vec3i unpack3IntsFromLong(long packed, Vec3i output) { - if (output == null) output = new Vec3i(); - - output.set( - unpack3IntsFromLong(packed, 0), - unpack3IntsFromLong(packed, 1), - unpack3IntsFromLong(packed, 2) - ); - - return output; - } - - public static long pack2IntsIntoLong(int a, int b) { - return - ((a & MASK_2_INTS_INTO_LONG) << (1 * BITS_2_INTS_INTO_LONG)) | - ((b & MASK_2_INTS_INTO_LONG) << (0 * BITS_2_INTS_INTO_LONG)); - } - - public static long pack2IntsIntoLong(Vec2i v) { - return pack2IntsIntoLong(v.x, v.y); - } - - public static int unpack2IntsFromLong(long packed, int index) { - if (index < 0 || index >= 2) { - throw new IllegalArgumentException("Invalid index " + index); - } - - int result = (int) ( - (packed >>> ((1 - index) * BITS_2_INTS_INTO_LONG)) - & MASK_2_INTS_INTO_LONG - ); - - return result; - } - - public static Vec2i unpack2IntsFromLong(long packed, Vec2i output) { - if (output == null) output = new Vec2i(); - - output.set( - unpack2IntsFromLong(packed, 0), - unpack2IntsFromLong(packed, 1) - ); - - return output; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import glm.vec._2.i.Vec2i; +import glm.vec._3.i.Vec3i; + +public class CoordinatePacker { + + private static final int BITS_3_INTS_INTO_LONG; + private static final long MASK_3_INTS_INTO_LONG; + + private static final int BITS_2_INTS_INTO_LONG; + private static final long MASK_2_INTS_INTO_LONG; + + static { + BITS_3_INTS_INTO_LONG = 64 / 3; + + /* + * What happens below: + * 1. 1 << BITS_3_INTS_INTO_LONG: + * 0000 ... 00100 ... 0000 + * \_________/ - BITS_3_INTS_INTO_LONG zeros + * 2. (1 << BITS_3_INTS_INTO_LONG) - 1: + * 0000 ... 00011 ... 1111 + * \_________/ - BITS_3_INTS_INTO_LONG ones - WIN + */ + + MASK_3_INTS_INTO_LONG = (1l << BITS_3_INTS_INTO_LONG) - 1; + + BITS_2_INTS_INTO_LONG = 64 / 2; + MASK_2_INTS_INTO_LONG = (1l << BITS_2_INTS_INTO_LONG) - 1; + } + + public static long pack3IntsIntoLong(int a, int b, int c) { + return ((a & MASK_3_INTS_INTO_LONG) << (2 * BITS_3_INTS_INTO_LONG)) | + ((b & MASK_3_INTS_INTO_LONG) << (1 * BITS_3_INTS_INTO_LONG)) | + ((c & MASK_3_INTS_INTO_LONG) << (0 * BITS_3_INTS_INTO_LONG)); + } + + public static long pack3IntsIntoLong(Vec3i v) { + return pack3IntsIntoLong(v.x, v.y, v.z); + } + + public static int unpack3IntsFromLong(long packed, int index) { + if (index < 0 || index >= 3) { + throw new IllegalArgumentException("Invalid index " + index); + } + + int result = (int) ((packed >>> ((2 - index) * BITS_3_INTS_INTO_LONG)) + & MASK_3_INTS_INTO_LONG); + + final long signMask = ((MASK_3_INTS_INTO_LONG + 1) >> 1); + + if ((result & signMask) != 0) { + result |= ~MASK_3_INTS_INTO_LONG; + } + + return result; + } + + public static Vec3i unpack3IntsFromLong(long packed, Vec3i output) { + if (output == null) + output = new Vec3i(); + + output.set( + unpack3IntsFromLong(packed, 0), + unpack3IntsFromLong(packed, 1), + unpack3IntsFromLong(packed, 2) + ); + + return output; + } + + public static long pack2IntsIntoLong(int a, int b) { + return ((a & MASK_2_INTS_INTO_LONG) << (1 * BITS_2_INTS_INTO_LONG)) | + ((b & MASK_2_INTS_INTO_LONG) << (0 * BITS_2_INTS_INTO_LONG)); + } + + public static long pack2IntsIntoLong(Vec2i v) { + return pack2IntsIntoLong(v.x, v.y); + } + + public static int unpack2IntsFromLong(long packed, int index) { + if (index < 0 || index >= 2) { + throw new IllegalArgumentException("Invalid index " + index); + } + + int result = (int) ((packed >>> ((1 - index) * BITS_2_INTS_INTO_LONG)) + & MASK_2_INTS_INTO_LONG); + + return result; + } + + public static Vec2i unpack2IntsFromLong(long packed, Vec2i output) { + if (output == null) + output = new Vec2i(); + + output.set( + unpack2IntsFromLong(packed, 0), + unpack2IntsFromLong(packed, 1) + ); + + return output; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java b/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java index 89f4527..23522c1 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/DataBuffer.java @@ -1,128 +1,147 @@ -package ru.windcorp.progressia.common.util; - -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import gnu.trove.list.array.TByteArrayList; - -public class DataBuffer { - - private static final int DEFAULT_CAPACITY = 1024; - private static final int TRANSFER_BUFFER_SIZE = 1024; - - private final TByteArrayList buffer; - - private final byte[] transferBuffer = new byte[TRANSFER_BUFFER_SIZE]; - - private int position; - - private final InputStream inputStream = new InputStream() { - @Override - public int read() throws IOException { - if (DataBuffer.this.position >= buffer.size()) return -1; - int result = buffer.getQuick(DataBuffer.this.position) & 0xFF; - ++DataBuffer.this.position; - return result; - } - }; - - private final OutputStream outputStream = new OutputStream() { - @Override - public void write(int b) throws IOException { - DataBuffer.this.buffer.add((byte) b); - } - }; - - private final DataInputStream reader = new DataInputStream(inputStream); - private final DataOutputStream writer = new DataOutputStream(outputStream); - - public DataBuffer(int capacity) { - this.buffer = new TByteArrayList(capacity); - } - - public DataBuffer() { - this(DEFAULT_CAPACITY); - } - - public DataBuffer(DataBuffer copyFrom) { - this.buffer = new TByteArrayList(copyFrom.buffer); - } - - public DataInputStream getReader() { - position = 0; - return reader; - } - - public InputStream getInputStream() { - return getReader(); - } - - public DataOutputStream getWriter() { - buffer.resetQuick(); - return writer; - } - - public OutputStream getOutputStream() { - return getWriter(); - } - - public int getSize() { - return buffer.size(); - } - - public void fill(DataInput source, int length) throws IOException { - buffer.resetQuick(); - buffer.ensureCapacity(length); - - while (length > 0) { - int currentLength = Math.min(transferBuffer.length, length); - - source.readFully(transferBuffer, 0, currentLength); - buffer.add(transferBuffer, 0, currentLength); - - length -= currentLength; - } - } - - public void flush(DataOutput sink) throws IOException { - int position = 0; - int length = buffer.size(); - - while (position < length) { - int currentLength = Math.min( - transferBuffer.length, - length - position - ); - - buffer.toArray(transferBuffer, position, 0, currentLength); - sink.write(transferBuffer, 0, currentLength); - - length -= currentLength; - } - } - - @Override - public int hashCode() { - return buffer.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - DataBuffer other = (DataBuffer) obj; - if (!buffer.equals(other.buffer)) - return false; - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import gnu.trove.list.array.TByteArrayList; + +public class DataBuffer { + + private static final int DEFAULT_CAPACITY = 1024; + private static final int TRANSFER_BUFFER_SIZE = 1024; + + private final TByteArrayList buffer; + + private final byte[] transferBuffer = new byte[TRANSFER_BUFFER_SIZE]; + + private int position; + + private final InputStream inputStream = new InputStream() { + @Override + public int read() throws IOException { + if (DataBuffer.this.position >= buffer.size()) + return -1; + int result = buffer.getQuick(DataBuffer.this.position) & 0xFF; + ++DataBuffer.this.position; + return result; + } + }; + + private final OutputStream outputStream = new OutputStream() { + @Override + public void write(int b) throws IOException { + DataBuffer.this.buffer.add((byte) b); + } + }; + + private final DataInputStream reader = new DataInputStream(inputStream); + private final DataOutputStream writer = new DataOutputStream(outputStream); + + public DataBuffer(int capacity) { + this.buffer = new TByteArrayList(capacity); + } + + public DataBuffer() { + this(DEFAULT_CAPACITY); + } + + public DataBuffer(DataBuffer copyFrom) { + this.buffer = new TByteArrayList(copyFrom.buffer); + } + + public DataInputStream getReader() { + position = 0; + return reader; + } + + public InputStream getInputStream() { + return getReader(); + } + + public DataOutputStream getWriter() { + buffer.resetQuick(); + return writer; + } + + public OutputStream getOutputStream() { + return getWriter(); + } + + public int getSize() { + return buffer.size(); + } + + public void fill(DataInput source, int length) throws IOException { + buffer.resetQuick(); + buffer.ensureCapacity(length); + + while (length > 0) { + int currentLength = Math.min(transferBuffer.length, length); + + source.readFully(transferBuffer, 0, currentLength); + buffer.add(transferBuffer, 0, currentLength); + + length -= currentLength; + } + } + + public void flush(DataOutput sink) throws IOException { + int position = 0; + int length = buffer.size(); + + while (position < length) { + int currentLength = Math.min( + transferBuffer.length, + length - position + ); + + buffer.toArray(transferBuffer, position, 0, currentLength); + sink.write(transferBuffer, 0, currentLength); + + length -= currentLength; + } + } + + @Override + public int hashCode() { + return buffer.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DataBuffer other = (DataBuffer) obj; + if (!buffer.equals(other.buffer)) + return false; + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java b/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java index 270545a..43487c0 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/FloatMathUtil.java @@ -1,29 +1,48 @@ -package ru.windcorp.progressia.common.util; - -public class FloatMathUtil { - - public static final float PI_F = (float) Math.PI; - - public static float floor(float x) { - return (float) Math.floor(x); - } - - public static float normalizeAngle(float a) { - return a - 2*PI_F * floor((a + PI_F) / (2*PI_F)); - } - - public static float sin(float x) { - return (float) Math.sin(x); - } - - public static float cos(float x) { - return (float) Math.cos(x); - } - - public static float tan(float x) { - return (float) Math.tan(x); - } - - private FloatMathUtil() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +public class FloatMathUtil { + + public static final float PI_F = (float) Math.PI; + + public static float floor(float x) { + return (float) Math.floor(x); + } + + public static float normalizeAngle(float a) { + return a - 2 * PI_F * floor((a + PI_F) / (2 * PI_F)); + } + + public static float sin(float x) { + return (float) Math.sin(x); + } + + public static float cos(float x) { + return (float) Math.cos(x); + } + + public static float tan(float x) { + return (float) Math.tan(x); + } + + private FloatMathUtil() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java index fbd65c0..c5b2952 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java +++ b/src/main/java/ru/windcorp/progressia/common/util/LowOverheadCache.java @@ -1,33 +1,50 @@ -package ru.windcorp.progressia.common.util; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -public class LowOverheadCache { - - private final ThreadLocal> ready = - ThreadLocal.withInitial(ArrayList::new); - - private final Supplier generator; - - public LowOverheadCache(Supplier generator) { - this.generator = generator; - } - - public E grab() { - List list = ready.get(); - int size = list.size(); - - if (size == 0) { - return generator.get(); - } - - return list.remove(size - 1); - } - - public void release(E object) { - ready.get().add(object); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; + +public class LowOverheadCache { + + private final ThreadLocal> ready = ThreadLocal.withInitial(ArrayList::new); + + private final Supplier generator; + + public LowOverheadCache(Supplier generator) { + this.generator = generator; + } + + public E grab() { + List list = ready.get(); + int size = list.size(); + + if (size == 0) { + return generator.get(); + } + + return list.remove(size - 1); + } + + public void release(E object) { + ready.get().add(object); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/Matrices.java b/src/main/java/ru/windcorp/progressia/common/util/Matrices.java index 9161f99..8804272 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Matrices.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Matrices.java @@ -1,64 +1,82 @@ -package ru.windcorp.progressia.common.util; - -import glm.mat._3.Mat3; -import glm.mat._4.Mat4; -import glm.mat._4.d.Mat4d; - -/** - * A set of caches for GLM matrix objects. - *

- * All {@code grab}bed objects must be {@code release}d as soon as possible. - * Ideally, user code should be: - *

- * Mat4 myMatrix = Vectors.grab4();
- * try {
- *     // use myMatrix
- * } finally {
- *     Matrices.release(myMatrix);
- * }
- * 
- * Provided objects may be reused after {@code release} has been invoked; - * do not store them. - *

- * This class is thread- and recursion-safe. - * - * @see Vectors - */ -public class Matrices { - - private static final LowOverheadCache MAT3S = - new LowOverheadCache<>(Mat3::new); - - public static Mat3 grab3() { - return MAT3S.grab(); - } - - public static void release(Mat3 m) { - MAT3S.release(m); - } - - private static final LowOverheadCache MAT4S = - new LowOverheadCache<>(Mat4::new); - - public static Mat4 grab4() { - return MAT4S.grab(); - } - - public static void release(Mat4 m) { - MAT4S.release(m); - } - - private static final LowOverheadCache MAT4DS = - new LowOverheadCache<>(Mat4d::new); - - public static Mat4d grab4d() { - return MAT4DS.grab(); - } - - public static void release(Mat4d m) { - MAT4DS.release(m); - } - - private Matrices() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import glm.mat._3.Mat3; +import glm.mat._4.Mat4; +import glm.mat._4.d.Mat4d; + +/** + * A set of caches for GLM matrix objects. + *

+ * All {@code grab}bed objects must be {@code release}d as soon as possible. + * Ideally, user code should be: + * + *

+ * Mat4 myMatrix = Vectors.grab4();
+ * try {
+ * 	// use myMatrix
+ * } finally {
+ * 	Matrices.release(myMatrix);
+ * }
+ * 
+ * + * Provided objects may be reused after {@code release} has been invoked; + * do not store them. + *

+ * This class is thread- and recursion-safe. + * + * @see Vectors + */ +public class Matrices { + + private static final LowOverheadCache MAT3S = new LowOverheadCache<>(Mat3::new); + + public static Mat3 grab3() { + return MAT3S.grab(); + } + + public static void release(Mat3 m) { + MAT3S.release(m); + } + + private static final LowOverheadCache MAT4S = new LowOverheadCache<>(Mat4::new); + + public static Mat4 grab4() { + return MAT4S.grab(); + } + + public static void release(Mat4 m) { + MAT4S.release(m); + } + + private static final LowOverheadCache MAT4DS = new LowOverheadCache<>(Mat4d::new); + + public static Mat4d grab4d() { + return MAT4DS.grab(); + } + + public static void release(Mat4d m) { + MAT4DS.release(m); + } + + private Matrices() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java b/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java index b9e67d9..295244d 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java +++ b/src/main/java/ru/windcorp/progressia/common/util/MultiLOC.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util; import java.util.HashMap; @@ -5,18 +23,18 @@ import java.util.Map; import java.util.function.Supplier; public class MultiLOC { - + private final Map, LowOverheadCache> caches = new HashMap<>(); - + public MultiLOC addClass(Class clazz, Supplier generator) { caches.put(clazz, new LowOverheadCache<>(generator)); return this; } - + public T grab(Class clazz) { return clazz.cast(caches.get(clazz).grab()); } - + @SuppressWarnings("unchecked") public void release(Object obj) { ((LowOverheadCache) caches.get(obj.getClass())).release(obj); diff --git a/src/main/java/ru/windcorp/progressia/common/util/Named.java b/src/main/java/ru/windcorp/progressia/common/util/Named.java index d7b03f9..d9fc97a 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Named.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Named.java @@ -1,61 +1,62 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import java.util.Objects; - -public abstract class Named { - - private final String name; - - public Named(String name) { - this.name = Objects.requireNonNull(name, "name"); - } - - public String getName() { - return name; - } - - @Override - public String toString() { - return getClass().getSimpleName() + " " + getName(); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Named other = (Named) obj; - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.Objects; + +public abstract class Named { + + private final String name; + + public Named(String name) { + this.name = Objects.requireNonNull(name, "name"); + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " " + getName(); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Named other = (Named) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java index 83645a0..2010ccb 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java +++ b/src/main/java/ru/windcorp/progressia/common/util/SizeLimitedList.java @@ -1,72 +1,90 @@ -package ru.windcorp.progressia.common.util; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.RandomAccess; - -import com.google.common.collect.ForwardingList; - -public class SizeLimitedList extends ForwardingList { - - private static final class RandomAccessSizeLimitedList - extends SizeLimitedList - implements RandomAccess { - protected RandomAccessSizeLimitedList(List parent, int maxSize) { - super(parent, maxSize); - } - } - - public static List wrap(List list, int maxSize) { - if (list instanceof RandomAccess) { - return new RandomAccessSizeLimitedList<>(list, maxSize); - } else { - return new SizeLimitedList<>(list, maxSize); - } - } - - private final List delegate; - - private final int maxSize; - - protected SizeLimitedList(List parent, int maxSize) { - this.delegate = Objects.requireNonNull(parent, "parent"); - this.maxSize = maxSize; - } - - @Override - public boolean addAll(Collection collection) { - return standardAddAll(collection); - } - - @Override - public boolean addAll(int index, Collection elements) { - return standardAddAll(index, elements); - } - - @Override - public boolean add(E e) { - checkMaxSize(); - return delegate().add(e); - } - - @Override - public void add(int index, final E e) { - checkMaxSize(); - delegate().add(index, e); - } - - private void checkMaxSize() { - if (size() >= maxSize) { - throw new UnsupportedOperationException( - "Maximum size " + maxSize + " reached" - ); - } - } - - @Override - protected List delegate() { - return delegate; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.RandomAccess; + +import com.google.common.collect.ForwardingList; + +public class SizeLimitedList extends ForwardingList { + + private static final class RandomAccessSizeLimitedList + extends SizeLimitedList + implements RandomAccess { + protected RandomAccessSizeLimitedList(List parent, int maxSize) { + super(parent, maxSize); + } + } + + public static List wrap(List list, int maxSize) { + if (list instanceof RandomAccess) { + return new RandomAccessSizeLimitedList<>(list, maxSize); + } else { + return new SizeLimitedList<>(list, maxSize); + } + } + + private final List delegate; + + private final int maxSize; + + protected SizeLimitedList(List parent, int maxSize) { + this.delegate = Objects.requireNonNull(parent, "parent"); + this.maxSize = maxSize; + } + + @Override + public boolean addAll(Collection collection) { + return standardAddAll(collection); + } + + @Override + public boolean addAll(int index, Collection elements) { + return standardAddAll(index, elements); + } + + @Override + public boolean add(E e) { + checkMaxSize(); + return delegate().add(e); + } + + @Override + public void add(int index, final E e) { + checkMaxSize(); + delegate().add(index, e); + } + + private void checkMaxSize() { + if (size() >= maxSize) { + throw new UnsupportedOperationException( + "Maximum size " + maxSize + " reached" + ); + } + } + + @Override + protected List delegate() { + return delegate; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java b/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java index 4c7b601..394c79d 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java +++ b/src/main/java/ru/windcorp/progressia/common/util/StashingStack.java @@ -1,247 +1,268 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.function.Supplier; - -import com.google.common.collect.Iterables; - -/** - * A low-overhead, fixed-capacity stack that does not dispose of popped elements - * but rather stashes them for later pushing. This allows the stack to - * operate without creating new objects. - *

- * This object always contains references to {@link #getCapacity()} elements, of - * which first {@link #getSize()} elements are present in the stack proper and - * accessable, and the rest are stashed. When an element is popped, is - * becomes stashed. When an element is pushed, it ceases to be stashed. - *

- * Stashed elements can be replaced with {@link #push(Object)}. - * - * @author Javapony - */ -@SuppressWarnings("unchecked") -public class StashingStack implements Iterable { - - /** - * Stores all elements. Elements with indices - * [0; {@link #head}] - * are present in the stack, elements with indices - * ({@link #head}; contents.length] are stashed. - */ - private final Object[] contents; - - private transient List contentsAsList; - - /** - * Index of the head of the stack in the {@link #contents} array, or - * -1, if the stack is empty. - */ - private int head = -1; - - protected StashingStack(Object[] stash, int dummy) { - this.contents = stash; - } - - /** - * Creates a new stack. Its stash is filled with {@code null}s. - * @param capacity stack's capacity - */ - public StashingStack(int capacity) { - this((T[]) new Object[capacity], 0); - } - - /** - * Creates a new stack with the supplied stash. - * @param contents elements that are put in the stash initially. - */ - public StashingStack(T[] contents) { - this(contents.clone(), 0); - } - - /** - * Creates a new stack with the supplied stash. - * @param contents elements that are put in the stash initially. - */ - public StashingStack(Iterable contents) { - this(Iterables.toArray(contents, Object.class), 0); - } - - /** - * Creates a new stack. Its stash is filled with objects provided by - * {@code generator}. The generator's {@link Supplier#get() get()} method - * will only be invoked {@code capacity} times from within this constructor. - * @param capacity stack's capacity - * @param generator a supplier of objects for the stash - */ - public StashingStack(int capacity, Supplier generator) { - this(capacity); - - for (int i = 0; i < contents.length; ++i) { - contents[i] = generator.get(); - } - } - /** - * Returns the amount of elements this stack can store. - * @return the capacity - */ - public int getCapacity() { - return contents.length; - } - - /** - * Returns the amount of elements that are currently in the stack. - * @return the size - */ - public int getSize() { - return head + 1; - } - - /** - * Checks whether this stack does not contain any elements. - * @return {@code true} is this stack is empty - */ - public boolean isEmpty() { - return getSize() == 0; - } - - /** - * Checks whether this stack is full. - * @return {@code true} is this stack is full - */ - public boolean isFull() { - return getSize() == getCapacity(); - } - - /** - * Returns, but does not remove, the head of this stack. If the stack is - * empty returns {@code null}. - * @return head of this stack or {@code null} - * @see #getHead() - */ - public T peek() { - if (head < 0) return null; - return (T) contents[head]; - } - - /** - * Returns, but does not remove, the head of this stack. If the stack is - * empty throws a {@link NoSuchElementException}. - * @return head of this stack - * @throws NoSuchElementException is the stack is empty - * @see #peek() - */ - public T getHead() { - if (head < 0) throw new NoSuchElementException(); - return (T) contents[head]; - } - - /** - * Returns and removes the head of this stack. If the stack is - * empty returns {@code null}. - * @return head of this stack or {@code null} - * @see #removeHead() - */ - public T pop() { - if (head < 0) return null; - return (T) contents[head--]; - } - - /** - * Returns and removes the head of this stack. If the stack is - * empty throws a {@link NoSuchElementException}. - * @return head of this stack - * @throws NoSuchElementException is the stack is empty - * @see #pop() - */ - public T removeHead() { - if (head < 0) throw new NoSuchElementException(); - return (T) contents[head--]; - } - - /** - * Pushes a new element from the stash onto the stack. If the stack is - * already full throws an {@link IllegalStateException}. The state of the - * new element is not specified. - * @return the new head - */ - public T push() { - if (head == contents.length - 1) { - throw new IllegalStateException(); - } - - return (T) contents[++head]; - } - - /** - * Pushes the specified element onto the stack. A stashed element is - * removed. If the stack is already full throws an - * {@link IllegalStateException}. - * @param newElement the element to push - * @return the new head - */ - public T push(T newElement) { - if (head == contents.length - 1) { - throw new IllegalStateException(); - } - - contents[++head] = newElement; - return newElement; - } - - /** - * Returns the specified element from the stack. Indexing starts from the - * bottom of the stack. If the index is out of bounds, an - * {@link IndexOutOfBoundsException} is thrown. - * @param index index of the element to retrieve, - * [0; {@link #getSize()}) - * @return the requested element - * @throws IndexOutOfBoundsException if the index is negative or greater - * than head - */ - public T get(int index) { - if (index > head) { - throw new IndexOutOfBoundsException( - "Requested index " + index + " > head " + head - ); - } - - return (T) contents[index]; - } - - /** - * Removes all elements from the stack. - */ - public void removeAll() { - head = -1; - } - - @Override - public Iterator iterator() { - if (contentsAsList == null) { - contentsAsList = Arrays.asList((T[]) contents); - } - - return contentsAsList.subList(0, getSize()).iterator(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.function.Supplier; + +import com.google.common.collect.Iterables; + +/** + * A low-overhead, fixed-capacity stack that does not dispose of popped elements + * but rather stashes them for later pushing. This allows the stack to + * operate without creating new objects. + *

+ * This object always contains references to {@link #getCapacity()} elements, of + * which first {@link #getSize()} elements are present in the stack proper and + * accessable, and the rest are stashed. When an element is popped, is + * becomes stashed. When an element is pushed, it ceases to be stashed. + *

+ * Stashed elements can be replaced with {@link #push(Object)}. + * + * @author Javapony + */ +@SuppressWarnings("unchecked") +public class StashingStack implements Iterable { + + /** + * Stores all elements. Elements with indices + * [0; {@link #head}] + * are present in the stack, elements with indices + * ({@link #head}; contents.length] are stashed. + */ + private final Object[] contents; + + private transient List contentsAsList; + + /** + * Index of the head of the stack in the {@link #contents} array, or + * -1, if the stack is empty. + */ + private int head = -1; + + protected StashingStack(Object[] stash, int dummy) { + this.contents = stash; + } + + /** + * Creates a new stack. Its stash is filled with {@code null}s. + * + * @param capacity stack's capacity + */ + public StashingStack(int capacity) { + this((T[]) new Object[capacity], 0); + } + + /** + * Creates a new stack with the supplied stash. + * + * @param contents elements that are put in the stash initially. + */ + public StashingStack(T[] contents) { + this(contents.clone(), 0); + } + + /** + * Creates a new stack with the supplied stash. + * + * @param contents elements that are put in the stash initially. + */ + public StashingStack(Iterable contents) { + this(Iterables.toArray(contents, Object.class), 0); + } + + /** + * Creates a new stack. Its stash is filled with objects provided by + * {@code generator}. The generator's {@link Supplier#get() get()} method + * will only be invoked {@code capacity} times from within this constructor. + * + * @param capacity stack's capacity + * @param generator a supplier of objects for the stash + */ + public StashingStack(int capacity, Supplier generator) { + this(capacity); + + for (int i = 0; i < contents.length; ++i) { + contents[i] = generator.get(); + } + } + + /** + * Returns the amount of elements this stack can store. + * + * @return the capacity + */ + public int getCapacity() { + return contents.length; + } + + /** + * Returns the amount of elements that are currently in the stack. + * + * @return the size + */ + public int getSize() { + return head + 1; + } + + /** + * Checks whether this stack does not contain any elements. + * + * @return {@code true} is this stack is empty + */ + public boolean isEmpty() { + return getSize() == 0; + } + + /** + * Checks whether this stack is full. + * + * @return {@code true} is this stack is full + */ + public boolean isFull() { + return getSize() == getCapacity(); + } + + /** + * Returns, but does not remove, the head of this stack. If the stack is + * empty returns {@code null}. + * + * @return head of this stack or {@code null} + * @see #getHead() + */ + public T peek() { + if (head < 0) + return null; + return (T) contents[head]; + } + + /** + * Returns, but does not remove, the head of this stack. If the stack is + * empty throws a {@link NoSuchElementException}. + * + * @return head of this stack + * @throws NoSuchElementException is the stack is empty + * @see #peek() + */ + public T getHead() { + if (head < 0) + throw new NoSuchElementException(); + return (T) contents[head]; + } + + /** + * Returns and removes the head of this stack. If the stack is + * empty returns {@code null}. + * + * @return head of this stack or {@code null} + * @see #removeHead() + */ + public T pop() { + if (head < 0) + return null; + return (T) contents[head--]; + } + + /** + * Returns and removes the head of this stack. If the stack is + * empty throws a {@link NoSuchElementException}. + * + * @return head of this stack + * @throws NoSuchElementException is the stack is empty + * @see #pop() + */ + public T removeHead() { + if (head < 0) + throw new NoSuchElementException(); + return (T) contents[head--]; + } + + /** + * Pushes a new element from the stash onto the stack. If the stack is + * already full throws an {@link IllegalStateException}. The state of the + * new element is not specified. + * + * @return the new head + */ + public T push() { + if (head == contents.length - 1) { + throw new IllegalStateException(); + } + + return (T) contents[++head]; + } + + /** + * Pushes the specified element onto the stack. A stashed element is + * removed. If the stack is already full throws an + * {@link IllegalStateException}. + * + * @param newElement the element to push + * @return the new head + */ + public T push(T newElement) { + if (head == contents.length - 1) { + throw new IllegalStateException(); + } + + contents[++head] = newElement; + return newElement; + } + + /** + * Returns the specified element from the stack. Indexing starts from the + * bottom of the stack. If the index is out of bounds, an + * {@link IndexOutOfBoundsException} is thrown. + * + * @param index index of the element to retrieve, + * [0; {@link #getSize()}) + * @return the requested element + * @throws IndexOutOfBoundsException if the index is negative or greater + * than head + */ + public T get(int index) { + if (index > head) { + throw new IndexOutOfBoundsException( + "Requested index " + index + " > head " + head + ); + } + + return (T) contents[index]; + } + + /** + * Removes all elements from the stack. + */ + public void removeAll() { + head = -1; + } + + @Override + public Iterator iterator() { + if (contentsAsList == null) { + contentsAsList = Arrays.asList((T[]) contents); + } + + return contentsAsList.subList(0, getSize()).iterator(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java b/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java index b6d030c..a081356 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java +++ b/src/main/java/ru/windcorp/progressia/common/util/TaskQueue.java @@ -1,126 +1,127 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BooleanSupplier; - -import ru.windcorp.jputil.functions.ThrowingRunnable; - -public class TaskQueue { - - private final Queue queue = new ConcurrentLinkedQueue<>(); - private final Collection repeating = new ConcurrentLinkedQueue<>(); - - private final BooleanSupplier runNow; - - public TaskQueue(BooleanSupplier runNow) { - this.runNow = runNow; - } - - public void schedule(Runnable task) { - repeating.add(task); - } - - public void removeScheduled(Runnable task) { - repeating.remove(task); - } - - public void invokeLater(Runnable task) { - queue.add(task); - } - - public void invokeNow(Runnable task) { - if (runNow.getAsBoolean()) { - task.run(); - } else { - invokeLater(task); - } - } - - private final Object waitAndInvokeMonitor = new Object(); - - @SuppressWarnings("unchecked") - public void waitAndInvoke( - ThrowingRunnable task - ) throws InterruptedException, E { - - if (runNow.getAsBoolean()) { - task.run(); - return; - } - - final AtomicBoolean flag = - new AtomicBoolean(false); - final AtomicReference thrownContainer = - new AtomicReference<>(null); - - invokeLater(() -> { - - try { - task.run(); - } catch (Throwable t) { - thrownContainer.set(t); - } - - flag.set(true); - - synchronized (waitAndInvokeMonitor) { - waitAndInvokeMonitor.notifyAll(); - } - }); - - while (!flag.get()) { - synchronized (waitAndInvokeMonitor) { - waitAndInvokeMonitor.wait(); - } - } - - Throwable thrown = thrownContainer.get(); - if (thrown != null) { - if (thrown instanceof RuntimeException) { - throw (RuntimeException) thrown; - } - - if (thrown instanceof Error) { - throw (Error) thrown; - } - - throw (E) thrown; // Guaranteed - } - } - - public void runTasks() { - Iterator tasks = queue.iterator(); - - while (tasks.hasNext()) { - tasks.next().run(); - tasks.remove(); - } - - for (Runnable task : repeating) { - task.run(); - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BooleanSupplier; + +import ru.windcorp.jputil.functions.ThrowingRunnable; + +public class TaskQueue { + + private final Queue queue = new ConcurrentLinkedQueue<>(); + private final Collection repeating = new ConcurrentLinkedQueue<>(); + + private final BooleanSupplier runNow; + + public TaskQueue(BooleanSupplier runNow) { + this.runNow = runNow; + } + + public void schedule(Runnable task) { + repeating.add(task); + } + + public void removeScheduled(Runnable task) { + repeating.remove(task); + } + + public void invokeLater(Runnable task) { + queue.add(task); + } + + public void invokeNow(Runnable task) { + if (runNow.getAsBoolean()) { + task.run(); + } else { + invokeLater(task); + } + } + + private final Object waitAndInvokeMonitor = new Object(); + + @SuppressWarnings("unchecked") + public void waitAndInvoke( + ThrowingRunnable task + ) + throws InterruptedException, + E { + + if (runNow.getAsBoolean()) { + task.run(); + return; + } + + final AtomicBoolean flag = new AtomicBoolean(false); + final AtomicReference thrownContainer = new AtomicReference<>(null); + + invokeLater(() -> { + + try { + task.run(); + } catch (Throwable t) { + thrownContainer.set(t); + } + + flag.set(true); + + synchronized (waitAndInvokeMonitor) { + waitAndInvokeMonitor.notifyAll(); + } + }); + + while (!flag.get()) { + synchronized (waitAndInvokeMonitor) { + waitAndInvokeMonitor.wait(); + } + } + + Throwable thrown = thrownContainer.get(); + if (thrown != null) { + if (thrown instanceof RuntimeException) { + throw (RuntimeException) thrown; + } + + if (thrown instanceof Error) { + throw (Error) thrown; + } + + throw (E) thrown; // Guaranteed + } + } + + public void runTasks() { + Iterator tasks = queue.iterator(); + + while (tasks.hasNext()) { + tasks.next().run(); + tasks.remove(); + } + + for (Runnable task : repeating) { + task.run(); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java index 4e7ac70..00ede3e 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/VectorUtil.java @@ -1,311 +1,451 @@ -package ru.windcorp.progressia.common.util; - -import java.util.function.Consumer; - -import glm.mat._4.Mat4; -import glm.vec._2.Vec2; -import glm.vec._2.d.Vec2d; -import glm.vec._2.i.Vec2i; -import glm.vec._3.Vec3; -import glm.vec._3.d.Vec3d; -import glm.vec._3.i.Vec3i; -import glm.vec._4.Vec4; -import glm.vec._4.d.Vec4d; -import glm.vec._4.i.Vec4i; - -public class VectorUtil { - - public static enum Axis { - X, Y, Z, W; - } - - public static void iterateCuboid( - int x0, int y0, int z0, - int x1, int y1, int z1, - Consumer action - ) { - Vec3i cursor = Vectors.grab3i(); - - for (int x = x0; x < x1; ++x) { - for (int y = y0; y < y1; ++y) { - for (int z = z0; z < z1; ++z) { - cursor.set(x, y, z); - action.accept(cursor); - } - } - } - - Vectors.release(cursor); - } - - public static void iterateCuboid( - Vec3i vMin, Vec3i vMax, - Consumer action - ) { - iterateCuboid(vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z, action); - } - - public static void iterateCuboidAround( - int cx, int cy, int cz, - int dx, int dy, int dz, - Consumer action - ) { - if (dx < 0) throw new IllegalArgumentException("dx " + dx + " is negative"); - if (dy < 0) throw new IllegalArgumentException("dy " + dx + " is negative"); - if (dz < 0) throw new IllegalArgumentException("dz " + dx + " is negative"); - - if (dx % 2 == 0) throw new IllegalArgumentException("dx " + dx + " is even, only odd accepted"); - if (dy % 2 == 0) throw new IllegalArgumentException("dy " + dy + " is even, only odd accepted"); - if (dz % 2 == 0) throw new IllegalArgumentException("dz " + dz + " is even, only odd accepted"); - - dx /= 2; - dy /= 2; - dz /= 2; - - iterateCuboid(cx - dx, cy - dy, cz - dz, cx + dx + 1, cy + dy + 1, cz + dz + 1, action); - } - - public static void iterateCuboidAround( - Vec3i center, - Vec3i diameters, - Consumer action - ) { - iterateCuboidAround(center.x, center.y, center.z, diameters.x, diameters.y, diameters.z, action); - } - - public static void iterateCuboidAround( - int cx, int cy, int cz, - int diameter, - Consumer action - ) { - iterateCuboidAround(cx, cy, cz, diameter, diameter, diameter, action); - } - - public static void iterateCuboidAround( - Vec3i center, - int diameter, - Consumer action - ) { - iterateCuboidAround(center.x, center.y, center.z, diameter, action); - } - - public static void applyMat4(Vec3 in, Mat4 mat, Vec3 out) { - Vec4 vec4 = Vectors.grab4(); - vec4.set(in, 1f); - - mat.mul(vec4); - - out.set(vec4.x, vec4.y, vec4.z); - Vectors.release(vec4); - } - - public static void applyMat4(Vec3 inOut, Mat4 mat) { - Vec4 vec4 = Vectors.grab4(); - vec4.set(inOut, 1f); - - mat.mul(vec4); - - inOut.set(vec4.x, vec4.y, vec4.z); - } - - public static Vec3 linearCombination( - Vec3 va, float ka, - Vec3 vb, float kb, - Vec3 output - ) { - output.set( - va.x * ka + vb.x * kb, - va.y * ka + vb.y * kb, - va.z * ka + vb.z * kb - ); - return output; - } - - public static Vec3 linearCombination( - Vec3 va, float ka, - Vec3 vb, float kb, - Vec3 vc, float kc, - Vec3 output - ) { - output.set( - va.x * ka + vb.x * kb + vc.x * kc, - va.y * ka + vb.y * kb + vc.y * kc, - va.z * ka + vb.z * kb + vc.z * kc - ); - return output; - } - - public static float get(Vec2 v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - default: throw new IllegalArgumentException("Vec2 does not have axis " + a); - } - } - - public static Vec2 set(Vec2 v, Axis a, float value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - default: throw new IllegalArgumentException("Vec2 does not have axis " + a); - } - return v; - } - - public static int get(Vec2i v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - default: throw new IllegalArgumentException("Vec2i does not have axis " + a); - } - } - - public static Vec2i set(Vec2i v, Axis a, int value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - default: throw new IllegalArgumentException("Vec2i does not have axis " + a); - } - return v; - } - - public static double get(Vec2d v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - default: throw new IllegalArgumentException("Vec2d does not have axis " + a); - } - } - - public static Vec2d set(Vec2d v, Axis a, double value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - default: throw new IllegalArgumentException("Vec2d does not have axis " + a); - } - return v; - } - - public static float get(Vec3 v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - default: throw new IllegalArgumentException("Vec3 does not have axis " + a); - } - } - - public static Vec3 set(Vec3 v, Axis a, float value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - default: throw new IllegalArgumentException("Vec3 does not have axis " + a); - } - return v; - } - - public static int get(Vec3i v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - default: throw new IllegalArgumentException("Vec3i does not have axis " + a); - } - } - - public static Vec3i set(Vec3i v, Axis a, int value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - default: throw new IllegalArgumentException("Vec3i does not have axis " + a); - } - return v; - } - - public static double get(Vec3d v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - default: throw new IllegalArgumentException("Vec3d does not have axis " + a); - } - } - - public static Vec3d set(Vec3d v, Axis a, double value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - default: throw new IllegalArgumentException("Vec3d does not have axis " + a); - } - return v; - } - - public static float get(Vec4 v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - case W: return v.w; - default: throw new IllegalArgumentException("Vec4 does not have axis " + a); - } - } - - public static Vec4 set(Vec4 v, Axis a, float value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - case W: v.w = value; break; - default: throw new IllegalArgumentException("Vec4 does not have axis " + a); - } - return v; - } - - public static int get(Vec4i v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - case W: return v.w; - default: throw new IllegalArgumentException("Vec4i does not have axis " + a); - } - } - - public static Vec4i set(Vec4i v, Axis a, int value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - case W: v.w = value; break; - default: throw new IllegalArgumentException("Vec4i does not have axis " + a); - } - return v; - } - - public static double get(Vec4d v, Axis a) { - switch (a) { - case X: return v.x; - case Y: return v.y; - case Z: return v.z; - case W: return v.w; - default: throw new IllegalArgumentException("Vec4d does not have axis " + a); - } - } - - public static Vec4d set(Vec4d v, Axis a, double value) { - switch (a) { - case X: v.x = value; break; - case Y: v.y = value; break; - case Z: v.z = value; break; - case W: v.w = value; break; - default: throw new IllegalArgumentException("Vec4d does not have axis " + a); - } - return v; - } - - private VectorUtil() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import java.util.function.Consumer; + +import glm.mat._4.Mat4; +import glm.vec._2.Vec2; +import glm.vec._2.d.Vec2d; +import glm.vec._2.i.Vec2i; +import glm.vec._3.Vec3; +import glm.vec._3.d.Vec3d; +import glm.vec._3.i.Vec3i; +import glm.vec._4.Vec4; +import glm.vec._4.d.Vec4d; +import glm.vec._4.i.Vec4i; + +public class VectorUtil { + + public static enum Axis { + X, Y, Z, W; + } + + public static void iterateCuboid( + int x0, + int y0, + int z0, + int x1, + int y1, + int z1, + Consumer action + ) { + Vec3i cursor = Vectors.grab3i(); + + for (int x = x0; x < x1; ++x) { + for (int y = y0; y < y1; ++y) { + for (int z = z0; z < z1; ++z) { + cursor.set(x, y, z); + action.accept(cursor); + } + } + } + + Vectors.release(cursor); + } + + public static void iterateCuboid( + Vec3i vMin, + Vec3i vMax, + Consumer action + ) { + iterateCuboid(vMin.x, vMin.y, vMin.z, vMax.x, vMax.y, vMax.z, action); + } + + public static void iterateCuboidAround( + int cx, + int cy, + int cz, + int dx, + int dy, + int dz, + Consumer action + ) { + if (dx < 0) + throw new IllegalArgumentException("dx " + dx + " is negative"); + if (dy < 0) + throw new IllegalArgumentException("dy " + dx + " is negative"); + if (dz < 0) + throw new IllegalArgumentException("dz " + dx + " is negative"); + + if (dx % 2 == 0) + throw new IllegalArgumentException("dx " + dx + " is even, only odd accepted"); + if (dy % 2 == 0) + throw new IllegalArgumentException("dy " + dy + " is even, only odd accepted"); + if (dz % 2 == 0) + throw new IllegalArgumentException("dz " + dz + " is even, only odd accepted"); + + dx /= 2; + dy /= 2; + dz /= 2; + + iterateCuboid(cx - dx, cy - dy, cz - dz, cx + dx + 1, cy + dy + 1, cz + dz + 1, action); + } + + public static void iterateCuboidAround( + Vec3i center, + Vec3i diameters, + Consumer action + ) { + iterateCuboidAround(center.x, center.y, center.z, diameters.x, diameters.y, diameters.z, action); + } + + public static void iterateCuboidAround( + int cx, + int cy, + int cz, + int diameter, + Consumer action + ) { + iterateCuboidAround(cx, cy, cz, diameter, diameter, diameter, action); + } + + public static void iterateCuboidAround( + Vec3i center, + int diameter, + Consumer action + ) { + iterateCuboidAround(center.x, center.y, center.z, diameter, action); + } + + public static void applyMat4(Vec3 in, Mat4 mat, Vec3 out) { + Vec4 vec4 = Vectors.grab4(); + vec4.set(in, 1f); + + mat.mul(vec4); + + out.set(vec4.x, vec4.y, vec4.z); + Vectors.release(vec4); + } + + public static void applyMat4(Vec3 inOut, Mat4 mat) { + Vec4 vec4 = Vectors.grab4(); + vec4.set(inOut, 1f); + + mat.mul(vec4); + + inOut.set(vec4.x, vec4.y, vec4.z); + } + + public static Vec3 linearCombination( + Vec3 va, + float ka, + Vec3 vb, + float kb, + Vec3 output + ) { + output.set( + va.x * ka + vb.x * kb, + va.y * ka + vb.y * kb, + va.z * ka + vb.z * kb + ); + return output; + } + + public static Vec3 linearCombination( + Vec3 va, + float ka, + Vec3 vb, + float kb, + Vec3 vc, + float kc, + Vec3 output + ) { + output.set( + va.x * ka + vb.x * kb + vc.x * kc, + va.y * ka + vb.y * kb + vc.y * kc, + va.z * ka + vb.z * kb + vc.z * kc + ); + return output; + } + + public static float get(Vec2 v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + default: + throw new IllegalArgumentException("Vec2 does not have axis " + a); + } + } + + public static Vec2 set(Vec2 v, Axis a, float value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + default: + throw new IllegalArgumentException("Vec2 does not have axis " + a); + } + return v; + } + + public static int get(Vec2i v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + default: + throw new IllegalArgumentException("Vec2i does not have axis " + a); + } + } + + public static Vec2i set(Vec2i v, Axis a, int value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + default: + throw new IllegalArgumentException("Vec2i does not have axis " + a); + } + return v; + } + + public static double get(Vec2d v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + default: + throw new IllegalArgumentException("Vec2d does not have axis " + a); + } + } + + public static Vec2d set(Vec2d v, Axis a, double value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + default: + throw new IllegalArgumentException("Vec2d does not have axis " + a); + } + return v; + } + + public static float get(Vec3 v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + default: + throw new IllegalArgumentException("Vec3 does not have axis " + a); + } + } + + public static Vec3 set(Vec3 v, Axis a, float value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + default: + throw new IllegalArgumentException("Vec3 does not have axis " + a); + } + return v; + } + + public static int get(Vec3i v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + default: + throw new IllegalArgumentException("Vec3i does not have axis " + a); + } + } + + public static Vec3i set(Vec3i v, Axis a, int value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + default: + throw new IllegalArgumentException("Vec3i does not have axis " + a); + } + return v; + } + + public static double get(Vec3d v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + default: + throw new IllegalArgumentException("Vec3d does not have axis " + a); + } + } + + public static Vec3d set(Vec3d v, Axis a, double value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + default: + throw new IllegalArgumentException("Vec3d does not have axis " + a); + } + return v; + } + + public static float get(Vec4 v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + case W: + return v.w; + default: + throw new IllegalArgumentException("Vec4 does not have axis " + a); + } + } + + public static Vec4 set(Vec4 v, Axis a, float value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + case W: + v.w = value; + break; + default: + throw new IllegalArgumentException("Vec4 does not have axis " + a); + } + return v; + } + + public static int get(Vec4i v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + case W: + return v.w; + default: + throw new IllegalArgumentException("Vec4i does not have axis " + a); + } + } + + public static Vec4i set(Vec4i v, Axis a, int value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + case W: + v.w = value; + break; + default: + throw new IllegalArgumentException("Vec4i does not have axis " + a); + } + return v; + } + + public static double get(Vec4d v, Axis a) { + switch (a) { + case X: + return v.x; + case Y: + return v.y; + case Z: + return v.z; + case W: + return v.w; + default: + throw new IllegalArgumentException("Vec4d does not have axis " + a); + } + } + + public static Vec4d set(Vec4d v, Axis a, double value) { + switch (a) { + case X: + v.x = value; + break; + case Y: + v.y = value; + break; + case Z: + v.z = value; + break; + case W: + v.w = value; + break; + default: + throw new IllegalArgumentException("Vec4d does not have axis " + a); + } + return v; + } + + private VectorUtil() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java index 355827e..7d99ea5 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/Vectors.java +++ b/src/main/java/ru/windcorp/progressia/common/util/Vectors.java @@ -1,113 +1,128 @@ -package ru.windcorp.progressia.common.util; - -import glm.vec._2.Vec2; -import glm.vec._2.i.Vec2i; -import glm.vec._3.Vec3; -import glm.vec._3.i.Vec3i; -import glm.vec._4.Vec4; -import glm.vec._4.i.Vec4i; - -/** - * A set of caches for GLM vector objects. - *

- * All {@code grab}bed objects must be {@code release}d as soon as possible. - * Ideally, user code should be: - *

- * Vec3 myVector = Vectors.grab3();
- * try {
- *     // use myVector
- * } finally {
- *     Vectors.release(myVector);
- * }
- * 
- * Provided objects may be reused after {@code release} has been invoked; - * do not store them. - *

- * This class is thread- and recursion-safe. - * - * @see Matrices - */ -public class Vectors { - - public static final Vec2 ZERO_2 = new Vec2 (0, 0); - public static final Vec2i ZERO_2i = new Vec2i(0, 0); - public static final Vec3 ZERO_3 = new Vec3 (0, 0, 0); - public static final Vec3i ZERO_3i = new Vec3i(0, 0, 0); - public static final Vec4 ZERO_4 = new Vec4 (0, 0, 0, 0); - public static final Vec4i ZERO_4i = new Vec4i(0, 0, 0, 0); - public static final Vec2 UNIT_2 = new Vec2 (1, 1); - public static final Vec2i UNIT_2i = new Vec2i(1, 1); - public static final Vec3 UNIT_3 = new Vec3 (1, 1, 1); - public static final Vec3i UNIT_3i = new Vec3i(1, 1, 1); - public static final Vec4 UNIT_4 = new Vec4 (1, 1, 1, 1); - public static final Vec4i UNIT_4i = new Vec4i(1, 1, 1, 1); - - private static final LowOverheadCache VEC3IS = - new LowOverheadCache<>(Vec3i::new); - - public static Vec3i grab3i() { - return VEC3IS.grab(); - } - - public static void release(Vec3i v) { - VEC3IS.release(v); - } - - private static final LowOverheadCache VEC3S = - new LowOverheadCache<>(Vec3::new); - - public static Vec3 grab3() { - return VEC3S.grab(); - } - - public static void release(Vec3 v) { - VEC3S.release(v); - } - - private static final LowOverheadCache VEC2IS = - new LowOverheadCache<>(Vec2i::new); - - public static Vec2i grab2i() { - return VEC2IS.grab(); - } - - public static void release(Vec2i v) { - VEC2IS.release(v); - } - - private static final LowOverheadCache VEC2S = - new LowOverheadCache<>(Vec2::new); - - public static Vec2 grab2() { - return VEC2S.grab(); - } - - public static void release(Vec2 v) { - VEC2S.release(v); - } - - private static final LowOverheadCache VEC4IS = - new LowOverheadCache<>(Vec4i::new); - - public static Vec4i grab4i() { - return VEC4IS.grab(); - } - - public static void release(Vec4i v) { - VEC4IS.release(v); - } - - private static final LowOverheadCache VEC4S = - new LowOverheadCache<>(Vec4::new); - - public static Vec4 grab4() { - return VEC4S.grab(); - } - - public static void release(Vec4 v) { - VEC4S.release(v); - } - - private Vectors() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util; + +import glm.vec._2.Vec2; +import glm.vec._2.i.Vec2i; +import glm.vec._3.Vec3; +import glm.vec._3.i.Vec3i; +import glm.vec._4.Vec4; +import glm.vec._4.i.Vec4i; + +/** + * A set of caches for GLM vector objects. + *

+ * All {@code grab}bed objects must be {@code release}d as soon as possible. + * Ideally, user code should be: + * + *

+ * Vec3 myVector = Vectors.grab3();
+ * try {
+ * 	// use myVector
+ * } finally {
+ * 	Vectors.release(myVector);
+ * }
+ * 
+ * + * Provided objects may be reused after {@code release} has been invoked; + * do not store them. + *

+ * This class is thread- and recursion-safe. + * + * @see Matrices + */ +public class Vectors { + + public static final Vec2 ZERO_2 = new Vec2(0, 0); + public static final Vec2i ZERO_2i = new Vec2i(0, 0); + public static final Vec3 ZERO_3 = new Vec3(0, 0, 0); + public static final Vec3i ZERO_3i = new Vec3i(0, 0, 0); + public static final Vec4 ZERO_4 = new Vec4(0, 0, 0, 0); + public static final Vec4i ZERO_4i = new Vec4i(0, 0, 0, 0); + public static final Vec2 UNIT_2 = new Vec2(1, 1); + public static final Vec2i UNIT_2i = new Vec2i(1, 1); + public static final Vec3 UNIT_3 = new Vec3(1, 1, 1); + public static final Vec3i UNIT_3i = new Vec3i(1, 1, 1); + public static final Vec4 UNIT_4 = new Vec4(1, 1, 1, 1); + public static final Vec4i UNIT_4i = new Vec4i(1, 1, 1, 1); + + private static final LowOverheadCache VEC3IS = new LowOverheadCache<>(Vec3i::new); + + public static Vec3i grab3i() { + return VEC3IS.grab(); + } + + public static void release(Vec3i v) { + VEC3IS.release(v); + } + + private static final LowOverheadCache VEC3S = new LowOverheadCache<>(Vec3::new); + + public static Vec3 grab3() { + return VEC3S.grab(); + } + + public static void release(Vec3 v) { + VEC3S.release(v); + } + + private static final LowOverheadCache VEC2IS = new LowOverheadCache<>(Vec2i::new); + + public static Vec2i grab2i() { + return VEC2IS.grab(); + } + + public static void release(Vec2i v) { + VEC2IS.release(v); + } + + private static final LowOverheadCache VEC2S = new LowOverheadCache<>(Vec2::new); + + public static Vec2 grab2() { + return VEC2S.grab(); + } + + public static void release(Vec2 v) { + VEC2S.release(v); + } + + private static final LowOverheadCache VEC4IS = new LowOverheadCache<>(Vec4i::new); + + public static Vec4i grab4i() { + return VEC4IS.grab(); + } + + public static void release(Vec4i v) { + VEC4IS.release(v); + } + + private static final LowOverheadCache VEC4S = new LowOverheadCache<>(Vec4::new); + + public static Vec4 grab4() { + return VEC4S.grab(); + } + + public static void release(Vec4 v) { + VEC4S.release(v); + } + + private Vectors() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java index df9bdcd..3289c3d 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/Analyzer.java @@ -1,32 +1,56 @@ -package ru.windcorp.progressia.common.util.crash; - -/** - * A crash report utility that performs analysis of a problem during crash - * report generation and presents its conclusion to the user via the crash report. - * Unlike {@link ContextProvider}s, Analyzers are provided with the reported problem - * details. - * @see ContextProvider - * @author serega404 - */ -public interface Analyzer { - - /** - * Provides a human-readable string describing this analyzer's conclusion - * on the presented problem, or returns {@code null} if no conclusion - * could be made. - * @param throwable The reported throwable (may be {@code null}) - * @param messageFormat A {@linkplain java.util.Formatter#syntax format string} of a - * human-readable description of the problem - * @param args The arguments for the format string - * @return a conclusion or {@code null} - */ - String analyze(Throwable throwable, String messageFormat, Object... args); - - /** - * Returns this analyzer's human-readable name. - * It should be A String In Title Case With Spaces. - * @return this analyzer's name - */ - String getName(); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.crash; + +/** + * A crash report utility that performs analysis of a problem during crash + * report generation and presents its conclusion to the user via the crash + * report. + * Unlike {@link ContextProvider}s, Analyzers are provided with the reported + * problem + * details. + * + * @see ContextProvider + * @author serega404 + */ +public interface Analyzer { + + /** + * Provides a human-readable string describing this analyzer's conclusion + * on the presented problem, or returns {@code null} if no conclusion + * could be made. + * + * @param throwable The reported throwable (may be {@code null}) + * @param messageFormat A {@linkplain java.util.Formatter#syntax format + * string} of a + * human-readable description of the problem + * @param args The arguments for the format string + * @return a conclusion or {@code null} + */ + String analyze(Throwable throwable, String messageFormat, Object... args); + + /** + * Returns this analyzer's human-readable name. + * It should be A String In Title Case With Spaces. + * + * @return this analyzer's name + */ + String getName(); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java index 7938c2a..5b62663 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ContextProvider.java @@ -1,31 +1,57 @@ -package ru.windcorp.progressia.common.util.crash; - -import java.util.Map; - -/** - * A crash report utility that gathers information about game and system state - * when a crash occurs and presents it to the user via the crash report. - * ContextProviders are not aware of the nature of the problem, unlike {@link Analyzer}s. - * @see Analyzer - * @author serega404 - */ -public interface ContextProvider { - - /** - * Provides human-readable description of the state of the game and the system. - * This information is {@link Map#put(Object, Object) put} into the provided map - * as key-value pairs. Keys are the characteristic being described, such as "OS Name", - * and should be Strings In Title Case With Spaces. - * If this provider cannot provide any information at this moment, the map is not - * modified. - * @param output the map to append output to - */ - void provideContext(Map output); - - /** - * Returns this provider's human-readable name. - * It should be A String In Title Case With Spaces. - * @return this provider's name - */ - String getName(); -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.crash; + +import java.util.Map; + +/** + * A crash report utility that gathers information about game and system state + * when a crash occurs and presents it to the user via the crash report. + * ContextProviders are not aware of the nature of the problem, unlike + * {@link Analyzer}s. + * + * @see Analyzer + * @author serega404 + */ +public interface ContextProvider { + + /** + * Provides human-readable description of the state of the game and the + * system. + * This information is {@link Map#put(Object, Object) put} into the provided + * map + * as key-value pairs. Keys are the characteristic being described, such as + * "OS Name", + * and should be Strings In Title Case With Spaces. + * If this provider cannot provide any information at this moment, the map + * is not + * modified. + * + * @param output the map to append output to + */ + void provideContext(Map output); + + /** + * Returns this provider's human-readable name. + * It should be A String In Title Case With Spaces. + * + * @return this provider's name + */ + String getName(); +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java index 6b12468..f33d4c5 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/CrashReports.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash; import org.apache.logging.log4j.LogManager; @@ -19,356 +37,398 @@ import java.text.SimpleDateFormat; import java.util.*; /** - * A utility for reporting critical problems, gathering system context and terminating the application consequently (crashing). - * Do not hesitate to use {@link #report(Throwable, String, Object...)} at every other line. + * A utility for reporting critical problems, gathering system context and + * terminating the application consequently (crashing). + * Do not hesitate to use {@link #report(Throwable, String, Object...)} at every + * other line. * * @author serega404 */ public class CrashReports { - private static final Path CRASH_REPORTS_PATH = Paths.get("crash-reports"); + private static final Path CRASH_REPORTS_PATH = Paths.get("crash-reports"); - private static final Collection PROVIDERS = Collections.synchronizedCollection(new ArrayList<>()); + private static final Collection PROVIDERS = Collections.synchronizedCollection(new ArrayList<>()); - private static final Collection ANALYZERS = Collections.synchronizedCollection(new ArrayList<>()); + private static final Collection ANALYZERS = Collections.synchronizedCollection(new ArrayList<>()); - private static final Logger LOGGER = LogManager.getLogger("crash"); - - /** - * Creates a {@link ReportedException} that describes the provided problem so the program can crash later. - * This method is intended to be used like so: - * - *

-     * try {
-     *     doSomethingDifficult(x);
-     * } catch (CouldntMakeItException e) {
-     *     throw CrashReports.report(e, "We couldn't make it at x = %d", x);
-     * }
-     * 
- * - *

Such usage ensures that the report will be dealt with at the top of the call stack - * (at least in methods that have a properly set up - * {@linkplain #crash(Throwable, String, Object...) crash handler}). Not throwing the returned - * exception is pointless; using this in a thread without a crash handler will not produce a crash. - * - *

Avoid inserting variable information into {@code messageFormat} directly; use - * {@linkplain Formatter#summary format string} syntax and {@code args}. Different Strings - * in {@code messageFormat} may be interpreted as unrelated problems by {@linkplain Analyzer crash analyzers}. - * - * @param throwable a {@link Throwable} that caused the problem, if any; {@code null} otherwise - * @param messageFormat a human-readable description of the problem displayed in the crash report - * @param args an array of arguments for formatting {@code messageFormat} - * @return an exception containing the provided information that must be thrown - */ - public static ReportedException report(Throwable throwable, String messageFormat, Object... args) { - if (throwable instanceof ReportedException) return (ReportedException) throwable; + private static final Logger LOGGER = LogManager.getLogger("crash"); - return new ReportedException(throwable, messageFormat, args); - } + /** + * Creates a {@link ReportedException} that describes the provided problem + * so the program can crash later. + * This method is intended to be used like so: + * + *

+	 * try {
+	 * 	doSomethingDifficult(x);
+	 * } catch (CouldntMakeItException e) {
+	 * 	throw CrashReports.report(e, "We couldn't make it at x = %d", x);
+	 * }
+	 * 
+ *

+ * Such usage ensures that the report will be dealt with at the top of the + * call stack + * (at least in methods that have a properly set up + * {@linkplain #crash(Throwable, String, Object...) crash handler}). Not + * throwing the returned + * exception is pointless; using this in a thread without a crash handler + * will not produce a crash. + *

+ * Avoid inserting variable information into {@code messageFormat} directly; + * use + * {@linkplain Formatter#summary format string} syntax and {@code args}. + * Different Strings + * in {@code messageFormat} may be interpreted as unrelated problems by + * {@linkplain Analyzer crash analyzers}. + * + * @param throwable a {@link Throwable} that caused the problem, if any; + * {@code null} otherwise + * @param messageFormat a human-readable description of the problem + * displayed in the crash report + * @param args an array of arguments for formatting + * {@code messageFormat} + * @return an exception containing the provided information that must be + * thrown + */ + public static ReportedException report(Throwable throwable, String messageFormat, Object... args) { + if (throwable instanceof ReportedException) + return (ReportedException) throwable; - /** - * Crashes the program due to the supplied problem. - * - *

Use {@link #report(Throwable, String, Object...)} unless you are creating a catch-all handler for a - * thread. - * - *

This method recovers information about the problem by casting {@code throwable} to {@link ReportedException}, - * or, failing that, uses the provided arguments as the information instead. It then constructs a full crash - * report, exports it and terminates the program by invoking {@link System#exit(int)}. - * - *

Such behavior can be dangerous or lead to unwanted consequences in the middle of the call stack, so it is - * necessary to invoke this method as high on the call stack as possible, usually in a {@code catch} clause - * of a {@code try} statement enveloping the thread's main method(s). - * - * @param throwable a {@link ReportedException} or another {@link Throwable} that caused the problem, if any; - * {@code null} otherwise - * @param messageFormat a human-readable description of the problem used when {@code throwable} is not a - * {@link ReportedException}. See {@link #report(Throwable, String, Object...)} for details. - * @param args an array of arguments for formatting {@code messageFormat} - * @return {@code null}, although this method never returns normally. Provided for convenience. - */ - public static RuntimeException crash(Throwable throwable, String messageFormat, Object... args) { - final StackTraceElement[] reportStackTrace; - - if (throwable instanceof ReportedException) { - ReportedException reportedException = (ReportedException) throwable; - - // Discard provided arguments - throwable = reportedException.getCause(); - messageFormat = reportedException.getMessageFormat(); - args = reportedException.getArgs(); - - reportStackTrace = reportedException.getStackTrace(); - } else { - reportStackTrace = getCurrentStackTrace(); - } + return new ReportedException(throwable, messageFormat, args); + } - StringBuilder output = new StringBuilder(); + /** + * Crashes the program due to the supplied problem. + *

+ * Use {@link #report(Throwable, String, Object...)} unless you are + * creating a catch-all handler for a + * thread. + *

+ * This method recovers information about the problem by casting + * {@code throwable} to {@link ReportedException}, + * or, failing that, uses the provided arguments as the information instead. + * It then constructs a full crash + * report, exports it and terminates the program by invoking + * {@link System#exit(int)}. + *

+ * Such behavior can be dangerous or lead to unwanted consequences in the + * middle of the call stack, so it is + * necessary to invoke this method as high on the call stack as possible, + * usually in a {@code catch} clause + * of a {@code try} statement enveloping the thread's main method(s). + * + * @param throwable a {@link ReportedException} or another + * {@link Throwable} that caused the problem, if any; + * {@code null} otherwise + * @param messageFormat a human-readable description of the problem used + * when {@code throwable} is not a + * {@link ReportedException}. See + * {@link #report(Throwable, String, Object...)} for + * details. + * @param args an array of arguments for formatting + * {@code messageFormat} + * @return {@code null}, although this method never returns normally. + * Provided for convenience. + */ + public static RuntimeException crash(Throwable throwable, String messageFormat, Object... args) { + final StackTraceElement[] reportStackTrace; - try { - String.format(messageFormat, args); - } catch (IllegalFormatException e) { - messageFormat = StringUtil.replaceAll(messageFormat, "%", "%%"); + if (throwable instanceof ReportedException) { + ReportedException reportedException = (ReportedException) throwable; - if (args.length != 0) { - messageFormat += "\nArgs:"; - for (Object arg : args) { - try { - messageFormat += " \"" + arg.toString() + "\""; - } catch (Throwable t) { - messageFormat += " exc: \"" + t.getClass().toString() + "\""; - } - } - args = new Object[0]; // clear args - } + // Discard provided arguments + throwable = reportedException.getCause(); + messageFormat = reportedException.getMessageFormat(); + args = reportedException.getArgs(); - messageFormat += "\nCould not format provided description"; - } + reportStackTrace = reportedException.getStackTrace(); + } else { + reportStackTrace = getCurrentStackTrace(); + } - appendContextProviders(output); - addSeparator(output); - if (appendAnalyzers(output, throwable, messageFormat, args)) { - addSeparator(output); - } + StringBuilder output = new StringBuilder(); - appendMessageFormat(output, messageFormat, args); + try { + String.format(messageFormat, args); + } catch (IllegalFormatException e) { + messageFormat = StringUtil.replaceAll(messageFormat, "%", "%%"); - appendStackTrace(output, reportStackTrace, "Reported at:"); - output.append('\n'); - appendThrowable(output, throwable); + if (args.length != 0) { + messageFormat += "\nArgs:"; + for (Object arg : args) { + try { + messageFormat += " \"" + arg.toString() + "\""; + } catch (Throwable t) { + messageFormat += " exc: \"" + t.getClass().toString() + "\""; + } + } + args = new Object[0]; // clear args + } - export(output.toString()); + messageFormat += "\nCould not format provided description"; + } - System.exit(0); - return null; - } + appendContextProviders(output); + addSeparator(output); + if (appendAnalyzers(output, throwable, messageFormat, args)) { + addSeparator(output); + } - private static StackTraceElement[] getCurrentStackTrace() { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - final int trim = 3; - - return Arrays.copyOfRange(stackTrace, trim, stackTrace.length); + appendMessageFormat(output, messageFormat, args); + + appendStackTrace(output, reportStackTrace, "Reported at:"); + output.append('\n'); + appendThrowable(output, throwable); + + export(output.toString()); + + System.exit(0); + return null; + } + + private static StackTraceElement[] getCurrentStackTrace() { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + final int trim = 3; + + return Arrays.copyOfRange(stackTrace, trim, stackTrace.length); } private static void appendContextProviders(StringBuilder output) { - // Do a local copy to avoid deadlocks -OLEGSHA - ContextProvider[] localProvidersCopy = PROVIDERS.toArray(new ContextProvider[PROVIDERS.size()]); + // Do a local copy to avoid deadlocks -OLEGSHA + ContextProvider[] localProvidersCopy = PROVIDERS.toArray(new ContextProvider[PROVIDERS.size()]); - for (ContextProvider provider : localProvidersCopy) { - if (provider == null) - continue; + for (ContextProvider provider : localProvidersCopy) { + if (provider == null) + continue; - addSeparator(output); + addSeparator(output); - try { - Map buf = new HashMap<>(); - provider.provideContext(buf); + try { + Map buf = new HashMap<>(); + provider.provideContext(buf); - if (!buf.isEmpty()) { - output.append(StringUtil.center(provider.getName(), 80)).append("\n"); - for (Map.Entry entry : buf.entrySet()) { - output.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); - } - } - } catch (Throwable t) { - String providerName; + if (!buf.isEmpty()) { + output.append(StringUtil.center(provider.getName(), 80)).append("\n"); + for (Map.Entry entry : buf.entrySet()) { + output.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n"); + } + } + } catch (Throwable t) { + String providerName; - try { - providerName = provider.getName(); - } catch (Throwable t1) { - providerName = provider.getClass().getName(); - } + try { + providerName = provider.getName(); + } catch (Throwable t1) { + providerName = provider.getClass().getName(); + } - output.append(providerName).append(" is broken").append("\n"); - // ContextProvider is broken - } - } - } + output.append(providerName).append(" is broken").append("\n"); + // ContextProvider is broken + } + } + } - private static boolean appendAnalyzers(StringBuilder output, Throwable throwable, String messageFormat, - Object[] args) { - boolean analyzerResponsesExist = false; + private static boolean appendAnalyzers( + StringBuilder output, + Throwable throwable, + String messageFormat, + Object[] args + ) { + boolean analyzerResponsesExist = false; - // Do a local copy to avoid deadlocks -OLEGSHA - Analyzer[] localAnalyzersCopy = ANALYZERS.toArray(new Analyzer[ANALYZERS.size()]); + // Do a local copy to avoid deadlocks -OLEGSHA + Analyzer[] localAnalyzersCopy = ANALYZERS.toArray(new Analyzer[ANALYZERS.size()]); - if (localAnalyzersCopy.length > 0) { - output.append(StringUtil.center("Analyzers", 80)).append("\n"); - } + if (localAnalyzersCopy.length > 0) { + output.append(StringUtil.center("Analyzers", 80)).append("\n"); + } - for (Analyzer analyzer : localAnalyzersCopy) { - if (analyzer == null) - continue; + for (Analyzer analyzer : localAnalyzersCopy) { + if (analyzer == null) + continue; - String answer; - try { - answer = analyzer.analyze(throwable, messageFormat, args); + String answer; + try { + answer = analyzer.analyze(throwable, messageFormat, args); - if (answer != null && !answer.isEmpty()) { - analyzerResponsesExist = true; - output.append(analyzer.getName()).append(": ").append(answer).append("\n"); - } - } catch (Throwable t) { - analyzerResponsesExist = true; + if (answer != null && !answer.isEmpty()) { + analyzerResponsesExist = true; + output.append(analyzer.getName()).append(": ").append(answer).append("\n"); + } + } catch (Throwable t) { + analyzerResponsesExist = true; - output.append("\n"); + output.append("\n"); - String analyzerName; + String analyzerName; - try { - analyzerName = analyzer.getName(); - } catch (Throwable t1) { - analyzerName = analyzer.getClass().getName(); - } + try { + analyzerName = analyzer.getName(); + } catch (Throwable t1) { + analyzerName = analyzer.getClass().getName(); + } - output.append(analyzerName).append(" is broken").append("\n"); - // Analyzer is broken - } - } + output.append(analyzerName).append(" is broken").append("\n"); + // Analyzer is broken + } + } - return analyzerResponsesExist; - } + return analyzerResponsesExist; + } - private static void appendMessageFormat(StringBuilder output, String messageFormat, Object... arg) { - output.append("Provided description: \n"); - if (messageFormat.isEmpty()) - output.append("none").append("\n"); - else - output.append(String.format(messageFormat, arg)).append("\n"); + private static void appendMessageFormat(StringBuilder output, String messageFormat, Object... arg) { + output.append("Provided description: \n"); + if (messageFormat.isEmpty()) + output.append("none").append("\n"); + else + output.append(String.format(messageFormat, arg)).append("\n"); - addSeparator(output); - } + addSeparator(output); + } - private static void appendThrowable(StringBuilder output, Throwable throwable) { - if (throwable == null) { - output.append("No Throwable provided").append("\n"); - return; - } - - output.append("Reported Throwable:\n"); - - // Formatting to a human-readable string - Writer sink = new StringBuilderWriter(output); - try { - throwable.printStackTrace(new PrintWriter(sink)); - } catch (Exception e) { - // PLAK - } - output.append('\n'); - } - - private static void appendStackTrace(StringBuilder output, StackTraceElement[] stackTrace, String header) { - output.append(header).append('\n'); - - for (StackTraceElement element : stackTrace) { - output.append("\tat ").append(element).append('\n'); - } - } + private static void appendThrowable(StringBuilder output, Throwable throwable) { + if (throwable == null) { + output.append("No Throwable provided").append("\n"); + return; + } - private static void export(String report) { - try { - LOGGER.fatal("\n" + report); - } catch (Exception e) { - // PLAK - } + output.append("Reported Throwable:\n"); - System.err.println(report); + // Formatting to a human-readable string + Writer sink = new StringBuilderWriter(output); + try { + throwable.printStackTrace(new PrintWriter(sink)); + } catch (Exception e) { + // PLAK + } + output.append('\n'); + } - generateCrashReportFiles(report); - } + private static void appendStackTrace(StringBuilder output, StackTraceElement[] stackTrace, String header) { + output.append(header).append('\n'); - private static void generateCrashReportFiles(String output) { - Date date = new Date(); - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss"); + for (StackTraceElement element : stackTrace) { + output.append("\tat ").append(element).append('\n'); + } + } - try { - if (!Files.exists(CRASH_REPORTS_PATH)) - Files.createDirectory(CRASH_REPORTS_PATH); + private static void export(String report) { + try { + LOGGER.fatal("\n" + report); + } catch (Exception e) { + // PLAK + } - createFileForCrashReport(output, CRASH_REPORTS_PATH.toString() + "/latest.log"); - createFileForCrashReport(output, - CRASH_REPORTS_PATH.toString() + "/crash-" + dateFormat.format(date) + ".log"); - } catch (Throwable t) { - // Crash Report not created - } - } + System.err.println(report); - private static void createFileForCrashReport(String buffer, String filename) { - try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(filename), StandardCharsets.UTF_8)) { - writer.write(buffer); - } catch (IOException ex) { - // Crash Report not created - } - } + generateCrashReportFiles(report); + } - private static void addSeparator(StringBuilder sb) { - sb.append(StringUtil.sequence('-', 80)).append("\n"); - } + private static void generateCrashReportFiles(String output) { + Date date = new Date(); + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss"); - /** - * Registers the provided {@link ContextProvider} so it is consulted in the case of a crash. - * @param provider the provider to register - */ - public static void registerProvider(ContextProvider provider) { - PROVIDERS.add(provider); - } + try { + if (!Files.exists(CRASH_REPORTS_PATH)) + Files.createDirectory(CRASH_REPORTS_PATH); - /** - * Registers the provided {@link Analyzer} so it is consulted in the case of a crash. - * @param analyzer the analyzer to register - */ - public static void registerAnalyzer(Analyzer analyzer) { - ANALYZERS.add(analyzer); - } + createFileForCrashReport(output, CRASH_REPORTS_PATH.toString() + "/latest.log"); + createFileForCrashReport( + output, + CRASH_REPORTS_PATH.toString() + "/crash-" + dateFormat.format(date) + ".log" + ); + } catch (Throwable t) { + // Crash Report not created + } + } - /** - * A wrapper used by {@link CrashReports} to transfer problem details from the place of - * occurrence to the handler at the top of the stack. Rethrow if caught - * (unless using {@link CrashReports#report(Throwable, String, Object...)}, which does - * so automatically). - * - * @author serega404 - */ - public static class ReportedException extends RuntimeException { + private static void createFileForCrashReport(String buffer, String filename) { + try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(filename), StandardCharsets.UTF_8)) { + writer.write(buffer); + } catch (IOException ex) { + // Crash Report not created + } + } + + private static void addSeparator(StringBuilder sb) { + sb.append(StringUtil.sequence('-', 80)).append("\n"); + } + + /** + * Registers the provided {@link ContextProvider} so it is consulted in the + * case of a crash. + * + * @param provider the provider to register + */ + public static void registerProvider(ContextProvider provider) { + PROVIDERS.add(provider); + } + + /** + * Registers the provided {@link Analyzer} so it is consulted in the case of + * a crash. + * + * @param analyzer the analyzer to register + */ + public static void registerAnalyzer(Analyzer analyzer) { + ANALYZERS.add(analyzer); + } + + /** + * A wrapper used by {@link CrashReports} to transfer problem details from + * the place of + * occurrence to the handler at the top of the stack. Rethrow if caught + * (unless using {@link CrashReports#report(Throwable, String, Object...)}, + * which does + * so automatically). + * + * @author serega404 + */ + public static class ReportedException extends RuntimeException { private static final long serialVersionUID = 223720835231091533L; - + private final String messageFormat; - private final Object[] args; + private final Object[] args; - /** - * Constructs a {@link ReportedException}. - * @param throwable the reported {@link Throwable} or {@code null} - * @param messageFormat the reported message format. - * This is not the message of the constructed Exception. - * @param args the reported message format arguments - */ - public ReportedException(Throwable throwable, String messageFormat, Object... args) { - super(throwable); - this.messageFormat = messageFormat; - this.args = args; - } + /** + * Constructs a {@link ReportedException}. + * + * @param throwable the reported {@link Throwable} or {@code null} + * @param messageFormat the reported message format. + * This is not the message of the constructed + * Exception. + * @param args the reported message format arguments + */ + public ReportedException(Throwable throwable, String messageFormat, Object... args) { + super(throwable); + this.messageFormat = messageFormat; + this.args = args; + } - /** - * Returns the reported message format. - * @return message format - */ - public String getMessageFormat() { - return messageFormat; - } + /** + * Returns the reported message format. + * + * @return message format + */ + public String getMessageFormat() { + return messageFormat; + } - /** - * Returns the reported message format arguments. - * @return message format arguments - */ - public Object[] getArgs() { - return args; - } - } + /** + * Returns the reported message format arguments. + * + * @return message format arguments + */ + public Object[] getArgs() { + return args; + } + } - private CrashReports() { - - } + private CrashReports() { + + } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java index 0633085..141efa9 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/ReportingEventBus.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash; import com.google.common.eventbus.EventBus; @@ -5,14 +23,19 @@ import com.google.common.eventbus.EventBus; import ru.windcorp.progressia.common.hacks.GuavaEventBusHijacker; public class ReportingEventBus { - - private ReportingEventBus() {} + + private ReportingEventBus() { + } public static EventBus create(String identifier) { - return GuavaEventBusHijacker.newEventBus(identifier, (throwable, context) -> { - // Makes sense to append identifier to messageFormat because different EventBuses are completely unrelated - throw CrashReports.crash(throwable, "Unexpected exception in EventBus " + identifier); - }); + return GuavaEventBusHijacker.newEventBus( + identifier, + (throwable, context) -> { + // Makes sense to append identifier to messageFormat because + // different EventBuses are completely unrelated + throw CrashReports.crash(throwable, "Unexpected exception in EventBus " + identifier); + } + ); } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java index 95d5f76..c07152f 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/analyzers/OutOfMemoryAnalyzer.java @@ -1,17 +1,35 @@ -package ru.windcorp.progressia.common.util.crash.analyzers; - -import ru.windcorp.progressia.common.util.crash.Analyzer; - -public class OutOfMemoryAnalyzer implements Analyzer { - @Override - public String analyze(Throwable throwable, String messageFormat, Object... args) { - if (throwable instanceof OutOfMemoryError) - return "Try to add memory to the JVM"; - return null; - } - - @Override - public String getName() { - return "Out Of Memory Analyzer"; - } -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.crash.analyzers; + +import ru.windcorp.progressia.common.util.crash.Analyzer; + +public class OutOfMemoryAnalyzer implements Analyzer { + @Override + public String analyze(Throwable throwable, String messageFormat, Object... args) { + if (throwable instanceof OutOfMemoryError) + return "Try to add memory to the JVM"; + return null; + } + + @Override + public String getName() { + return "Out Of Memory Analyzer"; + } +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java index 317a90a..6c16902 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/ArgsContextProvider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.ProgressiaLauncher; @@ -7,20 +25,20 @@ import java.util.Map; public class ArgsContextProvider implements ContextProvider { - @Override - public void provideContext(Map output) { - output.put("Number of arguments", ProgressiaLauncher.arguments.length + " total"); - if (ProgressiaLauncher.arguments.length > 0) { - StringBuilder buffer = new StringBuilder(); - for (String arg : ProgressiaLauncher.arguments) { - buffer.append(arg).append(";"); - } - output.put("Args", System.getProperty(buffer.toString())); - } - } + @Override + public void provideContext(Map output) { + output.put("Number of arguments", ProgressiaLauncher.arguments.length + " total"); + if (ProgressiaLauncher.arguments.length > 0) { + StringBuilder buffer = new StringBuilder(); + for (String arg : ProgressiaLauncher.arguments) { + buffer.append(arg).append(";"); + } + output.put("Args", System.getProperty(buffer.toString())); + } + } - @Override - public String getName() { - return "Arguments Context Provider"; - } + @Override + public String getName() { + return "Arguments Context Provider"; + } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java index ff55be7..b8f4358 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/JavaVersionContextProvider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.common.util.crash.ContextProvider; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java index 994504f..ca9d387 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/LanguageContextProvider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.client.localization.Localizer; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java index f8d4ab4..7fd4610 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OSContextProvider.java @@ -1,20 +1,38 @@ -package ru.windcorp.progressia.common.util.crash.providers; - -import ru.windcorp.progressia.common.util.crash.ContextProvider; - -import java.util.Map; - -public class OSContextProvider implements ContextProvider { - - @Override - public void provideContext(Map output) { - output.put("OS Name", System.getProperty("os.name")); - output.put("OS Version", System.getProperty("os.version")); - output.put("OS Architecture", System.getProperty("os.arch")); - } - - @Override - public String getName() { - return "OS Context Provider"; - } -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.crash.providers; + +import ru.windcorp.progressia.common.util.crash.ContextProvider; + +import java.util.Map; + +public class OSContextProvider implements ContextProvider { + + @Override + public void provideContext(Map output) { + output.put("OS Name", System.getProperty("os.name")); + output.put("OS Version", System.getProperty("os.version")); + output.put("OS Architecture", System.getProperty("os.arch")); + } + + @Override + public String getName() { + return "OS Context Provider"; + } +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java index 0f6d61d..ad31bba 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/OpenALContextProvider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.client.audio.AudioManager; diff --git a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java index eb1934e..e455d78 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java +++ b/src/main/java/ru/windcorp/progressia/common/util/crash/providers/RAMContextProvider.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.crash.providers; import ru.windcorp.progressia.common.util.crash.ContextProvider; @@ -11,7 +29,11 @@ public class RAMContextProvider implements ContextProvider { output.put("Max Memory", Long.toString(Runtime.getRuntime().maxMemory() / 1024 / 1024) + " MB"); output.put("Total Memory", Long.toString(Runtime.getRuntime().totalMemory() / 1024 / 1024) + " MB"); output.put("Free Memory", Long.toString(Runtime.getRuntime().freeMemory() / 1024 / 1024) + " MB"); - output.put("Used Memory", Long.toString((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + " MB"); + output.put( + "Used Memory", + Long.toString((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + + " MB" + ); } @Override diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java index 7ab5d54..6068669 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DoubleFlusher.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; @@ -7,17 +25,17 @@ class DoubleFlusher { public static void flushDouble(TCharList sink, double number, int width, int precision, boolean alwaysUseSign) { boolean isSignNeeded = !Double.isNaN(number) && !isZero(number, precision) && (number < 0 || alwaysUseSign); int size = getSize(number, precision, isSignNeeded); - + int needChars = Math.max(width, size); reserve(sink, needChars); - + int charPos = flushDigits(number, precision, sink); - + if (isSignNeeded) { sink.set(--charPos, number > 0 ? '+' : '-'); } } - + private static boolean isZero(double number, int precision) { int digits = (int) Math.floor(number * pow10(precision)); return digits == 0; @@ -27,9 +45,11 @@ class DoubleFlusher { private static final char[] INFINITY_CHARS = "Infinity".toCharArray(); private static int getSize(double number, int precision, boolean isSignNeeded) { - if (Double.isNaN(number)) return NaN_CHARS.length; - if (number == Double.POSITIVE_INFINITY) return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length; - + if (Double.isNaN(number)) + return NaN_CHARS.length; + if (number == Double.POSITIVE_INFINITY) + return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length; + int integer = (int) Math.floor(Math.abs(number)); return (isSignNeeded ? 1 : 0) + IntFlusher.stringSize(integer) + 1 + precision; } @@ -39,8 +59,8 @@ class DoubleFlusher { sink.add(' '); } } - - private static int flushDigits(double number, int precision, TCharList sink) { + + private static int flushDigits(double number, int precision, TCharList sink) { if (Double.isFinite(number)) { return flushFiniteDigits(number, precision, sink); } else { @@ -50,35 +70,36 @@ class DoubleFlusher { private static int flushFiniteDigits(double number, int precision, TCharList sink) { number = Math.abs(number); - + int integer = (int) Math.floor(number); int fraction = (int) Math.floor((number - Math.floor(number)) * pow10(precision)); - + int charPos = IntFlusher.flushDigits(fraction, sink, sink.size()); sink.set(--charPos, '.'); charPos = IntFlusher.flushDigits(integer, sink, charPos); - + return charPos; } private static double pow10(int precision) { double result = 1; - for (int i = 0; i < precision; ++i) result *= 10; + for (int i = 0; i < precision; ++i) + result *= 10; return result; } private static int flushNonFiniteDigits(double number, TCharList sink) { final char[] chars; - + if (Double.isNaN(number)) { chars = NaN_CHARS; } else { chars = INFINITY_CHARS; } - + int offset = sink.size() - chars.length; sink.set(offset, chars); return offset; } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java index 5c57a14..8376a3d 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicString.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.dynstr; import java.util.function.Supplier; @@ -7,25 +25,25 @@ import gnu.trove.list.array.TCharArrayList; import ru.windcorp.jputil.chars.CharConsumer; public final class DynamicString implements CharSequence { - + interface Part { void flush(TCharList sink); } - + @FunctionalInterface public interface CharFlusherPart { void flush(CharConsumer sink); } - + final TCharList chars = new TCharArrayList(); final Part[] parts; - + private int hashCode = 0; DynamicString(Part[] parts) { this.parts = parts; } - + /** * Causes the contents of this string to be reevaluated. * This is not currently thread-safe, take caution. @@ -33,12 +51,12 @@ public final class DynamicString implements CharSequence { public void update() { chars.clear(); hashCode = 0; - + for (Part part : parts) { part.flush(chars); } } - + public Supplier asSupplier() { return () -> { update(); @@ -60,79 +78,87 @@ public final class DynamicString implements CharSequence { public CharSequence subSequence(int start, int end) { return new SubString(start, end); } - + @Override public String toString() { int length = length(); - + StringBuilder sb = new StringBuilder(length); for (int i = 0; i < length; ++i) { sb.append(chars.get(i)); } - + return sb.toString(); } - + @Override public int hashCode() { int h = hashCode; - int length = length(); - - if (h != 0 || length == 0) return h; - - for (int i = 0; i < length; i++) { - h = 31 * h + this.chars.get(i); - } - - hashCode = h; - return h; + int length = length(); + + if (h != 0 || length == 0) + return h; + + for (int i = 0; i < length; i++) { + h = 31 * h + this.chars.get(i); + } + + hashCode = h; + return h; } - + @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (obj.getClass() != getClass()) return false; - + if (obj == null) + return false; + if (obj.getClass() != getClass()) + return false; + DynamicString other = (DynamicString) obj; - - if (hashCode() != this.hashCode()) return false; - + + if (hashCode() != this.hashCode()) + return false; + return other.chars.equals(this.chars); } - + private class SubString implements CharSequence { - + private final int start; private final int end; - + public SubString(int start, int end) { this.start = start; this.end = end; } - + @Override public int length() { return Math.min(end, DynamicString.this.length()) - start; } + @Override public char charAt(int index) { if (index < 0 || index > length()) { throw new IndexOutOfBoundsException(Integer.toString(index) + " is out of bounds"); } - + return DynamicString.this.charAt(index); } + @Override public CharSequence subSequence(int start, int end) { - if (start < 0) throw new IllegalArgumentException("start (" + start + ") is negative"); - if (end < start) throw new IllegalArgumentException("end (" + end + ") < start (" + start + ")"); - + if (start < 0) + throw new IllegalArgumentException("start (" + start + ") is negative"); + if (end < start) + throw new IllegalArgumentException("end (" + end + ") < start (" + start + ")"); + int absoluteStart = this.start + start; int absoluteEnd = this.start + end; - + return DynamicString.this.subSequence(absoluteStart, absoluteEnd); } - + } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java index f92ca17..030cd9d 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/DynamicStrings.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.dynstr; import java.util.ArrayList; @@ -11,145 +29,148 @@ import ru.windcorp.jputil.chars.CharConsumer; import ru.windcorp.jputil.functions.FloatSupplier; public class DynamicStrings { - + @FunctionalInterface public interface CharSource { void flush(CharConsumer sink); } - + @FunctionalInterface public interface StringSupplier { String get(); } - + public static class Builder { - + private final List parts = new ArrayList<>(); - + public DynamicString build() { return new DynamicString(parts.toArray(new DynamicString.Part[parts.size()])); } - + public Supplier buildSupplier() { return build().asSupplier(); } - + public Builder addConst(Object constant) { return add(constant.toString()); } - + public Builder add(String string) { return add(string.toCharArray()); } - + public Builder add(final char[] chars) { parts.add(sink -> sink.add(chars)); return this; } - + public Builder add(char c) { parts.add(sink -> sink.add(c)); return this; } - + public Builder addDyn(Object obj) { - if (obj == null) return add("null"); + if (obj == null) + return add("null"); return addDyn(obj::toString); } - + public Builder embed(DynamicString str) { - if (str == null) return add("null"); - + if (str == null) + return add("null"); + for (DynamicString.Part p : str.parts) { parts.add(p); } - + return this; } - + public Builder addDyn(Supplier supplier) { Objects.requireNonNull(supplier, "supplier"); return addDyn(() -> Objects.toString(supplier.get())); } - + public Builder addDyn(StringSupplier supplier) { Objects.requireNonNull(supplier, "supplier"); - + parts.add(sink -> { String str = supplier.get(); int length = str.length(); - + for (int i = 0; i < length; ++i) { sink.add(str.charAt(i)); } }); - + return this; } - + public Builder addDyn(IntSupplier supplier, int width, boolean alwaysUseSign) { Objects.requireNonNull(supplier, "supplier"); - + parts.add(sink -> IntFlusher.flushInt(sink, supplier.getAsInt(), width, alwaysUseSign)); return this; } - + public Builder addDyn(IntSupplier supplier, int width) { return addDyn(supplier, width, false); } - + public Builder addDyn(IntSupplier supplier, boolean alwaysUseSign) { return addDyn(supplier, 0, alwaysUseSign); } - + public Builder addDyn(IntSupplier supplier) { return addDyn(supplier, 0, false); } - + public Builder addDyn(DoubleSupplier supplier, int width, int precision, boolean alwaysUseSign) { Objects.requireNonNull(supplier, "supplier"); - + parts.add(sink -> DoubleFlusher.flushDouble(sink, supplier.getAsDouble(), width, precision, alwaysUseSign)); return this; } - + public Builder addDyn(DoubleSupplier supplier, int width, int precision) { return addDyn(supplier, width, precision, false); } - + public Builder addDyn(DoubleSupplier supplier, boolean alwaysUseSign, int precision) { return addDyn(supplier, 0, precision, alwaysUseSign); } - + public Builder addDyn(DoubleSupplier supplier, int precision) { return addDyn(supplier, 0, precision, false); } - + public Builder addDyn(FloatSupplier supplier, int width, int precision, boolean alwaysUseSign) { Objects.requireNonNull(supplier, "supplier"); - + parts.add(sink -> FloatFlusher.flushFloat(sink, supplier.getAsFloat(), width, precision, alwaysUseSign)); return this; } - + public Builder addDyn(FloatSupplier supplier, int width, int precision) { return addDyn(supplier, width, precision, false); } - + public Builder addDyn(FloatSupplier supplier, boolean alwaysUseSign, int precision) { return addDyn(supplier, 0, precision, alwaysUseSign); } - + public Builder addDyn(FloatSupplier supplier, int precision) { return addDyn(supplier, 0, precision, false); } - + } - + public static Builder builder() { return new Builder(); } - private DynamicStrings() {} + private DynamicStrings() { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java index c1128da..0b245ee 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/FloatFlusher.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; @@ -7,17 +25,17 @@ class FloatFlusher { public static void flushFloat(TCharList sink, float number, int width, int precision, boolean alwaysUseSign) { boolean isSignNeeded = !Float.isNaN(number) && !isZero(number, precision) && (number < 0 || alwaysUseSign); int size = getSize(number, precision, isSignNeeded); - + int needChars = Math.max(width, size); reserve(sink, needChars); - + int charPos = flushDigits(number, precision, sink); - + if (isSignNeeded) { sink.set(--charPos, number > 0 ? '+' : '-'); } } - + private static boolean isZero(float number, int precision) { int digits = (int) Math.floor(number * pow10(precision)); return digits == 0; @@ -27,9 +45,11 @@ class FloatFlusher { private static final char[] INFINITY_CHARS = "Infinity".toCharArray(); private static int getSize(float number, int precision, boolean isSignNeeded) { - if (Float.isNaN(number)) return NaN_CHARS.length; - if (number == Float.POSITIVE_INFINITY) return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length; - + if (Float.isNaN(number)) + return NaN_CHARS.length; + if (number == Float.POSITIVE_INFINITY) + return (isSignNeeded ? 1 : 0) + INFINITY_CHARS.length; + int integer = (int) Math.floor(Math.abs(number)); return (isSignNeeded ? 1 : 0) + IntFlusher.stringSize(integer) + 1 + precision; } @@ -39,8 +59,8 @@ class FloatFlusher { sink.add(' '); } } - - private static int flushDigits(float number, int precision, TCharList sink) { + + private static int flushDigits(float number, int precision, TCharList sink) { if (Float.isFinite(number)) { return flushFiniteDigits(number, precision, sink); } else { @@ -50,35 +70,36 @@ class FloatFlusher { private static int flushFiniteDigits(float number, int precision, TCharList sink) { number = Math.abs(number); - + int integer = (int) Math.floor(number); int fraction = (int) Math.floor((number - Math.floor(number)) * pow10(precision)); - + int charPos = IntFlusher.flushDigits(fraction, sink, sink.size()); sink.set(--charPos, '.'); charPos = IntFlusher.flushDigits(integer, sink, charPos); - + return charPos; } private static float pow10(int precision) { float result = 1; - for (int i = 0; i < precision; ++i) result *= 10; + for (int i = 0; i < precision; ++i) + result *= 10; return result; } private static int flushNonFiniteDigits(float number, TCharList sink) { final char[] chars; - + if (Float.isNaN(number)) { chars = NaN_CHARS; } else { chars = INFINITY_CHARS; } - + int offset = sink.size() - chars.length; sink.set(offset, chars); return offset; } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java b/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java index d838ca4..9924f81 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java +++ b/src/main/java/ru/windcorp/progressia/common/util/dynstr/IntFlusher.java @@ -1,111 +1,305 @@ /* - * The algorithm implemented in this class is adapted from OpenJDK's Integer.toString(int) implementation. - * This class therefore falls under the GNU GPL v2 only license. + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + package ru.windcorp.progressia.common.util.dynstr; import gnu.trove.list.TCharList; class IntFlusher { - + public static void flushInt(TCharList sink, int number, int width, boolean alwaysUseSign) { - int size = stringSize(number); - - boolean isSignNeeded = number != 0 && (number < 0 || alwaysUseSign); - if (isSignNeeded) { - size++; - } - - int needChars = Math.max(size, width); - reserve(sink, needChars); - - int charPos = flushDigits(number, sink, sink.size()); - - if (isSignNeeded) { - sink.set(--charPos, number > 0 ? '+' : '-'); - } + int size = stringSize(number); + + boolean isSignNeeded = number != 0 && (number < 0 || alwaysUseSign); + if (isSignNeeded) { + size++; + } + + int needChars = Math.max(size, width); + reserve(sink, needChars); + + int charPos = flushDigits(number, sink, sink.size()); + + if (isSignNeeded) { + sink.set(--charPos, number > 0 ? '+' : '-'); + } } /* * Copied from OpenJDK's Integer.stringSize(int) */ public static int stringSize(int x) { - int d = 1; - if (x >= 0) { - d = 0; - x = -x; - } - int p = -10; - for (int i = 1; i < 10; i++) { - if (x > p) - return i + d; - p = 10 * p; - } - return 10 + d; - } - + int d = 1; + if (x >= 0) { + d = 0; + x = -x; + } + int p = -10; + for (int i = 1; i < 10; i++) { + if (x > p) + return i + d; + p = 10 * p; + } + return 10 + d; + } + /* * Copied from OpenJDK's Integer.DigitTens and Integer.DigitOnes */ private static final char[] DIGIT_TENS = { - '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', - '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', - '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', - '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', - '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', - '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', - '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', - '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', - '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', - '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', + '0', + '0', + '0', + '0', + '0', + '0', + '0', + '0', + '0', + '0', + '1', + '1', + '1', + '1', + '1', + '1', + '1', + '1', + '1', + '1', + '2', + '2', + '2', + '2', + '2', + '2', + '2', + '2', + '2', + '2', + '3', + '3', + '3', + '3', + '3', + '3', + '3', + '3', + '3', + '3', + '4', + '4', + '4', + '4', + '4', + '4', + '4', + '4', + '4', + '4', + '5', + '5', + '5', + '5', + '5', + '5', + '5', + '5', + '5', + '5', + '6', + '6', + '6', + '6', + '6', + '6', + '6', + '6', + '6', + '6', + '7', + '7', + '7', + '7', + '7', + '7', + '7', + '7', + '7', + '7', + '8', + '8', + '8', + '8', + '8', + '8', + '8', + '8', + '8', + '8', + '9', + '9', + '9', + '9', + '9', + '9', + '9', + '9', + '9', + '9', }; - private static final char[] DIGIT_ONES = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - }; + private static final char[] DIGIT_ONES = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + }; /* * Adapted from OpenJDK's Integer.getChars(int, int, byte[]) */ public static int flushDigits(int number, TCharList output, int endIndex) { int q, r; - int charPos = endIndex; + int charPos = endIndex; - if (number >= 0) { - number = -number; - } + if (number >= 0) { + number = -number; + } - // Generate two digits per iteration - while (number <= -100) { - q = number / 100; - r = (q * 100) - number; - number = q; - output.set(--charPos, DIGIT_ONES[r]); - output.set(--charPos, DIGIT_TENS[r]); - } + // Generate two digits per iteration + while (number <= -100) { + q = number / 100; + r = (q * 100) - number; + number = q; + output.set(--charPos, DIGIT_ONES[r]); + output.set(--charPos, DIGIT_TENS[r]); + } - // We know there are at most two digits left at this point. - q = number / 10; - r = (q * 10) - number; - output.set(--charPos, (char) ('0' + r)); + // We know there are at most two digits left at this point. + q = number / 10; + r = (q * 10) - number; + output.set(--charPos, (char) ('0' + r)); - // Whatever left is the remaining digit. - if (q < 0) { - output.set(--charPos, (char) ('0' - q)); - } + // Whatever left is the remaining digit. + if (q < 0) { + output.set(--charPos, (char) ('0' - q)); + } - return charPos; + return charPos; } - + private static void reserve(TCharList sink, int needChars) { for (int i = 0; i < needChars; ++i) { sink.add(' '); diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java index 92fbec0..d896bac 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/IllegalIdException.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.util.namespaces; public class IllegalIdException extends RuntimeException { @@ -8,7 +26,12 @@ public class IllegalIdException extends RuntimeException { super(); } - protected IllegalIdException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + protected IllegalIdException( + String message, + Throwable cause, + boolean enableSuppression, + boolean writableStackTrace + ) { super(message, cause, enableSuppression, writableStackTrace); } diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java index 33b9f74..2d87007 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/Namespaced.java @@ -1,63 +1,64 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.util.namespaces; - -public abstract class Namespaced { - - private final String id; - - public Namespaced(String id) { - NamespacedUtil.checkId(id); - this.id = id; - } - - public final String getId() { - return id; - } - - public String getNamespace() { - return NamespacedUtil.getNamespace(getId()); - } - - public String getName() { - return NamespacedUtil.getName(getId()); - } - - @Override - public String toString() { - return getId(); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (getClass() != obj.getClass()) - return false; - Namespaced other = (Namespaced) obj; - if (!id.equals(other.id)) - return false; - return true; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.namespaces; + +public abstract class Namespaced { + + private final String id; + + public Namespaced(String id) { + NamespacedUtil.checkId(id); + this.id = id; + } + + public final String getId() { + return id; + } + + public String getNamespace() { + return NamespacedUtil.getNamespace(getId()); + } + + public String getName() { + return NamespacedUtil.getName(getId()); + } + + @Override + public String toString() { + return getId(); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (getClass() != obj.getClass()) + return false; + Namespaced other = (Namespaced) obj; + if (!id.equals(other.id)) + return false; + return true; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java index 583ccd2..2a94593 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedFactoryRegistry.java @@ -1,114 +1,133 @@ -package ru.windcorp.progressia.common.util.namespaces; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -public class NamespacedFactoryRegistry -implements Map> { - - @FunctionalInterface - public static interface Factory { - E build(String id); - } - - private final Map> backingMap = - Collections.synchronizedMap(new HashMap<>()); - - private final Logger logger = LogManager.getLogger(getClass()); - - public void register(String id, Factory element) { - if (get(id) != null) { - throw new IllegalArgumentException("ID " + id + " is already registered in " + getClass().getSimpleName()); - } - - logger.debug("Registering {} in {}", id, getClass().getSimpleName()); - backingMap.put(id, element); - } - - @Override - public int size() { - return backingMap.size(); - } - - @Override - public boolean isEmpty() { - return backingMap.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return backingMap.containsKey(key); - } - - public boolean has(String id) { - return backingMap.containsKey(id); - } - - @Override - public boolean containsValue(Object value) { - return backingMap.containsValue(value); - } - - public boolean isRegistered(E element) { - return has(element.getId()); - } - - @Override - public Factory get(Object key) { - return backingMap.get(key); - } - - public E create(String id) { - Factory factory = get(id); - E result = factory.build(id); - if (!result.getId().equals(id)) { - throw new IllegalStateException("Requested ID " + id + " but factory " + factory + " returned an object with ID " + result.getId()); - } - return result; - } - - @Override - public Factory put(String id, Factory factory) { - register(id, factory); - return null; - } - - @Override - public void putAll(Map> m) { - synchronized (backingMap) { - m.entrySet().forEach(e -> register(e.getKey(), e.getValue())); - } - } - - @Override - public Factory remove(Object key) { - return backingMap.remove(key); - } - - @Override - public void clear() { - backingMap.clear(); - } - - @Override - public Set keySet() { - return backingMap.keySet(); - } - - @Override - public Collection> values() { - return backingMap.values(); - } - - @Override - public Set>> entrySet() { - return backingMap.entrySet(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.namespaces; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class NamespacedFactoryRegistry + implements Map> { + + @FunctionalInterface + public static interface Factory { + E build(String id); + } + + private final Map> backingMap = Collections.synchronizedMap(new HashMap<>()); + + private final Logger logger = LogManager.getLogger(getClass()); + + public void register(String id, Factory element) { + if (get(id) != null) { + throw new IllegalArgumentException("ID " + id + " is already registered in " + getClass().getSimpleName()); + } + + logger.debug("Registering {} in {}", id, getClass().getSimpleName()); + backingMap.put(id, element); + } + + @Override + public int size() { + return backingMap.size(); + } + + @Override + public boolean isEmpty() { + return backingMap.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return backingMap.containsKey(key); + } + + public boolean has(String id) { + return backingMap.containsKey(id); + } + + @Override + public boolean containsValue(Object value) { + return backingMap.containsValue(value); + } + + public boolean isRegistered(E element) { + return has(element.getId()); + } + + @Override + public Factory get(Object key) { + return backingMap.get(key); + } + + public E create(String id) { + Factory factory = get(id); + E result = factory.build(id); + if (!result.getId().equals(id)) { + throw new IllegalStateException( + "Requested ID " + id + " but factory " + factory + " returned an object with ID " + result.getId() + ); + } + return result; + } + + @Override + public Factory put(String id, Factory factory) { + register(id, factory); + return null; + } + + @Override + public void putAll(Map> m) { + synchronized (backingMap) { + m.entrySet().forEach(e -> register(e.getKey(), e.getValue())); + } + } + + @Override + public Factory remove(Object key) { + return backingMap.remove(key); + } + + @Override + public void clear() { + backingMap.clear(); + } + + @Override + public Set keySet() { + return backingMap.keySet(); + } + + @Override + public Collection> values() { + return backingMap.values(); + } + + @Override + public Set>> entrySet() { + return backingMap.entrySet(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java index ca4a56f..ce1f3cf 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedInstanceRegistry.java @@ -1,113 +1,132 @@ -package ru.windcorp.progressia.common.util.namespaces; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.google.errorprone.annotations.DoNotCall; - -public class NamespacedInstanceRegistry -implements Map { - - private final Map backingMap = - Collections.synchronizedMap(new HashMap<>()); - - private final Logger logger = LogManager.getLogger(getClass()); - - public void register(E element) { - logger.debug("Registering {} in {}", element.getId(), getClass().getSimpleName()); - backingMap.put(element.getId(), element); - } - - public void registerAll(Collection elements) { - for (E element : elements) { - register(element); - } - } - - @Override - public int size() { - return backingMap.size(); - } - - @Override - public boolean isEmpty() { - return backingMap.isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return backingMap.containsKey(key); - } - - public boolean has(String id) { - return backingMap.containsKey(id); - } - - @Override - public boolean containsValue(Object value) { - return backingMap.containsValue(value); - } - - public boolean isRegistered(E element) { - return has(element.getId()); - } - - @Override - public E get(Object key) { - return backingMap.get(key); - } - - /** - * Use {@link #register(E)}. - */ - @Override - @DoNotCall @Deprecated - public E put(String key, E value) { - throw new UnsupportedOperationException( - "Use NamespacedInstanceRegistry.register(E)" - ); - } - - @Override - public E remove(Object key) { - return backingMap.remove(key); - } - - /** - * Use {@link #registerAll(Collection)}. - */ - @Override - @DoNotCall @Deprecated - public void putAll(Map m) { - throw new UnsupportedOperationException( - "Use NamespacedInstanceRegistry.registerAll(Collection)" - ); - } - - @Override - public void clear() { - backingMap.clear(); - } - - @Override - public Set keySet() { - return backingMap.keySet(); - } - - @Override - public Collection values() { - return backingMap.values(); - } - - @Override - public Set> entrySet() { - return backingMap.entrySet(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.namespaces; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.errorprone.annotations.DoNotCall; + +public class NamespacedInstanceRegistry + implements Map { + + private final Map backingMap = Collections.synchronizedMap(new HashMap<>()); + + private final Logger logger = LogManager.getLogger(getClass()); + + public void register(E element) { + logger.debug("Registering {} in {}", element.getId(), getClass().getSimpleName()); + backingMap.put(element.getId(), element); + } + + public void registerAll(Collection elements) { + for (E element : elements) { + register(element); + } + } + + @Override + public int size() { + return backingMap.size(); + } + + @Override + public boolean isEmpty() { + return backingMap.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return backingMap.containsKey(key); + } + + public boolean has(String id) { + return backingMap.containsKey(id); + } + + @Override + public boolean containsValue(Object value) { + return backingMap.containsValue(value); + } + + public boolean isRegistered(E element) { + return has(element.getId()); + } + + @Override + public E get(Object key) { + return backingMap.get(key); + } + + /** + * Use {@link #register(E)}. + */ + @Override + @DoNotCall + @Deprecated + public E put(String key, E value) { + throw new UnsupportedOperationException( + "Use NamespacedInstanceRegistry.register(E)" + ); + } + + @Override + public E remove(Object key) { + return backingMap.remove(key); + } + + /** + * Use {@link #registerAll(Collection)}. + */ + @Override + @DoNotCall + @Deprecated + public void putAll(Map m) { + throw new UnsupportedOperationException( + "Use NamespacedInstanceRegistry.registerAll(Collection)" + ); + } + + @Override + public void clear() { + backingMap.clear(); + } + + @Override + public Set keySet() { + return backingMap.keySet(); + } + + @Override + public Collection values() { + return backingMap.values(); + } + + @Override + public Set> entrySet() { + return backingMap.entrySet(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java index 5ced799..b969b8e 100644 --- a/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java +++ b/src/main/java/ru/windcorp/progressia/common/util/namespaces/NamespacedUtil.java @@ -1,106 +1,125 @@ -package ru.windcorp.progressia.common.util.namespaces; - -import java.util.Objects; - -import ru.windcorp.jputil.chars.StringUtil; - -public class NamespacedUtil { - - public static final char SEPARATOR = ':'; - - public static final int MAX_ID_LENGTH = 255; - private static final int MAX_PART_LENGTH = (MAX_ID_LENGTH - 1) / 2; - - public static final int MAX_NAMESPACE_LENGTH = MAX_PART_LENGTH; - public static final int MAX_NAME_LENGTH = MAX_PART_LENGTH; - - private static final int MIN_PART_LENGTH = 3; - - public static final int MIN_NAMESPACE_LENGTH = MIN_PART_LENGTH; - public static final int MIN_NAME_LENGTH = MIN_PART_LENGTH; - - /* - * This is the definition of the accepted pattern, but the value of - * these constants is not actually consulted in the check* methods. - */ - private static final String PART_CORE_REGEX = "[A-Z][a-zA-Z0-9]{2," + (MAX_PART_LENGTH - 1) + "}"; - private static final String PART_REGEX = "^" + PART_CORE_REGEX + "$"; - - public static final String NAMESPACE_REGEX = PART_REGEX; - public static final String NAME_REGEX = PART_REGEX; - public static final String ID_REGEX = "^" + PART_CORE_REGEX + ":" + PART_CORE_REGEX + "$"; - - public static String getName(String id) { - checkId(id); - return id.substring(id.indexOf(':') + 1); - } - - public static String getNamespace(String id) { - checkId(id); - return id.substring(0, id.indexOf(':')); - } - - public static String getId(String namespace, String name) { - checkPart(namespace, 0, namespace.length(), "Namespace"); - checkPart(name, 0, name.length(), "Name"); - - return namespace + SEPARATOR + name; - } - - public static void checkId(String id) { - Objects.requireNonNull(id, "id"); - - int firstSeparator = id.indexOf(SEPARATOR); - - boolean areSeparatorsInvalid = (firstSeparator < 0) || (id.indexOf(SEPARATOR, firstSeparator + 1) >= 0); - - if (areSeparatorsInvalid) { - int separators = StringUtil.count(id, SEPARATOR); - throw new IllegalIdException( - "ID \"" + id + "\" is invalid. " - + (separators == 0 ? "No " : "Too many (" + separators + ") ") - + "separators '" + SEPARATOR + "' found, exactly one required" - ); - } - - checkPart(id, 0, firstSeparator, "namespace"); - checkPart(id, firstSeparator + 1, id.length() - firstSeparator - 1, "name"); - } - - private static void checkPart(String data, int offset, int length, String nameForErrors) { - Objects.requireNonNull(data, nameForErrors); - - if (length > MAX_PART_LENGTH) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too long. " - + "Expected at most " + MAX_PART_LENGTH - + " characters" - ); - } else if (length < MIN_PART_LENGTH) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too short. " - + "Expected at lest " + MIN_PART_LENGTH - + " characters" - ); - } - - // Don't actually use *_REGEX for speed - - for (int i = 0; i < length; ++i) { - char c = data.charAt(i + offset); - if (!( - ( c >= 'A' && c <= 'Z') || - (i != 0 && c >= 'a' && c <= 'z') || - (i != 0 && c >= '0' && c <= '9') - )) { - throw new IllegalIdException( - nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is invalid. " - + "Allowed is: " + PART_REGEX - ); - } - } - } - - private NamespacedUtil() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.util.namespaces; + +import java.util.Objects; + +import ru.windcorp.jputil.chars.StringUtil; + +public class NamespacedUtil { + + public static final char SEPARATOR = ':'; + + public static final int MAX_ID_LENGTH = 255; + private static final int MAX_PART_LENGTH = (MAX_ID_LENGTH - 1) / 2; + + public static final int MAX_NAMESPACE_LENGTH = MAX_PART_LENGTH; + public static final int MAX_NAME_LENGTH = MAX_PART_LENGTH; + + private static final int MIN_PART_LENGTH = 3; + + public static final int MIN_NAMESPACE_LENGTH = MIN_PART_LENGTH; + public static final int MIN_NAME_LENGTH = MIN_PART_LENGTH; + + /* + * This is the definition of the accepted pattern, but the value of + * these constants is not actually consulted in the check* methods. + */ + private static final String PART_CORE_REGEX = "[A-Z][a-zA-Z0-9]{2," + (MAX_PART_LENGTH - 1) + "}"; + private static final String PART_REGEX = "^" + PART_CORE_REGEX + "$"; + + public static final String NAMESPACE_REGEX = PART_REGEX; + public static final String NAME_REGEX = PART_REGEX; + public static final String ID_REGEX = "^" + PART_CORE_REGEX + ":" + PART_CORE_REGEX + "$"; + + public static String getName(String id) { + checkId(id); + return id.substring(id.indexOf(':') + 1); + } + + public static String getNamespace(String id) { + checkId(id); + return id.substring(0, id.indexOf(':')); + } + + public static String getId(String namespace, String name) { + checkPart(namespace, 0, namespace.length(), "Namespace"); + checkPart(name, 0, name.length(), "Name"); + + return namespace + SEPARATOR + name; + } + + public static void checkId(String id) { + Objects.requireNonNull(id, "id"); + + int firstSeparator = id.indexOf(SEPARATOR); + + boolean areSeparatorsInvalid = (firstSeparator < 0) || (id.indexOf(SEPARATOR, firstSeparator + 1) >= 0); + + if (areSeparatorsInvalid) { + int separators = StringUtil.count(id, SEPARATOR); + throw new IllegalIdException( + "ID \"" + id + "\" is invalid. " + + (separators == 0 ? "No " : "Too many (" + separators + ") ") + + "separators '" + SEPARATOR + "' found, exactly one required" + ); + } + + checkPart(id, 0, firstSeparator, "namespace"); + checkPart(id, firstSeparator + 1, id.length() - firstSeparator - 1, "name"); + } + + private static void checkPart(String data, int offset, int length, String nameForErrors) { + Objects.requireNonNull(data, nameForErrors); + + if (length > MAX_PART_LENGTH) { + throw new IllegalIdException( + nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too long. " + + "Expected at most " + MAX_PART_LENGTH + + " characters" + ); + } else if (length < MIN_PART_LENGTH) { + throw new IllegalIdException( + nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is too short. " + + "Expected at lest " + MIN_PART_LENGTH + + " characters" + ); + } + + // Don't actually use *_REGEX for speed + + for (int i = 0; i < length; ++i) { + char c = data.charAt(i + offset); + if ( + !((c >= 'A' && c <= 'Z') || + (i != 0 && c >= 'a' && c <= 'z') || + (i != 0 && c >= '0' && c <= '9')) + ) { + throw new IllegalIdException( + nameForErrors + " \"" + data.substring(offset, offset + length) + "\" is invalid. " + + "Allowed is: " + PART_REGEX + ); + } + } + } + + private NamespacedUtil() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java index ab4dbf7..4d5f1f9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java +++ b/src/main/java/ru/windcorp/progressia/common/world/BlockRay.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import glm.vec._3.Vec3; @@ -9,24 +27,25 @@ import ru.windcorp.progressia.common.world.block.BlockFace; import static java.lang.Math.*; public class BlockRay { - + private final Vec3 position = new Vec3(); private final Vec3 direction = new Vec3(); - + private float distance; - + private final Vec3i block = new Vec3i(); private BlockFace currentFace = null; - + private boolean isValid = false; - + public void start(Vec3 position, Vec3 direction) { if (!direction.any()) { throw new IllegalArgumentException("Direction is a zero vector"); } isValid = true; - this.position.set(position).sub(0.5f); // Make sure lattice points are block vertices, not centers + this.position.set(position).sub(0.5f); // Make sure lattice points are + // block vertices, not centers this.direction.set(direction).normalize(); this.block.set(toBlock(position.x), toBlock(position.y), toBlock(position.z)); this.distance = 0; @@ -35,17 +54,17 @@ public class BlockRay { public void end() { isValid = false; } - + public Vec3i next() { checkState(); - + float tx = distanceToEdge(position.x, direction.x); float ty = distanceToEdge(position.y, direction.y); float tz = distanceToEdge(position.z, direction.z); - + float tMin; Axis axis; - + if (tx < ty && tx < tz) { tMin = tx; axis = Axis.X; @@ -56,58 +75,68 @@ public class BlockRay { tMin = tz; axis = Axis.Z; } - + // block.(axis) += signum(direction.(axis)) VectorUtil.set(block, axis, VectorUtil.get(block, axis) + (int) signum(VectorUtil.get(direction, axis))); - + // position += direction * tMin - VectorUtil.linearCombination(position, 1, direction, tMin, position); // position += direction * tMin + VectorUtil.linearCombination(position, 1, direction, tMin, position); // position + // += + // direction + // * + // tMin distance += tMin; - + // position.(axis) = round(position.(axis)) VectorUtil.set(position, axis, round(VectorUtil.get(position, axis))); - + this.currentFace = computeCurrentFace(axis, (int) signum(VectorUtil.get(direction, axis))); - + return block; } private static float distanceToEdge(float c, float dir) { - if (dir == 0) return Float.POSITIVE_INFINITY; - + if (dir == 0) + return Float.POSITIVE_INFINITY; + float edge; - + if (dir > 0) { edge = strictCeil(c); } else { edge = strictFloor(c); } - + return (edge - c) / dir; } private BlockFace computeCurrentFace(Axis axis, int sign) { - if (sign == 0) throw new IllegalStateException("sign is zero"); - + if (sign == 0) + throw new IllegalStateException("sign is zero"); + switch (axis) { - case X: return sign > 0 ? BlockFace.SOUTH : BlockFace.NORTH; - case Y: return sign > 0 ? BlockFace.EAST : BlockFace.WEST; + case X: + return sign > 0 ? BlockFace.SOUTH : BlockFace.NORTH; + case Y: + return sign > 0 ? BlockFace.EAST : BlockFace.WEST; default: - case Z: return sign > 0 ? BlockFace.BOTTOM : BlockFace.TOP; + case Z: + return sign > 0 ? BlockFace.BOTTOM : BlockFace.TOP; } } - + public Vec3i current() { checkState(); return block; } - + public Vec3 getPoint(Vec3 output) { output.set(position); - output.add(0.5f); // Make sure we're in the block-center coordinate system + output.add(0.5f); // Make sure we're in the block-center coordinate + // system return output; } - + public BlockFace getCurrentFace() { return currentFace; } @@ -116,28 +145,30 @@ public class BlockRay { checkState(); return distance; } - + private void checkState() { if (!isValid) { throw new IllegalStateException("BlockRay not started"); } } - + private static int toBlock(float c) { return (int) round(c); } - + /** * Returns a smallest integer a such that a > c. + * * @param c the number to compute strict ceiling of * @return the strict ceiling of c */ private static float strictCeil(float c) { return (float) (floor(c) + 1); } - + /** * Returns a largest integer a such that a < c. + * * @param c the number to compute strict ceiling of * @return the strict ceiling of c */ diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java index 8590a65..252429c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkData.java @@ -1,557 +1,560 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world; - -import static ru.windcorp.progressia.common.world.block.BlockFace.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.util.VectorUtil; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; -import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; - -public class ChunkData -implements GenericChunk< - ChunkData, - BlockData, - TileData, - TileDataStack -> { - - public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; - - private final Vec3i position = new Vec3i(); - private final WorldData world; - - private final BlockData[] blocks = new BlockData[ - BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK - ]; - - private final TileDataStack[] tiles = new TileDataStack[ - BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * - BLOCK_FACE_COUNT - ]; - - private Object generationHint = null; - - private final Collection listeners = - Collections.synchronizedCollection(new ArrayList<>()); - - public ChunkData(Vec3i position, WorldData world) { - this.position.set(position.x, position.y, position.z); - this.world = world; - } - - @Override - public Vec3i getPosition() { - return position; - } - - @Override - public BlockData getBlock(Vec3i posInChunk) { - return blocks[getBlockIndex(posInChunk)]; - } - - public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { - BlockData previous = blocks[getBlockIndex(posInChunk)]; - blocks[getBlockIndex(posInChunk)] = block; - - if (notify) { - getListeners().forEach(l -> { - l.onChunkBlockChanged(this, posInChunk, previous, block); - l.onChunkChanged(this); - }); - } - } - - @Override - public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { - return tiles[getTileIndex(blockInChunk, face)]; - } - - /** - * Internal use only. Modify a list returned by - * {@link #getTiles(Vec3i, BlockFace)} or - * {@link #getTilesOrNull(Vec3i, BlockFace)} - * to change tiles. - */ - protected void setTiles( - Vec3i blockInChunk, BlockFace face, - TileDataStack tiles - ) { - this.tiles[getTileIndex(blockInChunk, face)] = tiles; - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getTilesOrNull(blockInChunk, face) != null; - } - - @Override - public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { - int index = getTileIndex(blockInChunk, face); - - if (tiles[index] == null) { - createTileStack(blockInChunk, face); - } - - return tiles[index]; - } - - private void createTileStack(Vec3i blockInChunk, BlockFace face) { - Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); - TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); - setTiles(blockInChunk, face, stack); - } - - private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { - for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { - TileDataStack stack = getTilesOrNull(blockInChunk, BlockFace.getFaces().get(i)); - if (stack instanceof TileDataStackImpl) { - return ((TileDataStackImpl) stack).blockInChunk; - } - } - - return new Vec3i(blockInChunk); - } - - private static int getBlockIndex(Vec3i posInChunk) { - checkLocalCoordinates(posInChunk); - - return - posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + - posInChunk.y * BLOCKS_PER_CHUNK + - posInChunk.x; - } - - private static int getTileIndex(Vec3i posInChunk, BlockFace face) { - return - getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + - face.getId(); - } - - private static void checkLocalCoordinates(Vec3i posInChunk) { - if (!isInBounds(posInChunk)) { - throw new IllegalCoordinatesException( - "Coordinates " + str(posInChunk) + " " - + "are not legal chunk coordinates" - ); - } - } - - public static boolean isInBounds(Vec3i posInChunk) { - return - posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && - posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && - posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; - } - - public boolean isBorder(Vec3i blockInChunk, BlockFace face) { - final int min = 0, max = BLOCKS_PER_CHUNK - 1; - return - (blockInChunk.x == min && face == SOUTH ) || - (blockInChunk.x == max && face == NORTH ) || - (blockInChunk.y == min && face == EAST ) || - (blockInChunk.y == max && face == WEST ) || - (blockInChunk.z == min && face == BOTTOM) || - (blockInChunk.z == max && face == TOP ); - } - - public void forEachBlock(Consumer action) { - VectorUtil.iterateCuboid( - 0, 0, 0, - BLOCKS_PER_CHUNK, BLOCKS_PER_CHUNK, BLOCKS_PER_CHUNK, - action - ); - } - - public void forEachTileStack(Consumer action) { - forEachBlock(blockInChunk -> { - for (BlockFace face : BlockFace.getFaces()) { - TileDataStack stack = getTilesOrNull(blockInChunk, face); - if (stack == null) continue; - action.accept(stack); - } - }); - } - - /** - * Iterates over all tiles in this chunk. - * - * @param action the action to perform. {@code TileLocation} refers to each - * tile using its primary block - */ - public void forEachTile(BiConsumer action) { - forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); - } - - public WorldData getWorld() { - return world; - } - - public Collection getListeners() { - return listeners; - } - - public void addListener(ChunkDataListener listener) { - this.listeners.add(listener); - } - - public void removeListener(ChunkDataListener listener) { - this.listeners.remove(listener); - } - - private static String str(Vec3i v) { - return "(" + v.x + "; " + v.y + "; " + v.z + ")"; - } - - protected void onLoaded() { - getListeners().forEach(l -> l.onChunkLoaded(this)); - } - - protected void beforeUnloaded() { - getListeners().forEach(l -> l.beforeChunkUnloaded(this)); - } - - public Object getGenerationHint() { - return generationHint; - } - - public void setGenerationHint(Object generationHint) { - this.generationHint = generationHint; - } - - /** - * Implementation of {@link TileDataStack} used internally by {@link ChunkData} to - * actually store the tiles. This is basically an array wrapper with reporting - * capabilities. - * @author javapony - */ - private class TileDataStackImpl extends TileDataStack { - private class TileReferenceImpl implements TileReference { - private int index; - - public TileReferenceImpl(int index) { - this.index = index; - } - - public void incrementIndex() { - this.index++; - } - - public void decrementIndex() { - this.index--; - } - - public void invalidate() { - this.index = 0; - } - - @Override - public TileData get() { - if (!isValid()) return null; - return TileDataStackImpl.this.get(this.index); - } - - @Override - public int getIndex() { - return index; - } - - @Override - public TileDataStack getStack() { - return TileDataStackImpl.this; - } - - @Override - public boolean isValid() { - return this.index >= 0; - } - } - - private final TileData[] tiles = new TileData[TILES_PER_FACE]; - private int size = 0; - - private final TileReferenceImpl[] references = new TileReferenceImpl[tiles.length]; - private final int[] indicesByTag = new int[tiles.length]; - private final int[] tagsByIndex = new int[tiles.length]; - - { - Arrays.fill(indicesByTag, -1); - Arrays.fill(tagsByIndex, -1); - } - - /* - * Potentially shared - */ - private final Vec3i blockInChunk; - private final BlockFace face; - - public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { - this.blockInChunk = blockInChunk; - this.face = face; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - if (output == null) output = new Vec3i(); - output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); - return output; - } - - @Override - public BlockFace getFace() { - return face; - } - - @Override - public ChunkData getChunk() { - return ChunkData.this; - } - - @Override - public int size() { - return size; - } - - @Override - public TileData get(int index) { - checkIndex(index, false); - - return tiles[index]; - } - - @Override - public TileData set(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - TileData previous = get(index); // checks index - - tiles[index] = tile; - - if (references[index] != null) { - references[index].invalidate(); - references[index] = null; - } - - assert checkConsistency(); - - report(previous, tile); - return previous; - } - - @Override - public void add(int index, TileData tile) { - Objects.requireNonNull(tile, "tile"); - checkIndex(index, true); - - if (index != size()) { - System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); - - for (int i = index; i < size; ++i) { - if (references[i] != null) { - references[i].incrementIndex(); - } - - indicesByTag[tagsByIndex[i]]++; - } - - System.arraycopy(references, index + 1, references, index + 2, size - index); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); - } - - size++; - tiles[index] = tile; - references[index] = null; - - for (int tag = 0; tag < indicesByTag.length; ++tag) { - if (tagsByIndex[tag] == -1) { - indicesByTag[tag] = index; - tagsByIndex[index] = tag; - break; - } - } - - modCount++; - assert checkConsistency(); - - report(null, tile); - } - - @Override - public void load(TileData tile, int tag) { - addFarthest(tile); - - int assignedTag = getIndexByTag(tag); - - if (assignedTag == tag) return; - if (assignedTag == -1) { - throw new IllegalArgumentException("Tag " + tag + " already used by tile at index " + getIndexByTag(tag)); - } - - indicesByTag[tagsByIndex[size() - 1]] = -1; - tagsByIndex[size() - 1] = tag; - indicesByTag[tag] = size() - 1; - - assert checkConsistency(); - } - - @Override - public TileData remove(int index) { - TileData previous = get(index); // checks index - - if (references[index] != null) { - references[index].invalidate(); - } - - indicesByTag[tagsByIndex[index]] = -1; - - if (index != size() - 1) { - System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); - - for (int i = index + 1; i < size; ++i) { - if (references[i] != null) { - references[i].decrementIndex(); - } - - indicesByTag[tagsByIndex[i]]--; - } - - System.arraycopy(references, index + 1, references, index, size - index - 1); - System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); - } - - size--; - tiles[size] = null; - references[size] = null; - tagsByIndex[size] = -1; - - modCount++; - assert checkConsistency(); - - report(previous, null); - return previous; - } - - @Override - public TileReference getReference(int index) { - checkIndex(index, false); - - if (references[index] == null) { - references[index] = new TileReferenceImpl(index); - } - - return references[index]; - } - - @Override - public int getIndexByTag(int tag) { - return indicesByTag[tag]; - } - - @Override - public int getTagByIndex(int index) { - checkIndex(index, false); - return tagsByIndex[index]; - } - - @Override - public void clear() { - while (!isEmpty()) { - removeFarthest(); - } - } - - private void checkIndex(int index, boolean isSizeAllowed) { - if (isSizeAllowed ? (index > size()) : (index >= size())) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); - - if (index < 0) - throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); - - if (index >= TILES_PER_FACE) - throw new TileStackIsFullException("Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE); - } - - private void report(TileData previous, TileData current) { - ChunkData.this.getListeners().forEach(l -> { - if (previous != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, previous, false); - } - - if (current != null) { - l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, current, true); - } - - l.onChunkChanged(ChunkData.this); - }); - } - - private boolean checkConsistency() { - int index; - - for (index = 0; index < size(); ++index) { - if (get(index) == null) - throw new AssertionError("get(index) is null"); - - if (references[index] != null) { - TileReference ref = getReference(index); - if (ref == null) - throw new AssertionError("references[index] is not null but getReference(index) is"); - if (!ref.isValid()) - throw new AssertionError("Reference is not valid"); - if (ref.get() != get(index)) - throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); - if (ref.getIndex() != index) - throw new AssertionError("Reference has invalid index"); - if (ref.getStack() != this) - throw new AssertionError("Reference has invalid TDS"); - } - - if (index != indicesByTag[tagsByIndex[index]]) - throw new AssertionError("Tag mapping is inconsistent"); - if (index != getIndexByTag(getTagByIndex(index))) - throw new AssertionError("Tag methods are inconsistent with tag mapping"); - } - - for (; index < tiles.length; ++index) { - if (tiles[index] != null) - throw new AssertionError("Leftover tile detected"); - if (references[index] != null) - throw new AssertionError("Leftover reference detected"); - if (tagsByIndex[index] != -1) - throw new AssertionError("Leftover tags detected"); - } - - return true; - } - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import static ru.windcorp.progressia.common.world.block.BlockFace.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.VectorUtil; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.tile.TileReference; +import ru.windcorp.progressia.common.world.tile.TileStackIsFullException; + +public class ChunkData + implements GenericChunk { + + public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; + + private final Vec3i position = new Vec3i(); + private final WorldData world; + + private final BlockData[] blocks = new BlockData[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK]; + + private final TileDataStack[] tiles = new TileDataStack[BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK * + BLOCK_FACE_COUNT]; + + private Object generationHint = null; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public ChunkData(Vec3i position, WorldData world) { + this.position.set(position.x, position.y, position.z); + this.world = world; + } + + @Override + public Vec3i getPosition() { + return position; + } + + @Override + public BlockData getBlock(Vec3i posInChunk) { + return blocks[getBlockIndex(posInChunk)]; + } + + public void setBlock(Vec3i posInChunk, BlockData block, boolean notify) { + BlockData previous = blocks[getBlockIndex(posInChunk)]; + blocks[getBlockIndex(posInChunk)] = block; + + if (notify) { + getListeners().forEach(l -> { + l.onChunkBlockChanged(this, posInChunk, previous, block); + l.onChunkChanged(this); + }); + } + } + + @Override + public TileDataStack getTilesOrNull(Vec3i blockInChunk, BlockFace face) { + return tiles[getTileIndex(blockInChunk, face)]; + } + + /** + * Internal use only. Modify a list returned by + * {@link #getTiles(Vec3i, BlockFace)} or + * {@link #getTilesOrNull(Vec3i, BlockFace)} + * to change tiles. + */ + protected void setTiles( + Vec3i blockInChunk, + BlockFace face, + TileDataStack tiles + ) { + this.tiles[getTileIndex(blockInChunk, face)] = tiles; + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getTilesOrNull(blockInChunk, face) != null; + } + + @Override + public TileDataStack getTiles(Vec3i blockInChunk, BlockFace face) { + int index = getTileIndex(blockInChunk, face); + + if (tiles[index] == null) { + createTileStack(blockInChunk, face); + } + + return tiles[index]; + } + + private void createTileStack(Vec3i blockInChunk, BlockFace face) { + Vec3i independentBlockInChunk = conjureIndependentBlockInChunkVec3i(blockInChunk); + TileDataStackImpl stack = new TileDataStackImpl(independentBlockInChunk, face); + setTiles(blockInChunk, face, stack); + } + + private Vec3i conjureIndependentBlockInChunkVec3i(Vec3i blockInChunk) { + for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { + TileDataStack stack = getTilesOrNull(blockInChunk, BlockFace.getFaces().get(i)); + if (stack instanceof TileDataStackImpl) { + return ((TileDataStackImpl) stack).blockInChunk; + } + } + + return new Vec3i(blockInChunk); + } + + private static int getBlockIndex(Vec3i posInChunk) { + checkLocalCoordinates(posInChunk); + + return posInChunk.z * BLOCKS_PER_CHUNK * BLOCKS_PER_CHUNK + + posInChunk.y * BLOCKS_PER_CHUNK + + posInChunk.x; + } + + private static int getTileIndex(Vec3i posInChunk, BlockFace face) { + return getBlockIndex(posInChunk) * BLOCK_FACE_COUNT + + face.getId(); + } + + private static void checkLocalCoordinates(Vec3i posInChunk) { + if (!isInBounds(posInChunk)) { + throw new IllegalCoordinatesException( + "Coordinates " + str(posInChunk) + " " + + "are not legal chunk coordinates" + ); + } + } + + public static boolean isInBounds(Vec3i posInChunk) { + return posInChunk.x >= 0 && posInChunk.x < BLOCKS_PER_CHUNK && + posInChunk.y >= 0 && posInChunk.y < BLOCKS_PER_CHUNK && + posInChunk.z >= 0 && posInChunk.z < BLOCKS_PER_CHUNK; + } + + public boolean isBorder(Vec3i blockInChunk, BlockFace face) { + final int min = 0, max = BLOCKS_PER_CHUNK - 1; + return (blockInChunk.x == min && face == SOUTH) || + (blockInChunk.x == max && face == NORTH) || + (blockInChunk.y == min && face == EAST) || + (blockInChunk.y == max && face == WEST) || + (blockInChunk.z == min && face == BOTTOM) || + (blockInChunk.z == max && face == TOP); + } + + public void forEachBlock(Consumer action) { + VectorUtil.iterateCuboid( + 0, + 0, + 0, + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + action + ); + } + + public void forEachTileStack(Consumer action) { + forEachBlock(blockInChunk -> { + for (BlockFace face : BlockFace.getFaces()) { + TileDataStack stack = getTilesOrNull(blockInChunk, face); + if (stack == null) + continue; + action.accept(stack); + } + }); + } + + /** + * Iterates over all tiles in this chunk. + * + * @param action the action to perform. {@code TileLocation} refers to each + * tile using its primary block + */ + public void forEachTile(BiConsumer action) { + forEachTileStack(stack -> stack.forEach(tileData -> action.accept(stack, tileData))); + } + + public WorldData getWorld() { + return world; + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(ChunkDataListener listener) { + this.listeners.add(listener); + } + + public void removeListener(ChunkDataListener listener) { + this.listeners.remove(listener); + } + + private static String str(Vec3i v) { + return "(" + v.x + "; " + v.y + "; " + v.z + ")"; + } + + protected void onLoaded() { + getListeners().forEach(l -> l.onChunkLoaded(this)); + } + + protected void beforeUnloaded() { + getListeners().forEach(l -> l.beforeChunkUnloaded(this)); + } + + public Object getGenerationHint() { + return generationHint; + } + + public void setGenerationHint(Object generationHint) { + this.generationHint = generationHint; + } + + /** + * Implementation of {@link TileDataStack} used internally by + * {@link ChunkData} to + * actually store the tiles. This is basically an array wrapper with + * reporting + * capabilities. + * + * @author javapony + */ + private class TileDataStackImpl extends TileDataStack { + private class TileReferenceImpl implements TileReference { + private int index; + + public TileReferenceImpl(int index) { + this.index = index; + } + + public void incrementIndex() { + this.index++; + } + + public void decrementIndex() { + this.index--; + } + + public void invalidate() { + this.index = 0; + } + + @Override + public TileData get() { + if (!isValid()) + return null; + return TileDataStackImpl.this.get(this.index); + } + + @Override + public int getIndex() { + return index; + } + + @Override + public TileDataStack getStack() { + return TileDataStackImpl.this; + } + + @Override + public boolean isValid() { + return this.index >= 0; + } + } + + private final TileData[] tiles = new TileData[TILES_PER_FACE]; + private int size = 0; + + private final TileReferenceImpl[] references = new TileReferenceImpl[tiles.length]; + private final int[] indicesByTag = new int[tiles.length]; + private final int[] tagsByIndex = new int[tiles.length]; + + { + Arrays.fill(indicesByTag, -1); + Arrays.fill(tagsByIndex, -1); + } + + /* + * Potentially shared + */ + private final Vec3i blockInChunk; + private final BlockFace face; + + public TileDataStackImpl(Vec3i blockInChunk, BlockFace face) { + this.blockInChunk = blockInChunk; + this.face = face; + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + if (output == null) + output = new Vec3i(); + output.set(blockInChunk.x, blockInChunk.y, blockInChunk.z); + return output; + } + + @Override + public BlockFace getFace() { + return face; + } + + @Override + public ChunkData getChunk() { + return ChunkData.this; + } + + @Override + public int size() { + return size; + } + + @Override + public TileData get(int index) { + checkIndex(index, false); + + return tiles[index]; + } + + @Override + public TileData set(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + TileData previous = get(index); // checks index + + tiles[index] = tile; + + if (references[index] != null) { + references[index].invalidate(); + references[index] = null; + } + + assert checkConsistency(); + + report(previous, tile); + return previous; + } + + @Override + public void add(int index, TileData tile) { + Objects.requireNonNull(tile, "tile"); + checkIndex(index, true); + + if (index != size()) { + System.arraycopy(tiles, index + 1, tiles, index + 2, size - index); + + for (int i = index; i < size; ++i) { + if (references[i] != null) { + references[i].incrementIndex(); + } + + indicesByTag[tagsByIndex[i]]++; + } + + System.arraycopy(references, index + 1, references, index + 2, size - index); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index + 2, size - index); + } + + size++; + tiles[index] = tile; + references[index] = null; + + for (int tag = 0; tag < indicesByTag.length; ++tag) { + if (tagsByIndex[tag] == -1) { + indicesByTag[tag] = index; + tagsByIndex[index] = tag; + break; + } + } + + modCount++; + assert checkConsistency(); + + report(null, tile); + } + + @Override + public void load(TileData tile, int tag) { + addFarthest(tile); + + int assignedTag = getIndexByTag(tag); + + if (assignedTag == tag) + return; + if (assignedTag == -1) { + throw new IllegalArgumentException( + "Tag " + tag + " already used by tile at index " + getIndexByTag(tag) + ); + } + + indicesByTag[tagsByIndex[size() - 1]] = -1; + tagsByIndex[size() - 1] = tag; + indicesByTag[tag] = size() - 1; + + assert checkConsistency(); + } + + @Override + public TileData remove(int index) { + TileData previous = get(index); // checks index + + if (references[index] != null) { + references[index].invalidate(); + } + + indicesByTag[tagsByIndex[index]] = -1; + + if (index != size() - 1) { + System.arraycopy(tiles, index + 1, tiles, index, size - index - 1); + + for (int i = index + 1; i < size; ++i) { + if (references[i] != null) { + references[i].decrementIndex(); + } + + indicesByTag[tagsByIndex[i]]--; + } + + System.arraycopy(references, index + 1, references, index, size - index - 1); + System.arraycopy(tagsByIndex, index + 1, tagsByIndex, index, size - index - 1); + } + + size--; + tiles[size] = null; + references[size] = null; + tagsByIndex[size] = -1; + + modCount++; + assert checkConsistency(); + + report(previous, null); + return previous; + } + + @Override + public TileReference getReference(int index) { + checkIndex(index, false); + + if (references[index] == null) { + references[index] = new TileReferenceImpl(index); + } + + return references[index]; + } + + @Override + public int getIndexByTag(int tag) { + return indicesByTag[tag]; + } + + @Override + public int getTagByIndex(int index) { + checkIndex(index, false); + return tagsByIndex[index]; + } + + @Override + public void clear() { + while (!isEmpty()) { + removeFarthest(); + } + } + + private void checkIndex(int index, boolean isSizeAllowed) { + if (isSizeAllowed ? (index > size()) : (index >= size())) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: size is " + size); + + if (index < 0) + throw new IndexOutOfBoundsException("Index " + index + " is out of bounds: index cannot be negative"); + + if (index >= TILES_PER_FACE) + throw new TileStackIsFullException( + "Index " + index + " is out of bounds: maximum tile stack size is " + TILES_PER_FACE + ); + } + + private void report(TileData previous, TileData current) { + ChunkData.this.getListeners().forEach(l -> { + if (previous != null) { + l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, previous, false); + } + + if (current != null) { + l.onChunkTilesChanged(ChunkData.this, blockInChunk, face, current, true); + } + + l.onChunkChanged(ChunkData.this); + }); + } + + private boolean checkConsistency() { + int index; + + for (index = 0; index < size(); ++index) { + if (get(index) == null) + throw new AssertionError("get(index) is null"); + + if (references[index] != null) { + TileReference ref = getReference(index); + if (ref == null) + throw new AssertionError("references[index] is not null but getReference(index) is"); + if (!ref.isValid()) + throw new AssertionError("Reference is not valid"); + if (ref.get() != get(index)) + throw new AssertionError("Reference points to " + (ref.get() == null ? "null" : "wrong tile")); + if (ref.getIndex() != index) + throw new AssertionError("Reference has invalid index"); + if (ref.getStack() != this) + throw new AssertionError("Reference has invalid TDS"); + } + + if (index != indicesByTag[tagsByIndex[index]]) + throw new AssertionError("Tag mapping is inconsistent"); + if (index != getIndexByTag(getTagByIndex(index))) + throw new AssertionError("Tag methods are inconsistent with tag mapping"); + } + + for (; index < tiles.length; ++index) { + if (tiles[index] != null) + throw new AssertionError("Leftover tile detected"); + if (references[index] != null) + throw new AssertionError("Leftover reference detected"); + if (tagsByIndex[index] != -1) + throw new AssertionError("Leftover tags detected"); + } + + return true; + } + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java index 216617e..72008c4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListener.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; @@ -6,46 +24,69 @@ import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface ChunkDataListener { - + /** * Invoked after a block has changed in a chunk. - * This is not triggered when a change is caused by chunk loading or unloading. - * @param chunk the chunk that has changed - * @param blockInChunk the {@linkplain Coordinates#blockInChunk chunk coordinates} of the change - * @param previous the previous occupant of {@code blockInChunk} - * @param current the current (new) occupant of {@code blockInChunk} + * This is not triggered when a change is caused by chunk loading or + * unloading. + * + * @param chunk the chunk that has changed + * @param blockInChunk the {@linkplain Coordinates#blockInChunk chunk + * coordinates} of the change + * @param previous the previous occupant of {@code blockInChunk} + * @param current the current (new) occupant of {@code blockInChunk} */ - default void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) {} - + default void onChunkBlockChanged(ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current) { + } + /** * Invoked after a tile has been added or removed from a chunk. - * This is not triggered when a change is caused by chunk loading or unloading. - * @param chunk the chunk that has changed - * @param blockInChunk the {@linkplain Coordinates#blockInChunk chunk coordinates} of the change - * @param face the face that the changed tile belongs or belonged to - * @param tile the tile that has been added or removed - * @param wasAdded {@code true} iff the tile has been added, {@code false} iff the tile has been removed + * This is not triggered when a change is caused by chunk loading or + * unloading. + * + * @param chunk the chunk that has changed + * @param blockInChunk the {@linkplain Coordinates#blockInChunk chunk + * coordinates} of the change + * @param face the face that the changed tile belongs or belonged to + * @param tile the tile that has been added or removed + * @param wasAdded {@code true} iff the tile has been added, + * {@code false} iff the tile has been removed */ - default void onChunkTilesChanged(ChunkData chunk, Vec3i blockInChunk, BlockFace face, TileData tile, boolean wasAdded) {} - + default void onChunkTilesChanged( + ChunkData chunk, + Vec3i blockInChunk, + BlockFace face, + TileData tile, + boolean wasAdded + ) { + } + /** - * Invoked whenever a chunk changes, loads or unloads. If some other method in this - * {@code ChunkDataListener} are to be invoked, e.g. is the change was caused by a + * Invoked whenever a chunk changes, loads or unloads. If some other method + * in this + * {@code ChunkDataListener} are to be invoked, e.g. is the change was + * caused by a * block being removed, this method is called last. + * * @param chunk the chunk that has changed */ - default void onChunkChanged(ChunkData chunk) {} - + default void onChunkChanged(ChunkData chunk) { + } + /** * Invoked whenever a chunk has been loaded. + * * @param chunk the chunk that has loaded */ - default void onChunkLoaded(ChunkData chunk) {} - + default void onChunkLoaded(ChunkData chunk) { + } + /** * Invoked whenever a chunk is about to be unloaded. + * * @param chunk the chunk that is going to be loaded */ - default void beforeChunkUnloaded(ChunkData chunk) {} + default void beforeChunkUnloaded(ChunkData chunk) { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java index e0ca46a..b39437c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java +++ b/src/main/java/ru/windcorp/progressia/common/world/ChunkDataListeners.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import java.util.function.Consumer; @@ -6,7 +24,7 @@ import java.util.function.Supplier; import glm.vec._3.i.Vec3i; public class ChunkDataListeners { - + public static WorldDataListener createAdder(Supplier listenerSupplier) { return new WorldDataListener() { @Override @@ -15,11 +33,12 @@ public class ChunkDataListeners { } }; } - + public static WorldDataListener createAdder(ChunkDataListener listener) { return createAdder(() -> listener); } - - private ChunkDataListeners() {} + + private ChunkDataListeners() { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java index 7bd06ce..55fc4bc 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java +++ b/src/main/java/ru/windcorp/progressia/common/world/Coordinates.java @@ -1,146 +1,162 @@ -package ru.windcorp.progressia.common.world; - -import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; - -import glm.vec._3.i.Vec3i; - -/** - * Contains static methods to convert world block coordinates, chunk block - * coordinates and chunk coordinates. - *

- * Three types of coordinates are used in Progressia: - *

    - * - *
  • World coordinates, in code referred to as {@code blockInWorld} - - * coordinates relative to world origin. Every block in the world has unique - * world coordinates.
  • - * - *
  • Chunk coordinates, in code referred to as {@code blockInChunk} - - * coordinates relative some chunk's origin. Every block in the chunk has unique - * chunk coordinates, but blocks in different chunks may have identical chunk - * coordinates. These coordinates are only useful in combination with a chunk - * reference. Chunk coordinates are always [0; {@link #BLOCKS_PER_CHUNK}).
  • - * - *
  • Coordinates of chunk, in code referred to as {@code chunk} - - * chunk coordinates relative to world origin. Every chunk in the world has - * unique coordinates of chunk.
  • - * - *
- */ -public class Coordinates { - - public static final int BITS_IN_CHUNK_COORDS = 4; - public static final int CHUNK_SIZE = 1 << BITS_IN_CHUNK_COORDS; - public static final int CHUNK_COORDS_MASK = CHUNK_SIZE - 1; - - /** - * Computes the coordinate of the chunk that the block specified by the - * provided world coordinate belongs to. - * - * @param blockInWorld world coordinate of the block - * @return the corresponding coordinate of the chunk containing the block - * - * @see #convertInWorldToChunk(Vec3i, Vec3i) - */ - public static int convertInWorldToChunk(int blockInWorld) { - return blockInWorld >> BITS_IN_CHUNK_COORDS; - } - - /** - * Computes the coordinates of the chunk that the block specified by the - * provided world coordinates belongs to. - * - * @param blockInWorld world coordinates of the block - * @param output a {@link Vec3i} to store the result in - * @return {@code output} - * - * @see #convertInWorldToChunk(int) - */ - public static Vec3i convertInWorldToChunk( - Vec3i blockInWorld, - Vec3i output - ) { - if (output == null) output = new Vec3i(); - - output.x = convertInWorldToChunk(blockInWorld.x); - output.y = convertInWorldToChunk(blockInWorld.y); - output.z = convertInWorldToChunk(blockInWorld.z); - - return output; - } - - /** - * Computes the chunk coordinate that the block specified by the - * provided world coordinate has in its chunk. - * - * @param blockInWorld world coordinate of the block - * @return the corresponding chunk coordinate of the block - * - * @see #convertInWorldToInChunk(Vec3i, Vec3i) - */ - public static int convertInWorldToInChunk(int blockInWorld) { - return blockInWorld & CHUNK_COORDS_MASK; - } - - /** - * Computes the chunk coordinates that the block specified by the - * provided world coordinates has in its chunk. - * - * @param blockInWorld world coordinates of the block - * @param output a {@link Vec3i} to store the result in - * @return {@code output} - * - * @see #convertInWorldToInChunk(int) - */ - public static Vec3i convertInWorldToInChunk( - Vec3i blockInWorld, - Vec3i output - ) { - if (output == null) output = new Vec3i(); - - output.x = convertInWorldToInChunk(blockInWorld.x); - output.y = convertInWorldToInChunk(blockInWorld.y); - output.z = convertInWorldToInChunk(blockInWorld.z); - - return output; - } - - /** - * Computes the world coordinate of the block specified by its chunk - * coordinate and the coordinate of its chunk. - * - * @param chunk coordinate of chunk - * @param blockInChunk chunk coordinate of block - * @return corresponding world coordinate - * - * @see #getInWorld(int, int) - */ - public static int getInWorld(int chunk, int blockInChunk) { - return blockInChunk | (chunk << BITS_IN_CHUNK_COORDS); - } - - /** - * Computes the world coordinates of the block specified by its chunk - * coordinates and the coordinates of its chunk. - * - * @param chunk coordinate of chunk - * @param blockInChunk chunk coordinate of block - * @param output a {@link Vec3i} to store the result in - * @return {@code output} - * - * @see #getInWorld(int) - */ - public static Vec3i getInWorld( - Vec3i chunk, Vec3i blockInChunk, - Vec3i output - ) { - if (output == null) output = new Vec3i(); - - output.x = getInWorld(chunk.x, blockInChunk.x); - output.y = getInWorld(chunk.y, blockInChunk.y); - output.z = getInWorld(chunk.z, blockInChunk.z); - - return output; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; + +import glm.vec._3.i.Vec3i; + +/** + * Contains static methods to convert world block coordinates, chunk block + * coordinates and chunk coordinates. + *

+ * Three types of coordinates are used in Progressia: + *

    + *
  • World coordinates, in code referred to as + * {@code blockInWorld} - + * coordinates relative to world origin. Every block in the world has unique + * world coordinates.
  • + *
  • Chunk coordinates, in code referred to as + * {@code blockInChunk} - + * coordinates relative some chunk's origin. Every block in the chunk has unique + * chunk coordinates, but blocks in different chunks may have identical chunk + * coordinates. These coordinates are only useful in combination with a chunk + * reference. Chunk coordinates are always + * [0; {@link #BLOCKS_PER_CHUNK}).
  • + *
  • Coordinates of chunk, in code referred to as + * {@code chunk} - + * chunk coordinates relative to world origin. Every chunk in the world has + * unique coordinates of chunk.
  • + *
+ */ +public class Coordinates { + + public static final int BITS_IN_CHUNK_COORDS = 4; + public static final int CHUNK_SIZE = 1 << BITS_IN_CHUNK_COORDS; + public static final int CHUNK_COORDS_MASK = CHUNK_SIZE - 1; + + /** + * Computes the coordinate of the chunk that the block specified by the + * provided world coordinate belongs to. + * + * @param blockInWorld world coordinate of the block + * @return the corresponding coordinate of the chunk containing the block + * @see #convertInWorldToChunk(Vec3i, Vec3i) + */ + public static int convertInWorldToChunk(int blockInWorld) { + return blockInWorld >> BITS_IN_CHUNK_COORDS; + } + + /** + * Computes the coordinates of the chunk that the block specified by the + * provided world coordinates belongs to. + * + * @param blockInWorld world coordinates of the block + * @param output a {@link Vec3i} to store the result in + * @return {@code output} + * @see #convertInWorldToChunk(int) + */ + public static Vec3i convertInWorldToChunk( + Vec3i blockInWorld, + Vec3i output + ) { + if (output == null) + output = new Vec3i(); + + output.x = convertInWorldToChunk(blockInWorld.x); + output.y = convertInWorldToChunk(blockInWorld.y); + output.z = convertInWorldToChunk(blockInWorld.z); + + return output; + } + + /** + * Computes the chunk coordinate that the block specified by the + * provided world coordinate has in its chunk. + * + * @param blockInWorld world coordinate of the block + * @return the corresponding chunk coordinate of the block + * @see #convertInWorldToInChunk(Vec3i, Vec3i) + */ + public static int convertInWorldToInChunk(int blockInWorld) { + return blockInWorld & CHUNK_COORDS_MASK; + } + + /** + * Computes the chunk coordinates that the block specified by the + * provided world coordinates has in its chunk. + * + * @param blockInWorld world coordinates of the block + * @param output a {@link Vec3i} to store the result in + * @return {@code output} + * @see #convertInWorldToInChunk(int) + */ + public static Vec3i convertInWorldToInChunk( + Vec3i blockInWorld, + Vec3i output + ) { + if (output == null) + output = new Vec3i(); + + output.x = convertInWorldToInChunk(blockInWorld.x); + output.y = convertInWorldToInChunk(blockInWorld.y); + output.z = convertInWorldToInChunk(blockInWorld.z); + + return output; + } + + /** + * Computes the world coordinate of the block specified by its chunk + * coordinate and the coordinate of its chunk. + * + * @param chunk coordinate of chunk + * @param blockInChunk chunk coordinate of block + * @return corresponding world coordinate + * @see #getInWorld(int, int) + */ + public static int getInWorld(int chunk, int blockInChunk) { + return blockInChunk | (chunk << BITS_IN_CHUNK_COORDS); + } + + /** + * Computes the world coordinates of the block specified by its chunk + * coordinates and the coordinates of its chunk. + * + * @param chunk coordinate of chunk + * @param blockInChunk chunk coordinate of block + * @param output a {@link Vec3i} to store the result in + * @return {@code output} + * @see #getInWorld(int) + */ + public static Vec3i getInWorld( + Vec3i chunk, + Vec3i blockInChunk, + Vec3i output + ) { + if (output == null) + output = new Vec3i(); + + output.x = getInWorld(chunk.x, blockInChunk.x); + output.y = getInWorld(chunk.y, blockInChunk.y); + output.z = getInWorld(chunk.z, blockInChunk.z); + + return output; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java b/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java index 0dac53d..532d22f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/DecodingException.java @@ -1,7 +1,26 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; /** * Thrown to indicate that some data could not be properly decoded. + * * @author javapony */ public class DecodingException extends Exception { diff --git a/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java b/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java index aba1390..69240cf 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/IllegalCoordinatesException.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; public class IllegalCoordinatesException extends RuntimeException { @@ -20,8 +38,12 @@ public class IllegalCoordinatesException extends RuntimeException { super(message, cause); } - public IllegalCoordinatesException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { + public IllegalCoordinatesException( + String message, + Throwable cause, + boolean enableSuppression, + boolean writableStackTrace + ) { super(message, cause, enableSuppression, writableStackTrace); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java index fd5282c..95e6eab 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectChunk.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import glm.vec._3.i.Vec3i; diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java index 1aad748..8433b9b 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketAffectWorld.java @@ -1,13 +1,31 @@ -package ru.windcorp.progressia.common.world; - -import ru.windcorp.progressia.common.comms.packets.Packet; - -public abstract class PacketAffectWorld extends Packet { - - public PacketAffectWorld(String id) { - super(id); - } - - public abstract void apply(WorldData world); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import ru.windcorp.progressia.common.comms.packets.Packet; + +public abstract class PacketAffectWorld extends Packet { + + public PacketAffectWorld(String id) { + super(id); + } + + public abstract void apply(WorldData world); + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java index faf6331..c65b045 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketRevokeChunk.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import java.io.DataInput; @@ -7,9 +25,9 @@ import java.io.IOException; import glm.vec._3.i.Vec3i; public class PacketRevokeChunk extends PacketAffectChunk { - + private final Vec3i position = new Vec3i(); - + public PacketRevokeChunk() { this("Core:RevokeChunk"); } @@ -17,16 +35,16 @@ public class PacketRevokeChunk extends PacketAffectChunk { protected PacketRevokeChunk(String id) { super(id); } - + public void set(Vec3i chunkPos) { this.position.set(chunkPos.x, chunkPos.y, chunkPos.z); } - + @Override public void read(DataInput input) throws IOException { this.position.set(input.readInt(), input.readInt(), input.readInt()); } - + @Override public void write(DataOutput output) throws IOException { output.writeInt(this.position.x); @@ -43,12 +61,12 @@ public class PacketRevokeChunk extends PacketAffectChunk { } } } - + @Override public void getAffectedChunk(Vec3i output) { output.set(getPosition().x, getPosition().y, getPosition().z); } - + public Vec3i getPosition() { return position; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java index 6dc2b90..ca079ff 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSendChunk.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import java.io.DataInput; @@ -11,10 +29,10 @@ import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.world.io.ChunkIO; public class PacketSendChunk extends PacketAffectChunk { - + private final DataBuffer data = new DataBuffer(); private final Vec3i position = new Vec3i(); - + public PacketSendChunk() { this("Core:SendChunk"); } @@ -22,23 +40,23 @@ public class PacketSendChunk extends PacketAffectChunk { protected PacketSendChunk(String id) { super(id); } - + public void set(ChunkData chunk) { this.position.set(chunk.getX(), chunk.getY(), chunk.getZ()); - + try { ChunkIO.save(chunk, this.data.getWriter(), IOContext.COMMS); } catch (IOException e) { // Impossible } } - + @Override public void read(DataInput input) throws IOException { this.position.set(input.readInt(), input.readInt(), input.readInt()); this.data.fill(input, input.readInt()); } - + @Override public void write(DataOutput output) throws IOException { output.writeInt(this.position.x); @@ -56,16 +74,16 @@ public class PacketSendChunk extends PacketAffectChunk { throw CrashReports.report(e, "Could not load chunk"); } } - + @Override public void getAffectedChunk(Vec3i output) { output.set(getPosition().x, getPosition().y, getPosition().z); } - + public Vec3i getPosition() { return position; } - + public DataBuffer getData() { return data; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java b/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java index 4eda94f..f835614 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PacketSetLocalPlayer.java @@ -1,39 +1,57 @@ -package ru.windcorp.progressia.common.world; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import ru.windcorp.progressia.common.comms.packets.Packet; - -public class PacketSetLocalPlayer extends Packet { - - private long entityId; - - public PacketSetLocalPlayer() { - this("Core:SetLocalPlayer"); - } - - protected PacketSetLocalPlayer(String id) { - super(id); - } - - public void set(long entityId) { - this.entityId = entityId; - } - - @Override - public void read(DataInput input) throws IOException, DecodingException { - this.entityId = input.readLong(); - } - - @Override - public void write(DataOutput output) throws IOException { - output.writeLong(this.entityId); - } - - public long getEntityId() { - return entityId; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.comms.packets.Packet; + +public class PacketSetLocalPlayer extends Packet { + + private long entityId; + + public PacketSetLocalPlayer() { + this("Core:SetLocalPlayer"); + } + + protected PacketSetLocalPlayer(String id) { + super(id); + } + + public void set(long entityId) { + this.entityId = entityId; + } + + @Override + public void read(DataInput input) throws IOException, DecodingException { + this.entityId = input.readLong(); + } + + @Override + public void write(DataOutput output) throws IOException { + output.writeLong(this.entityId); + } + + public long getEntityId() { + return entityId; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java b/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java index b56df0c..2123e3f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/PlayerData.java @@ -1,15 +1,33 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import ru.windcorp.progressia.common.world.entity.EntityData; public class PlayerData { - + private EntityData entity; public PlayerData(EntityData entity) { this.entity = entity; } - + public EntityData getEntity() { return entity; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java index c4d69ef..85c6188 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldData.java @@ -1,215 +1,216 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.map.TLongObjectMap; -import gnu.trove.map.hash.TLongObjectHashMap; -import gnu.trove.set.TLongSet; -import ru.windcorp.progressia.common.collision.CollisionModel; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.ChunkMap; -import ru.windcorp.progressia.common.world.generic.ChunkSet; -import ru.windcorp.progressia.common.world.generic.GenericWorld; -import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; - -public class WorldData -implements GenericWorld< - BlockData, - TileData, - TileDataStack, - ChunkData, - EntityData -> { - - private final ChunkMap chunksByPos = new LongBasedChunkMap<>( - TCollections.synchronizedMap(new TLongObjectHashMap<>()) - ); - - private final Collection chunks = - Collections.unmodifiableCollection(chunksByPos.values()); - - private final TLongObjectMap entitiesById = - TCollections.synchronizedMap(new TLongObjectHashMap<>()); - - private final Collection entities = - Collections.unmodifiableCollection(entitiesById.valueCollection()); - - private float time = 0; - - private final Collection listeners = - Collections.synchronizedCollection(new ArrayList<>()); - - public WorldData() { - - } - - @Override - public ChunkData getChunk(Vec3i pos) { - return chunksByPos.get(pos); - } - - @Override - public Collection getChunks() { - return chunks; - } - - public ChunkSet getLoadedChunks() { - return chunksByPos.keys(); - } - - @Override - public Collection getEntities() { - return entities; - } - - @Override - public void forEachEntity(Consumer action) { - synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF TROVE4J so that gnu.trove.impl.sync.SynchronizedCollection.forEach is synchronized - getEntities().forEach(action); - } - } - - - public TLongSet getLoadedEntities() { - return entitiesById.keySet(); - } - - private void addChunkListeners(ChunkData chunk) { - getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); - } - - public synchronized void addChunk(ChunkData chunk) { - addChunkListeners(chunk); - - ChunkData previous = chunksByPos.get(chunk); - if (previous != null) { - throw new IllegalArgumentException(String.format( - "Chunk at (%d; %d; %d) already exists", - chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z - )); - } - - chunksByPos.put(chunk, chunk); - - chunk.onLoaded(); - getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); - } - - public synchronized void removeChunk(ChunkData chunk) { - getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); - chunk.beforeUnloaded(); - - chunksByPos.remove(chunk); - } - - public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) - throw new IllegalCoordinatesException( - "Coordinates " - + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " - + "do not belong to a loaded chunk" - ); - - chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); - } - - public EntityData getEntity(long entityId) { - return entitiesById.get(entityId); - } - - public void addEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); - - if (previous != null) { - String message = "Cannot add entity " + entity + ": "; - - if (previous == entity) { - message += "already present"; - } else { - message += "entity with the same EntityID already present (" + previous + ")"; - } - - throw new IllegalStateException(message); - } - - getListeners().forEach(l -> l.onEntityAdded(this, entity)); - } - - public void removeEntity(long entityId) { - synchronized (entitiesById) { - EntityData entity = entitiesById.get(entityId); - - if (entity == null) { - throw new IllegalArgumentException("Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present"); - } else { - removeEntity(entity); - } - } - } - - public void removeEntity(EntityData entity) { - Objects.requireNonNull(entity, "entity"); - - getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); - entitiesById.remove(entity.getEntityId()); - } - - public float getTime() { - return time; - } - - public void advanceTime(float change) { - this.time += change; - } - - public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { - ChunkData chunk = getChunkByBlock(blockInWorld); - if (chunk == null) return null; - - BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); - if (block == null) return null; - return block.getCollisionModel(); - } - - public Collection getListeners() { - return listeners; - } - - public void addListener(WorldDataListener e) { - listeners.add(e); - } - - public void removeListener(WorldDataListener o) { - listeners.remove(o); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.map.TLongObjectMap; +import gnu.trove.map.hash.TLongObjectHashMap; +import gnu.trove.set.TLongSet; +import ru.windcorp.progressia.common.collision.CollisionModel; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.ChunkMap; +import ru.windcorp.progressia.common.world.generic.ChunkSet; +import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.common.world.generic.LongBasedChunkMap; +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataStack; + +public class WorldData + implements GenericWorld { + + private final ChunkMap chunksByPos = new LongBasedChunkMap<>( + TCollections.synchronizedMap(new TLongObjectHashMap<>()) + ); + + private final Collection chunks = Collections.unmodifiableCollection(chunksByPos.values()); + + private final TLongObjectMap entitiesById = TCollections.synchronizedMap(new TLongObjectHashMap<>()); + + private final Collection entities = Collections.unmodifiableCollection(entitiesById.valueCollection()); + + private float time = 0; + + private final Collection listeners = Collections.synchronizedCollection(new ArrayList<>()); + + public WorldData() { + + } + + @Override + public ChunkData getChunk(Vec3i pos) { + return chunksByPos.get(pos); + } + + @Override + public Collection getChunks() { + return chunks; + } + + public ChunkSet getLoadedChunks() { + return chunksByPos.keys(); + } + + @Override + public Collection getEntities() { + return entities; + } + + @Override + public void forEachEntity(Consumer action) { + synchronized (entitiesById) { // TODO HORRIBLY MUTILATE THE CORPSE OF + // TROVE4J so that + // gnu.trove.impl.sync.SynchronizedCollection.forEach + // is synchronized + getEntities().forEach(action); + } + } + + public TLongSet getLoadedEntities() { + return entitiesById.keySet(); + } + + private void addChunkListeners(ChunkData chunk) { + getListeners().forEach(l -> l.getChunkListeners(this, chunk.getPosition(), chunk::addListener)); + } + + public synchronized void addChunk(ChunkData chunk) { + addChunkListeners(chunk); + + ChunkData previous = chunksByPos.get(chunk); + if (previous != null) { + throw new IllegalArgumentException( + String.format( + "Chunk at (%d; %d; %d) already exists", + chunk.getPosition().x, + chunk.getPosition().y, + chunk.getPosition().z + ) + ); + } + + chunksByPos.put(chunk, chunk); + + chunk.onLoaded(); + getListeners().forEach(l -> l.onChunkLoaded(this, chunk)); + } + + public synchronized void removeChunk(ChunkData chunk) { + getListeners().forEach(l -> l.beforeChunkUnloaded(this, chunk)); + chunk.beforeUnloaded(); + + chunksByPos.remove(chunk); + } + + public void setBlock(Vec3i blockInWorld, BlockData block, boolean notify) { + ChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + throw new IllegalCoordinatesException( + "Coordinates " + + "(" + blockInWorld.x + "; " + blockInWorld.y + "; " + blockInWorld.z + ") " + + "do not belong to a loaded chunk" + ); + + chunk.setBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null), block, notify); + } + + public EntityData getEntity(long entityId) { + return entitiesById.get(entityId); + } + + public void addEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + EntityData previous = entitiesById.putIfAbsent(entity.getEntityId(), entity); + + if (previous != null) { + String message = "Cannot add entity " + entity + ": "; + + if (previous == entity) { + message += "already present"; + } else { + message += "entity with the same EntityID already present (" + previous + ")"; + } + + throw new IllegalStateException(message); + } + + getListeners().forEach(l -> l.onEntityAdded(this, entity)); + } + + public void removeEntity(long entityId) { + synchronized (entitiesById) { + EntityData entity = entitiesById.get(entityId); + + if (entity == null) { + throw new IllegalArgumentException( + "Entity with EntityID " + EntityData.formatEntityId(entityId) + " not present" + ); + } else { + removeEntity(entity); + } + } + } + + public void removeEntity(EntityData entity) { + Objects.requireNonNull(entity, "entity"); + + getListeners().forEach(l -> l.beforeEntityRemoved(this, entity)); + entitiesById.remove(entity.getEntityId()); + } + + public float getTime() { + return time; + } + + public void advanceTime(float change) { + this.time += change; + } + + public CollisionModel getCollisionModelOfBlock(Vec3i blockInWorld) { + ChunkData chunk = getChunkByBlock(blockInWorld); + if (chunk == null) + return null; + + BlockData block = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, null)); + if (block == null) + return null; + return block.getCollisionModel(); + } + + public Collection getListeners() { + return listeners; + } + + public void addListener(WorldDataListener e) { + listeners.add(e); + } + + public void removeListener(WorldDataListener o) { + listeners.remove(o); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java index 19469fa..9211efd 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java +++ b/src/main/java/ru/windcorp/progressia/common/world/WorldDataListener.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world; import java.util.function.Consumer; @@ -6,44 +24,60 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.entity.EntityData; public interface WorldDataListener { - + /** - * Invoked when a new {@link ChunkData} instance is created. This method should be used to add - * {@link ChunkDataListener}s to a new chunk. When listeners are added with this method, - * their {@link ChunkDataListener#onChunkLoaded(ChunkData) onChunkLoaded} methods will be invoked. - * @param world the world instance - * @param chunk the {@linkplain Coordinates#chunk coordinates of chunk} of the chunk about to load - * @param chunkListenerSink a sink for listeners. All listeners passed to its - * {@link Consumer#accept(Object) accept} method will be added to the chunk. + * Invoked when a new {@link ChunkData} instance is created. This method + * should be used to add + * {@link ChunkDataListener}s to a new chunk. When listeners are added with + * this method, + * their {@link ChunkDataListener#onChunkLoaded(ChunkData) onChunkLoaded} + * methods will be invoked. + * + * @param world the world instance + * @param chunk the {@linkplain Coordinates#chunk coordinates of + * chunk} of the chunk about to load + * @param chunkListenerSink a sink for listeners. All listeners passed to + * its + * {@link Consumer#accept(Object) accept} method + * will be added to the chunk. */ - default void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) {} - + default void getChunkListeners(WorldData world, Vec3i chunk, Consumer chunkListenerSink) { + } + /** * Invoked whenever a {@link Chunk} has been loaded. + * * @param world the world instance * @param chunk the chunk that has loaded */ - default void onChunkLoaded(WorldData world, ChunkData chunk) {} - + default void onChunkLoaded(WorldData world, ChunkData chunk) { + } + /** * Invoked whenever a {@link Chunk} is about to be unloaded. + * * @param world the world instance * @param chunk the chunk that is going to be unloaded */ - default void beforeChunkUnloaded(WorldData world, ChunkData chunk) {} - + default void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + } + /** * Invoked whenever an {@link EntityData} has been added. - * @param world the world instance + * + * @param world the world instance * @param entity the entity that has been added */ - default void onEntityAdded(WorldData world, EntityData entity) {} - + default void onEntityAdded(WorldData world, EntityData entity) { + } + /** * Invoked whenever an {@link EntityData} is about to be removed. - * @param world the world instance + * + * @param world the world instance * @param entity the entity that is going to be removed */ - default void beforeEntityRemoved(WorldData world, EntityData entity) {} + default void beforeEntityRemoved(WorldData world, EntityData entity) { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java index 0e0cefb..e94f838 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockData.java @@ -1,35 +1,36 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world.block; - -import ru.windcorp.progressia.common.collision.AABB; -import ru.windcorp.progressia.common.collision.CollisionModel; -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericBlock; - -public class BlockData extends Namespaced implements GenericBlock { - - public BlockData(String id) { - super(id); - } - - public CollisionModel getCollisionModel() { - return AABB.UNIT_CUBE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.block; + +import ru.windcorp.progressia.common.collision.AABB; +import ru.windcorp.progressia.common.collision.CollisionModel; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.generic.GenericBlock; + +public class BlockData extends Namespaced implements GenericBlock { + + public BlockData(String id) { + super(id); + } + + public CollisionModel getCollisionModel() { + return AABB.UNIT_CUBE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java index f3541a3..ac1934c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockDataRegistry.java @@ -1,30 +1,31 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world.block; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class BlockDataRegistry extends NamespacedInstanceRegistry { - - private static final BlockDataRegistry INSTANCE = new BlockDataRegistry(); - - public static BlockDataRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.block; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class BlockDataRegistry extends NamespacedInstanceRegistry { + + private static final BlockDataRegistry INSTANCE = new BlockDataRegistry(); + + public static BlockDataRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java index e0aa6e1..9023500 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockFace.java @@ -1,169 +1,177 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world.block; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -import glm.vec._3.i.Vec3i; - -public final class BlockFace extends BlockRelation { - - public static final BlockFace - TOP = new BlockFace( 0, 0, +1, true, "TOP"), - BOTTOM = new BlockFace( 0, 0, -1, false, "BOTTOM"), - NORTH = new BlockFace(+1, 0, 0, true, "NORTH"), - SOUTH = new BlockFace(-1, 0, 0, false, "SOUTH"), - WEST = new BlockFace( 0, +1, 0, false, "WEST"), - EAST = new BlockFace( 0, -1, 0, true, "EAST"); - - private static final ImmutableList ALL_FACES = - ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST); - - static { - link(TOP, BOTTOM); - link(NORTH, SOUTH); - link(WEST, EAST); - } - - private static final ImmutableList PRIMARY_FACES = - ALL_FACES.stream().filter(BlockFace::isPrimary).collect(ImmutableList.toImmutableList()); - - private static final ImmutableList SECONDARY_FACES = - ALL_FACES.stream().filter(BlockFace::isSecondary).collect(ImmutableList.toImmutableList()); - - public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); - public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); - public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); - - public static ImmutableList getFaces() { - return ALL_FACES; - } - - public static ImmutableList getPrimaryFaces() { - return PRIMARY_FACES; - } - - public static ImmutableList getSecondaryFaces() { - return SECONDARY_FACES; - } - - private static void link(BlockFace a, BlockFace b) { - a.counterFace = b; - b.counterFace = a; - } - - public static ImmutableMap mapToFaces( - E top, E bottom, - E north, E south, - E east, E west - ) { - return ImmutableMap.builderWithExpectedSize(6) - .put(TOP, top) - .put(BOTTOM, bottom) - .put(NORTH, north) - .put(SOUTH, south) - .put(EAST, east) - .put(WEST, west) - .build(); - } - - private static int nextId = 0; - - private final int id; - private final String name; - private BlockFace counterFace; - private final boolean isPrimary; - - private BlockFace(int x, int y, int z, boolean isPrimary, String name) { - super(x, y, z); - this.id = nextId++; - this.isPrimary = isPrimary; - this.name = name; - } - - public String getName() { - return name; - } - - public boolean isPrimary() { - return isPrimary; - } - - public BlockFace getPrimary() { - if (isPrimary) return this; - else return counterFace; - } - - public BlockFace getPrimaryAndMoveCursor(Vec3i cursor) { - if (isPrimary) return this; - - cursor.add(getVector()); - return counterFace; - } - - public boolean isSecondary() { - return !isPrimary; - } - - public BlockFace getSecondary() { - if (isPrimary) return counterFace; - else return this; - } - - public BlockFace getSecondaryAndMoveCursor(Vec3i cursor) { - if (!isPrimary) return this; - - cursor.add(getVector()); - return counterFace; - } - - public BlockFace getCounter() { - return counterFace; - } - - public BlockFace getCounterAndMoveCursor(Vec3i cursor) { - cursor.add(getVector()); - return counterFace; - } - - public int getId() { - return id; - } - - @Override - public float getEuclideanDistance() { - return 1.0f; - } - - @Override - public int getChebyshevDistance() { - return 1; - } - - @Override - public int getManhattanDistance() { - return 1; - } - - @Override - public String toString() { - return getName(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.block; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +import glm.vec._3.i.Vec3i; + +public final class BlockFace extends BlockRelation { + + public static final BlockFace TOP = new BlockFace(0, 0, +1, true, "TOP"), + BOTTOM = new BlockFace(0, 0, -1, false, "BOTTOM"), + NORTH = new BlockFace(+1, 0, 0, true, "NORTH"), + SOUTH = new BlockFace(-1, 0, 0, false, "SOUTH"), + WEST = new BlockFace(0, +1, 0, false, "WEST"), + EAST = new BlockFace(0, -1, 0, true, "EAST"); + + private static final ImmutableList ALL_FACES = ImmutableList.of(TOP, BOTTOM, NORTH, SOUTH, WEST, EAST); + + static { + link(TOP, BOTTOM); + link(NORTH, SOUTH); + link(WEST, EAST); + } + + private static final ImmutableList PRIMARY_FACES = ALL_FACES.stream().filter(BlockFace::isPrimary) + .collect(ImmutableList.toImmutableList()); + + private static final ImmutableList SECONDARY_FACES = ALL_FACES.stream().filter(BlockFace::isSecondary) + .collect(ImmutableList.toImmutableList()); + + public static final int BLOCK_FACE_COUNT = ALL_FACES.size(); + public static final int PRIMARY_BLOCK_FACE_COUNT = PRIMARY_FACES.size(); + public static final int SECONDARY_BLOCK_FACE_COUNT = SECONDARY_FACES.size(); + + public static ImmutableList getFaces() { + return ALL_FACES; + } + + public static ImmutableList getPrimaryFaces() { + return PRIMARY_FACES; + } + + public static ImmutableList getSecondaryFaces() { + return SECONDARY_FACES; + } + + private static void link(BlockFace a, BlockFace b) { + a.counterFace = b; + b.counterFace = a; + } + + public static ImmutableMap mapToFaces( + E top, + E bottom, + E north, + E south, + E east, + E west + ) { + return ImmutableMap.builderWithExpectedSize(6) + .put(TOP, top) + .put(BOTTOM, bottom) + .put(NORTH, north) + .put(SOUTH, south) + .put(EAST, east) + .put(WEST, west) + .build(); + } + + private static int nextId = 0; + + private final int id; + private final String name; + private BlockFace counterFace; + private final boolean isPrimary; + + private BlockFace(int x, int y, int z, boolean isPrimary, String name) { + super(x, y, z); + this.id = nextId++; + this.isPrimary = isPrimary; + this.name = name; + } + + public String getName() { + return name; + } + + public boolean isPrimary() { + return isPrimary; + } + + public BlockFace getPrimary() { + if (isPrimary) + return this; + else + return counterFace; + } + + public BlockFace getPrimaryAndMoveCursor(Vec3i cursor) { + if (isPrimary) + return this; + + cursor.add(getVector()); + return counterFace; + } + + public boolean isSecondary() { + return !isPrimary; + } + + public BlockFace getSecondary() { + if (isPrimary) + return counterFace; + else + return this; + } + + public BlockFace getSecondaryAndMoveCursor(Vec3i cursor) { + if (!isPrimary) + return this; + + cursor.add(getVector()); + return counterFace; + } + + public BlockFace getCounter() { + return counterFace; + } + + public BlockFace getCounterAndMoveCursor(Vec3i cursor) { + cursor.add(getVector()); + return counterFace; + } + + public int getId() { + return id; + } + + @Override + public float getEuclideanDistance() { + return 1.0f; + } + + @Override + public int getChebyshevDistance() { + return 1; + } + + @Override + public int getManhattanDistance() { + return 1; + } + + @Override + public String toString() { + return getName(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java b/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java index 06dd1c2..02e1c2e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/BlockRelation.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.block; import static java.lang.Math.abs; @@ -7,52 +25,55 @@ import glm.vec._3.Vec3; import glm.vec._3.i.Vec3i; public class BlockRelation { - + private final Vec3i vector = new Vec3i(); private final Vec3 normalized = new Vec3(); - + public BlockRelation(int x, int y, int z) { vector.set(x, y, z); normalized.set(x, y, z).normalize(); } - + public BlockRelation(Vec3i vector) { this(vector.x, vector.y, vector.z); } - + public Vec3i getVector() { return vector; } - + public Vec3 getNormalized() { return normalized; } - + /** * Returns the distance between the source and destination blocks, as * defined by the Euclidean space. Your everyday distance. + * * @return square root of the sum of the squares of the coordinates */ public float getEuclideanDistance() { return vector.length(); } - + /** * Returns the Manhattan distance, also known as the taxicab distance, * between the source and the destination blocks. Manhattan distance is * defined as the sum of the absolute values of the coordinates, * which is also the minimum amount of block faces that need to be crossed - * to move from source to destination. + * to move from source to destination. + * * @return the sum of the absolute values of the coordinates */ public int getManhattanDistance() { return abs(vector.x) + abs(vector.y) + abs(vector.z); } - + /** * Returns the Chebyshev distance between the source and the destination * blocks. Chebyshev distance is defined as the maximum of the absolute - * values of the coordinates. + * values of the coordinates. + * * @return the maximum of the absolute values of the coordinates */ public int getChebyshevDistance() { diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java b/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java index 8ade185..2c1c8a2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/PacketAffectBlock.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.block; import java.io.DataInput; @@ -10,17 +28,17 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.PacketAffectChunk; public abstract class PacketAffectBlock extends PacketAffectChunk { - + private final Vec3i blockInWorld = new Vec3i(); - + public PacketAffectBlock(String id) { super(id); } - + public Vec3i getBlockInWorld() { return blockInWorld; } - + public void set(Vec3i blockInWorld) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java index e166aad..55d0eb2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/block/PacketSetBlock.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.block; import java.io.DataInput; @@ -9,21 +27,21 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public class PacketSetBlock extends PacketAffectBlock { - + private String blockId; - + public PacketSetBlock() { this("Core:SetBlock"); } - + protected PacketSetBlock(String id) { super(id); } - + public String getBlockId() { return blockId; } - + public void set(BlockData block, Vec3i blockInWorld) { super.set(blockInWorld); this.blockId = block.getId(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java index f645bef..7b3325c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityData.java @@ -1,205 +1,224 @@ -package ru.windcorp.progressia.common.world.entity; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import glm.vec._2.Vec2; -import glm.vec._3.Vec3; -import ru.windcorp.jputil.chars.StringUtil; -import ru.windcorp.progressia.common.collision.Collideable; -import ru.windcorp.progressia.common.collision.CollisionModel; -import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.state.StatefulObject; -import ru.windcorp.progressia.common.world.generic.GenericEntity; - -public class EntityData extends StatefulObject implements Collideable, GenericEntity { - - private final Vec3 position = new Vec3(); - private final Vec3 velocity = new Vec3(); - - private final Vec2 direction = new Vec2(); - - /** - * The unique {@code long} value guaranteed to never be assigned to an entity as its entity ID. - * This can safely be used as a placeholder or a sentinel value. - */ - public static final long NULL_ENTITY_ID = 0x0000_0000_0000_0000; - - private long entityId; - - private CollisionModel collisionModel = null; - - private double age = 0; - - public EntityData(String id) { - super(EntityDataRegistry.getInstance(), id); - } - - @Override - public Vec3 getPosition() { - return position; - } - - public void setPosition(Vec3 position) { - move(position.sub_(getPosition())); - } - - public void move(Vec3 displacement) { - this.position.add(displacement); - if (getCollisionModel() != null) { - getCollisionModel().moveOrigin(displacement); - } - } - - public Vec3 getVelocity() { - return velocity; - } - - public void setVelocity(Vec3 velocity) { - this.velocity.set(velocity); - } - - public Vec2 getDirection() { - return direction; - } - - public void setDirection(Vec2 direction) { - this.direction.set(direction.x, direction.y); - } - - public float getYaw() { - return getDirection().x; - } - - public float getPitch() { - return getDirection().y; - } - - public long getEntityId() { - return entityId; - } - - public void setEntityId(long entityId) { - if (entityId == NULL_ENTITY_ID) { - throw new IllegalArgumentException("Attempted to set entity ID to NULL_ENTITY_ID (" + entityId + ")"); - } - this.entityId = entityId; - } - - public double getAge() { - return age; - } - - public void setAge(double age) { - this.age = age; - } - - public void incrementAge(double increment) { - this.age += increment; - } - - @Override - public CollisionModel getCollisionModel() { - return collisionModel; - } - - public void setCollisionModel(CollisionModel collisionModel) { - this.collisionModel = collisionModel; - } - - @Override - public boolean onCollision(Collideable other) { - return false; - } - - @Override - public float getCollisionMass() { - return 1.0f; - } - - @Override - public void moveAsCollideable(Vec3 displacement) { - move(displacement); - } - - @Override - public void getCollideableVelocity(Vec3 output) { - output.set(getVelocity()); - } - - @Override - public void changeVelocityOnCollision(Vec3 velocityChange) { - getVelocity().add(velocityChange); - } - - public Vec3 getLookingAtVector(Vec3 output) { - output.set( - Math.cos(getPitch()) * Math.cos(getYaw()), - Math.cos(getPitch()) * Math.sin(getYaw()), - -Math.sin(getPitch()) - ); - - return output; - } - - @Override - public String toString() { - return new StringBuilder(super.toString()) - .append(" (EntityID ") - .append(StringUtil.toFullHex(getEntityId())) - .append(")") - .toString(); - } - - public static String formatEntityId(long entityId) { - return new String(StringUtil.toFullHex(entityId)); - } - - /* - * tmp - */ - - @Override - public void write(DataOutput output, IOContext context) throws IOException { - output.writeFloat(getPosition().x); - output.writeFloat(getPosition().y); - output.writeFloat(getPosition().z); - - output.writeFloat(getVelocity().x); - output.writeFloat(getVelocity().y); - output.writeFloat(getVelocity().z); - - output.writeFloat(getDirection().x); - output.writeFloat(getDirection().y); - - super.write(output, context); - } - - @Override - public void read(DataInput input, IOContext context) throws IOException { - Vec3 position = new Vec3( - input.readFloat(), - input.readFloat(), - input.readFloat() - ); - - Vec3 velocity = new Vec3( - input.readFloat(), - input.readFloat(), - input.readFloat() - ); - - Vec2 direction = new Vec2( - input.readFloat(), - input.readFloat() - ); - - setPosition(position); - setVelocity(velocity); - setDirection(direction); - - super.read(input, context); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.entity; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import glm.vec._2.Vec2; +import glm.vec._3.Vec3; +import ru.windcorp.jputil.chars.StringUtil; +import ru.windcorp.progressia.common.collision.Collideable; +import ru.windcorp.progressia.common.collision.CollisionModel; +import ru.windcorp.progressia.common.state.IOContext; +import ru.windcorp.progressia.common.state.StatefulObject; +import ru.windcorp.progressia.common.world.generic.GenericEntity; + +public class EntityData extends StatefulObject implements Collideable, GenericEntity { + + private final Vec3 position = new Vec3(); + private final Vec3 velocity = new Vec3(); + + private final Vec2 direction = new Vec2(); + + /** + * The unique {@code long} value guaranteed to never be assigned to an + * entity as its entity ID. + * This can safely be used as a placeholder or a sentinel value. + */ + public static final long NULL_ENTITY_ID = 0x0000_0000_0000_0000; + + private long entityId; + + private CollisionModel collisionModel = null; + + private double age = 0; + + public EntityData(String id) { + super(EntityDataRegistry.getInstance(), id); + } + + @Override + public Vec3 getPosition() { + return position; + } + + public void setPosition(Vec3 position) { + move(position.sub_(getPosition())); + } + + public void move(Vec3 displacement) { + this.position.add(displacement); + if (getCollisionModel() != null) { + getCollisionModel().moveOrigin(displacement); + } + } + + public Vec3 getVelocity() { + return velocity; + } + + public void setVelocity(Vec3 velocity) { + this.velocity.set(velocity); + } + + public Vec2 getDirection() { + return direction; + } + + public void setDirection(Vec2 direction) { + this.direction.set(direction.x, direction.y); + } + + public float getYaw() { + return getDirection().x; + } + + public float getPitch() { + return getDirection().y; + } + + public long getEntityId() { + return entityId; + } + + public void setEntityId(long entityId) { + if (entityId == NULL_ENTITY_ID) { + throw new IllegalArgumentException("Attempted to set entity ID to NULL_ENTITY_ID (" + entityId + ")"); + } + this.entityId = entityId; + } + + public double getAge() { + return age; + } + + public void setAge(double age) { + this.age = age; + } + + public void incrementAge(double increment) { + this.age += increment; + } + + @Override + public CollisionModel getCollisionModel() { + return collisionModel; + } + + public void setCollisionModel(CollisionModel collisionModel) { + this.collisionModel = collisionModel; + } + + @Override + public boolean onCollision(Collideable other) { + return false; + } + + @Override + public float getCollisionMass() { + return 1.0f; + } + + @Override + public void moveAsCollideable(Vec3 displacement) { + move(displacement); + } + + @Override + public void getCollideableVelocity(Vec3 output) { + output.set(getVelocity()); + } + + @Override + public void changeVelocityOnCollision(Vec3 velocityChange) { + getVelocity().add(velocityChange); + } + + public Vec3 getLookingAtVector(Vec3 output) { + output.set( + Math.cos(getPitch()) * Math.cos(getYaw()), + Math.cos(getPitch()) * Math.sin(getYaw()), + -Math.sin(getPitch()) + ); + + return output; + } + + @Override + public String toString() { + return new StringBuilder(super.toString()) + .append(" (EntityID ") + .append(StringUtil.toFullHex(getEntityId())) + .append(")") + .toString(); + } + + public static String formatEntityId(long entityId) { + return new String(StringUtil.toFullHex(entityId)); + } + + /* + * tmp + */ + + @Override + public void write(DataOutput output, IOContext context) throws IOException { + output.writeFloat(getPosition().x); + output.writeFloat(getPosition().y); + output.writeFloat(getPosition().z); + + output.writeFloat(getVelocity().x); + output.writeFloat(getVelocity().y); + output.writeFloat(getVelocity().z); + + output.writeFloat(getDirection().x); + output.writeFloat(getDirection().y); + + super.write(output, context); + } + + @Override + public void read(DataInput input, IOContext context) throws IOException { + Vec3 position = new Vec3( + input.readFloat(), + input.readFloat(), + input.readFloat() + ); + + Vec3 velocity = new Vec3( + input.readFloat(), + input.readFloat(), + input.readFloat() + ); + + Vec2 direction = new Vec2( + input.readFloat(), + input.readFloat() + ); + + setPosition(position); + setVelocity(velocity); + setDirection(direction); + + super.read(input, context); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java index 9f0c8f1..26f219d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/EntityDataRegistry.java @@ -1,17 +1,35 @@ -package ru.windcorp.progressia.common.world.entity; - -import ru.windcorp.progressia.common.state.StatefulObjectRegistry; - -public class EntityDataRegistry extends StatefulObjectRegistry { - - private static final EntityDataRegistry INSTANCE = new EntityDataRegistry(); - - public static EntityDataRegistry getInstance() { - return INSTANCE; - } - - public void register(String id) { - super.register(id, () -> new EntityData(id)); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.entity; + +import ru.windcorp.progressia.common.state.StatefulObjectRegistry; + +public class EntityDataRegistry extends StatefulObjectRegistry { + + private static final EntityDataRegistry INSTANCE = new EntityDataRegistry(); + + public static EntityDataRegistry getInstance() { + return INSTANCE; + } + + public void register(String id) { + super.register(id, () -> new EntityData(id)); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java index 4d6d403..f3bf792 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketAffectEntity.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -9,26 +27,26 @@ import ru.windcorp.progressia.common.world.PacketAffectWorld; import ru.windcorp.progressia.common.world.WorldData; public class PacketAffectEntity extends PacketAffectWorld { - + private long entityId; public PacketAffectEntity(String id) { super(id); } - + public long getEntityId() { return entityId; } - + public void set(long entityId) { this.entityId = entityId; } - + @Override public void read(DataInput input) throws IOException, DecodingException { this.entityId = input.readLong(); } - + @Override public void write(DataOutput output) throws IOException { output.writeLong(this.entityId); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java index fcfadc5..d09b0f3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketChangeEntity.java @@ -1,67 +1,85 @@ -package ru.windcorp.progressia.common.world.entity; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import ru.windcorp.progressia.common.state.IOContext; -import ru.windcorp.progressia.common.util.DataBuffer; -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.common.world.DecodingException; -import ru.windcorp.progressia.common.world.WorldData; - -public class PacketChangeEntity extends PacketAffectEntity { - - private final DataBuffer buffer = new DataBuffer(); - - public PacketChangeEntity() { - super("Core:EntityChange"); - } - - protected PacketChangeEntity(String id) { - super(id); - } - - public DataBuffer getBuffer() { - return buffer; - } - - public void set(EntityData entity) { - super.set(entity.getEntityId()); - - try { - entity.write(this.buffer.getWriter(), IOContext.COMMS); - } catch (IOException e) { - throw CrashReports.report(e, "Entity could not be written"); - } - } - - @Override - public void read(DataInput input) throws IOException, DecodingException { - super.read(input); - this.buffer.fill(input, input.readInt()); - } - - @Override - public void write(DataOutput output) throws IOException { - super.write(output); - output.writeInt(this.buffer.getSize()); - this.buffer.flush(output); - } - - @Override - public void apply(WorldData world) { - EntityData entity = world.getEntity(getEntityId()); - - if (entity == null) { - throw CrashReports.report(null, "Entity with ID %d not found", getEntityId()); - } - - try { - entity.read(getBuffer().getReader(), IOContext.COMMS); - } catch (IOException e) { - throw CrashReports.report(e, "Entity could not be read"); - } - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.entity; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import ru.windcorp.progressia.common.state.IOContext; +import ru.windcorp.progressia.common.util.DataBuffer; +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.common.world.DecodingException; +import ru.windcorp.progressia.common.world.WorldData; + +public class PacketChangeEntity extends PacketAffectEntity { + + private final DataBuffer buffer = new DataBuffer(); + + public PacketChangeEntity() { + super("Core:EntityChange"); + } + + protected PacketChangeEntity(String id) { + super(id); + } + + public DataBuffer getBuffer() { + return buffer; + } + + public void set(EntityData entity) { + super.set(entity.getEntityId()); + + try { + entity.write(this.buffer.getWriter(), IOContext.COMMS); + } catch (IOException e) { + throw CrashReports.report(e, "Entity could not be written"); + } + } + + @Override + public void read(DataInput input) throws IOException, DecodingException { + super.read(input); + this.buffer.fill(input, input.readInt()); + } + + @Override + public void write(DataOutput output) throws IOException { + super.write(output); + output.writeInt(this.buffer.getSize()); + this.buffer.flush(output); + } + + @Override + public void apply(WorldData world) { + EntityData entity = world.getEntity(getEntityId()); + + if (entity == null) { + throw CrashReports.report(null, "Entity with ID %d not found", getEntityId()); + } + + try { + entity.read(getBuffer().getReader(), IOContext.COMMS); + } catch (IOException e) { + throw CrashReports.report(e, "Entity could not be read"); + } + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java index b7bf77e..06dfc12 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketRevokeEntity.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -8,7 +26,7 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public class PacketRevokeEntity extends PacketAffectEntity { - + public PacketRevokeEntity() { this("Core:RevokeEntity"); } @@ -16,17 +34,17 @@ public class PacketRevokeEntity extends PacketAffectEntity { protected PacketRevokeEntity(String id) { super(id); } - + @Override public void set(long entityId) { super.set(entityId); } - + @Override public void read(DataInput input) throws IOException, DecodingException { super.read(input); } - + @Override public void write(DataOutput output) throws IOException { super.write(output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java index 569be14..6604d4a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/entity/PacketSendEntity.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.entity; import java.io.DataInput; @@ -11,36 +29,37 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public class PacketSendEntity extends PacketAffectEntity { - + private String entityTypeId; private final DataBuffer buffer = new DataBuffer(); - + public PacketSendEntity() { this("Core:SendEntity"); } - + protected PacketSendEntity(String id) { super(id); } - + /** * Returns the text ID of the entity added by this packet. + * * @return text ID * @see #getEntityId() */ public String getEntityTypeId() { return entityTypeId; } - + public DataBuffer getBuffer() { return buffer; } - + public void set(EntityData entity) { super.set(entity.getEntityId()); - + this.entityTypeId = entity.getId(); - + try { entity.write(this.buffer.getWriter(), IOContext.COMMS); } catch (IOException e) { @@ -51,7 +70,7 @@ public class PacketSendEntity extends PacketAffectEntity { @Override public void read(DataInput input) throws IOException, DecodingException { super.read(input); - + this.entityTypeId = input.readUTF(); this.buffer.fill(input, input.readInt()); } @@ -59,23 +78,23 @@ public class PacketSendEntity extends PacketAffectEntity { @Override public void write(DataOutput output) throws IOException { super.write(output); - + output.writeUTF(this.entityTypeId); output.writeInt(this.buffer.getSize()); this.buffer.flush(output); } - + @Override public void apply(WorldData world) { EntityData entity = EntityDataRegistry.getInstance().create(getEntityTypeId()); - + entity.setEntityId(getEntityId()); try { entity.read(getBuffer().getReader(), IOContext.COMMS); } catch (IOException e) { throw CrashReports.report(e, "Could not read an entity from an internal buffer"); } - + world.addEntity(entity); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java index ab83f9a..6c35781 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkMap.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; @@ -7,105 +25,117 @@ import java.util.function.BiPredicate; import glm.vec._3.i.Vec3i; public interface ChunkMap { - + /* * Size */ - + int size(); - + default boolean isEmpty() { return size() == 0; } - + /* * Basic operations */ - + boolean containsKey(Vec3i pos); - + V get(Vec3i pos); + V put(Vec3i pos, V obj); + V remove(Vec3i pos); - + default boolean containsValue(V value) { return values().contains(value); } - + default V getOrDefault(Vec3i pos, V def) { return containsKey(pos) ? def : get(pos); } - + default V compute(Vec3i pos, BiFunction remappingFunction) { V newValue = remappingFunction.apply(pos, get(pos)); - + if (newValue == null) { remove(pos); } else { put(pos, newValue); } - + return newValue; } - + // TODO implement ALL default methods from Map - + /* * Basic operation wrappers */ - - // TODO implement (int, int, int) and GenericChunk versions of all of the above - + + // TODO implement (int, int, int) and GenericChunk versions of all of the + // above + default boolean containsChunk(GenericChunk chunk) { return containsKey(chunk.getPosition()); } - + default V get(GenericChunk chunk) { return get(chunk.getPosition()); } - + default V put(GenericChunk chunk, V obj) { return put(chunk.getPosition(), obj); } - + default V remove(GenericChunk chunk) { return remove(chunk.getPosition()); } - + default V getOrDefault(GenericChunk chunk, V def) { return containsChunk(chunk) ? def : get(chunk); } - - default > V compute(C chunk, BiFunction remappingFunction) { + + default > V compute( + C chunk, + BiFunction remappingFunction + ) { V newValue = remappingFunction.apply(chunk, get(chunk)); - + if (newValue == null) { remove(chunk); } else { put(chunk, newValue); } - + return newValue; } - + /* * Views */ - + Collection values(); + ChunkSet keys(); - + /* * Bulk operations */ - + boolean removeIf(BiPredicate condition); + void forEach(BiConsumer action); - - default > void forEachIn(GenericWorld world, BiConsumer action) { + + default > void forEachIn( + GenericWorld world, + BiConsumer action + ) { forEach((pos, value) -> { C chunk = world.getChunk(pos); - if (chunk == null) return; + if (chunk == null) + return; action.accept(chunk, value); }); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java index 84013ec..73c2267 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSet.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; @@ -11,156 +29,168 @@ import gnu.trove.set.hash.TLongHashSet; import ru.windcorp.progressia.common.util.Vectors; public interface ChunkSet extends Iterable { - + /* * Size */ - + int size(); - + default boolean isEmpty() { return size() == 0; } - + /* * Basic operations */ - + boolean contains(Vec3i pos); + boolean add(Vec3i pos); + boolean remove(Vec3i pos); - + /* * Basic operation wrappers */ - + default boolean contains(int x, int y, int z) { Vec3i v = Vectors.grab3i(); boolean result = contains(v); Vectors.release(v); return result; } - + default boolean add(int x, int y, int z) { Vec3i v = Vectors.grab3i(); boolean result = add(v); Vectors.release(v); return result; } - + default boolean remove(int x, int y, int z) { Vec3i v = Vectors.grab3i(); boolean result = remove(v); Vectors.release(v); return result; } - + default boolean contains(GenericChunk chunk) { return contains(chunk.getPosition()); } - + default boolean add(GenericChunk chunk) { return add(chunk.getPosition()); } - + default boolean remove(GenericChunk chunk) { return remove(chunk.getPosition()); } - - default > void forEachIn(GenericWorld world, Consumer action) { + + default > void forEachIn( + GenericWorld world, + Consumer action + ) { forEach(position -> { C chunk = world.getChunk(position); - if (chunk == null) return; + if (chunk == null) + return; action.accept(chunk); }); } - + /* * Bulk operations on ChunkSets */ - + boolean containsAll(ChunkSet other); + boolean containsAny(ChunkSet other); - + void addAll(ChunkSet other); + void removeAll(ChunkSet other); + void retainAll(ChunkSet other); - + /* * Other bulk operations */ - + void clear(); - + default boolean containsAll(Iterable other) { boolean[] hasMissing = new boolean[] { false }; - + other.forEach(v -> { if (!contains(v)) { hasMissing[0] = true; } }); - + return hasMissing[0]; } - + default boolean containsAny(Iterable other) { boolean[] hasPresent = new boolean[] { false }; - + other.forEach(v -> { if (contains(v)) { hasPresent[0] = true; } }); - + return hasPresent[0]; } - + default void addAll(Iterable other) { other.forEach(this::add); } - + default void removeAll(Iterable other) { other.forEach(this::remove); } - + default void retainAll(Iterable other) { if (other instanceof ChunkSet) { - // We shouldn't invoke retainAll(ChunkSet) because we could be the fallback for it + // We shouldn't invoke retainAll(ChunkSet) because we could be the + // fallback for it removeIf(v -> !((ChunkSet) other).contains(v)); return; } - - final int threshold = 16; // Maximum size of other at which point creating a Set becomes faster than iterating - + + final int threshold = 16; // Maximum size of other at which point + // creating a Set becomes faster than + // iterating + Collection collection = null; int otherSize = -1; - + if (other instanceof Set) { collection = (Set) other; } else if (other instanceof Collection) { Collection otherAsCollection = ((Collection) other); otherSize = otherAsCollection.size(); - + if (otherSize < threshold) { collection = otherAsCollection; } } - + if (collection != null) { final Collection c = collection; removeIf(v -> !c.contains(v)); return; } - + if (otherSize < 0) { otherSize = gnu.trove.impl.Constants.DEFAULT_CAPACITY; } - + retainAll(new LongBasedChunkSet(new TLongHashSet(otherSize), other)); return; } - + default void removeIf(Predicate condition) { for (Iterator it = iterator(); it.hasNext();) { if (condition.test(it.next())) { @@ -168,7 +198,7 @@ public interface ChunkSet extends Iterable { } } } - + default void retainIf(Predicate condition) { for (Iterator it = iterator(); it.hasNext();) { if (!condition.test(it.next())) { @@ -176,35 +206,35 @@ public interface ChunkSet extends Iterable { } } } - + default boolean containsAllChunks(Iterable> chunks) { boolean[] hasMissing = new boolean[] { false }; - + chunks.forEach(c -> { if (!contains(c.getPosition())) { hasMissing[0] = true; } }); - + return hasMissing[0]; } - + default boolean containsAnyChunks(Iterable> chunks) { boolean[] hasPresent = new boolean[] { false }; - + chunks.forEach(c -> { if (contains(c.getPosition())) { hasPresent[0] = true; } }); - + return hasPresent[0]; } - + default void addAllChunks(Iterable> chunks) { chunks.forEach(this::add); } - + default void removeAllChunks(Iterable> chunks) { chunks.forEach(this::remove); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java index 3e50dd3..93413e4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/ChunkSets.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Iterator; @@ -10,25 +28,26 @@ import glm.vec._3.i.Vec3i; import gnu.trove.set.hash.TLongHashSet; public class ChunkSets { - + public static ChunkSet newHashSet() { return new LongBasedChunkSet(new TLongHashSet()); } - + public static ChunkSet newSyncHashSet(Object mutex) { return new SynchronizedChunkSet(new LongBasedChunkSet(new TLongHashSet()), mutex); } - + public static ChunkSet newSyncHashSet() { return newSyncHashSet(null); } - + public static ChunkSet empty() { return EMPTY_SET; } - - private ChunkSets() {} - + + private ChunkSets() { + } + private final static ChunkSet EMPTY_SET = new ChunkSet() { @Override @@ -38,6 +57,7 @@ public class ChunkSets { public boolean hasNext() { return false; } + @Override public Vec3i next() { throw new NoSuchElementException(); @@ -94,18 +114,18 @@ public class ChunkSets { public void clear() { throw new UnsupportedOperationException(); } - + }; - + private static class SynchronizedChunkSet implements ChunkSet { - + private final ChunkSet parent; private final Object mutex; public SynchronizedChunkSet(ChunkSet parent, Object mutex) { Objects.requireNonNull(parent, "parent"); this.parent = parent; - + this.mutex = mutex == null ? this : mutex; } @@ -116,155 +136,217 @@ public class ChunkSets { @Override public void forEach(Consumer action) { - synchronized (mutex) { parent.forEach(action); } + synchronized (mutex) { + parent.forEach(action); + } } @Override public int size() { - synchronized (mutex) { return parent.size(); } + synchronized (mutex) { + return parent.size(); + } } @Override public boolean isEmpty() { - synchronized (mutex) { return parent.isEmpty(); } + synchronized (mutex) { + return parent.isEmpty(); + } } @Override public boolean contains(Vec3i pos) { - synchronized (mutex) { return parent.contains(pos); } + synchronized (mutex) { + return parent.contains(pos); + } } @Override public boolean add(Vec3i pos) { - synchronized (mutex) { return parent.add(pos); } + synchronized (mutex) { + return parent.add(pos); + } } @Override public boolean remove(Vec3i pos) { - synchronized (mutex) { return parent.remove(pos); } + synchronized (mutex) { + return parent.remove(pos); + } } @Override public boolean contains(int x, int y, int z) { - synchronized (mutex) { return parent.contains(x, y, z); } + synchronized (mutex) { + return parent.contains(x, y, z); + } } @Override public boolean add(int x, int y, int z) { - synchronized (mutex) { return parent.add(x, y, z); } + synchronized (mutex) { + return parent.add(x, y, z); + } } @Override public boolean remove(int x, int y, int z) { - synchronized (mutex) { return parent.remove(x, y, z); } + synchronized (mutex) { + return parent.remove(x, y, z); + } } @Override public boolean contains(GenericChunk chunk) { - synchronized (mutex) { return parent.contains(chunk); } + synchronized (mutex) { + return parent.contains(chunk); + } } @Override public boolean add(GenericChunk chunk) { - synchronized (mutex) { return parent.add(chunk); } + synchronized (mutex) { + return parent.add(chunk); + } } @Override public boolean remove(GenericChunk chunk) { - synchronized (mutex) { return parent.remove(chunk); } + synchronized (mutex) { + return parent.remove(chunk); + } } @Override - public > void forEachIn(GenericWorld world, - Consumer action) { - synchronized (mutex) { parent.forEachIn(world, action); } + public > void forEachIn( + GenericWorld world, + Consumer action + ) { + synchronized (mutex) { + parent.forEachIn(world, action); + } } @Override public boolean containsAll(ChunkSet other) { - synchronized (mutex) { return parent.containsAll(other); } + synchronized (mutex) { + return parent.containsAll(other); + } } @Override public boolean containsAny(ChunkSet other) { - synchronized (mutex) { return parent.containsAny(other); } + synchronized (mutex) { + return parent.containsAny(other); + } } @Override public void addAll(ChunkSet other) { - synchronized (mutex) { parent.addAll(other); } + synchronized (mutex) { + parent.addAll(other); + } } @Override public void removeAll(ChunkSet other) { - synchronized (mutex) { parent.removeAll(other); } + synchronized (mutex) { + parent.removeAll(other); + } } @Override public void retainAll(ChunkSet other) { - synchronized (mutex) { parent.retainAll(other); } + synchronized (mutex) { + parent.retainAll(other); + } } @Override public void clear() { - synchronized (mutex) { parent.clear(); } + synchronized (mutex) { + parent.clear(); + } } @Override public boolean containsAll(Iterable other) { - synchronized (mutex) { return parent.containsAll(other); } + synchronized (mutex) { + return parent.containsAll(other); + } } @Override public boolean containsAny(Iterable other) { - synchronized (mutex) { return parent.containsAny(other); } + synchronized (mutex) { + return parent.containsAny(other); + } } @Override public void addAll(Iterable other) { - synchronized (mutex) { parent.addAll(other); } + synchronized (mutex) { + parent.addAll(other); + } } @Override public void removeAll(Iterable other) { - synchronized (mutex) { parent.removeAll(other); } + synchronized (mutex) { + parent.removeAll(other); + } } @Override public void retainAll(Iterable other) { - synchronized (mutex) { parent.retainAll(other); } + synchronized (mutex) { + parent.retainAll(other); + } } @Override public void removeIf(Predicate condition) { - synchronized (mutex) { parent.removeIf(condition); } + synchronized (mutex) { + parent.removeIf(condition); + } } @Override public void retainIf(Predicate condition) { - synchronized (mutex) { parent.retainIf(condition); } + synchronized (mutex) { + parent.retainIf(condition); + } } @Override public boolean containsAllChunks(Iterable> chunks) { - synchronized (mutex) { return parent.containsAllChunks(chunks); } + synchronized (mutex) { + return parent.containsAllChunks(chunks); + } } @Override public boolean containsAnyChunks(Iterable> chunks) { - synchronized (mutex) { return parent.containsAnyChunks(chunks); } + synchronized (mutex) { + return parent.containsAnyChunks(chunks); + } } @Override public void addAllChunks(Iterable> chunks) { - synchronized (mutex) { parent.addAllChunks(chunks); } + synchronized (mutex) { + parent.addAllChunks(chunks); + } } @Override public void removeAllChunks(Iterable> chunks) { - synchronized (mutex) { parent.removeAllChunks(chunks); } + synchronized (mutex) { + parent.removeAllChunks(chunks); + } } - + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java index b0a6e2d..d669b07 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericBlock.java @@ -1,7 +1,25 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; public interface GenericBlock { - + String getId(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java index 0bbff1a..c6a1b32 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericChunk.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.function.Consumer; @@ -8,102 +26,102 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockFace; -public interface GenericChunk< - Self extends GenericChunk, - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack -> { - +public interface GenericChunk, B extends GenericBlock, T extends GenericTile, TS extends GenericTileStack> { + public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; Vec3i getPosition(); - + B getBlock(Vec3i blockInChunk); + TS getTiles(Vec3i blockInChunk, BlockFace face); + boolean hasTiles(Vec3i blockInChunk, BlockFace face); - + default int getX() { return getPosition().x; } - + default int getMinX() { return Coordinates.getInWorld(getX(), 0); } - + default int getMaxX() { return Coordinates.getInWorld(getX(), BLOCKS_PER_CHUNK - 1); } - + default int getY() { return getPosition().y; } - + default int getMinY() { return Coordinates.getInWorld(getY(), 0); } - + default int getMaxY() { return Coordinates.getInWorld(getY(), BLOCKS_PER_CHUNK - 1); } - + default int getZ() { return getPosition().z; } - + default int getMinZ() { return Coordinates.getInWorld(getZ(), 0); } - + default int getMaxZ() { return Coordinates.getInWorld(getZ(), BLOCKS_PER_CHUNK - 1); } - + default boolean containsBiC(Vec3i blockInChunk) { - return - blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && - blockInChunk.y >= 0 && blockInChunk.y < BLOCKS_PER_CHUNK && - blockInChunk.z >= 0 && blockInChunk.z < BLOCKS_PER_CHUNK; + return blockInChunk.x >= 0 && blockInChunk.x < BLOCKS_PER_CHUNK && + blockInChunk.y >= 0 && blockInChunk.y < BLOCKS_PER_CHUNK && + blockInChunk.z >= 0 && blockInChunk.z < BLOCKS_PER_CHUNK; } - + default boolean containsBiW(Vec3i blockInWorld) { Vec3i v = Vectors.grab3i(); - + v = Coordinates.getInWorld(getPosition(), Vectors.ZERO_3i, v); v = blockInWorld.sub(v, v); - + boolean result = containsBiC(v); - + Vectors.release(v); return result; } - + default void forEachBiC(Consumer action) { VectorUtil.iterateCuboid( - 0, 0, 0, - BLOCKS_PER_CHUNK, BLOCKS_PER_CHUNK, BLOCKS_PER_CHUNK, - action + 0, + 0, + 0, + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + action ); } - + default void forEachBiW(Consumer action) { VectorUtil.iterateCuboid( - Coordinates.getInWorld(getX(), 0), - Coordinates.getInWorld(getY(), 0), - Coordinates.getInWorld(getZ(), 0), - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - BLOCKS_PER_CHUNK, - action + Coordinates.getInWorld(getX(), 0), + Coordinates.getInWorld(getY(), 0), + Coordinates.getInWorld(getZ(), 0), + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + BLOCKS_PER_CHUNK, + action ); } - + default TS getTilesOrNull(Vec3i blockInChunk, BlockFace face) { if (hasTiles(blockInChunk, face)) { return getTiles(blockInChunk, face); } - + return null; } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java index ac8ca36..c15bd39 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericEntity.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import glm.vec._3.Vec3; @@ -5,15 +23,17 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; public interface GenericEntity { - + String getId(); + Vec3 getPosition(); - + default Vec3i getBlockInWorld(Vec3i output) { - if (output == null) output = new Vec3i(); + if (output == null) + output = new Vec3i(); return getPosition().round(output); } - + default Vec3i getChunkCoords(Vec3i output) { output = getBlockInWorld(output); return Coordinates.convertInWorldToChunk(output, output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java index f674391..e35aec2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTile.java @@ -1,7 +1,25 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; public interface GenericTile { - + String getId(); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java index 476ba31..31a5158 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericTileStack.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.AbstractList; @@ -9,37 +27,35 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockFace; -public abstract class GenericTileStack< - Self extends GenericTileStack, - T extends GenericTile, - C extends GenericChunk -> -extends AbstractList -implements RandomAccess { - +public abstract class GenericTileStack, T extends GenericTile, C extends GenericChunk> + extends AbstractList + implements RandomAccess { + public static interface TSConsumer { void accept(int layer, T tile); } public static final int TILES_PER_FACE = 8; - + public abstract Vec3i getBlockInChunk(Vec3i output); + public abstract C getChunk(); + public abstract BlockFace getFace(); - + public Vec3i getBlockInWorld(Vec3i output) { // This is safe return Coordinates.getInWorld(getChunk().getPosition(), getBlockInChunk(output), output); } - + public boolean isFull() { return size() >= TILES_PER_FACE; } - + public T getClosest() { return get(0); } - + public T getFarthest() { return get(size() - 1); } @@ -50,7 +66,7 @@ implements RandomAccess { action.accept(i, get(i)); } } - + @Override public void forEach(Consumer action) { Objects.requireNonNull(action, "action"); @@ -58,33 +74,33 @@ implements RandomAccess { action.accept(get(i)); } } - + public T findClosest(String id) { Objects.requireNonNull(id, "id"); - + for (int i = 0; i < size(); ++i) { T tile = get(i); if (tile.getId().equals(id)) { return tile; } } - + return null; } - + public T findFarthest(String id) { Objects.requireNonNull(id, "id"); - + for (int i = 0; i < size(); ++i) { T tile = get(i); if (tile.getId().equals(id)) { return tile; } } - + return null; } - + public boolean contains(String id) { return findClosest(id) != null; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java index bdfdfaa..943067e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/GenericWorld.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; @@ -10,23 +28,18 @@ import ru.windcorp.progressia.common.util.Vectors; import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.block.BlockFace; -public interface GenericWorld< - B extends GenericBlock, - T extends GenericTile, - TS extends GenericTileStack, - C extends GenericChunk, - E extends GenericEntity -> { +public interface GenericWorld, C extends GenericChunk, E extends GenericEntity> { Collection getChunks(); + C getChunk(Vec3i pos); - + Collection getEntities(); - + /* * Chunks */ - + default C getChunkByBlock(Vec3i blockInWorld) { Vec3i chunkCoords = Vectors.grab3i(); chunkCoords = Coordinates.convertInWorldToChunk(blockInWorld, chunkCoords); @@ -34,93 +47,94 @@ public interface GenericWorld< Vectors.release(chunkCoords); return result; } - + default B getBlock(Vec3i blockInWorld) { Vec3i v = Vectors.grab3i(); B result; - + C chunk = getChunk(Coordinates.convertInWorldToChunk(blockInWorld, v)); if (chunk == null) { result = null; } else { result = chunk.getBlock(Coordinates.convertInWorldToInChunk(blockInWorld, v)); } - + Vectors.release(v); return result; } - + default TS getTiles(Vec3i blockInWorld, BlockFace face) { Vec3i v = Vectors.grab3i(); TS result; - + C chunk = getChunk(Coordinates.convertInWorldToChunk(blockInWorld, v)); if (chunk == null) { result = null; } else { result = chunk.getTiles(Coordinates.convertInWorldToInChunk(blockInWorld, v), face); } - + Vectors.release(v); return result; } - + default TS getTilesOrNull(Vec3i blockInWorld, BlockFace face) { Vec3i v = Vectors.grab3i(); TS result; - + C chunk = getChunk(Coordinates.convertInWorldToChunk(blockInWorld, v)); if (chunk == null) { result = null; } else { result = chunk.getTilesOrNull(Coordinates.convertInWorldToInChunk(blockInWorld, v), face); } - + Vectors.release(v); return result; } - + default boolean hasTiles(Vec3i blockInWorld, BlockFace face) { Vec3i v = Vectors.grab3i(); boolean result; - + C chunk = getChunk(Coordinates.convertInWorldToChunk(blockInWorld, v)); if (chunk == null) { result = false; } else { result = chunk.hasTiles(Coordinates.convertInWorldToInChunk(blockInWorld, v), face); } - + Vectors.release(v); return result; } - + default T getTile(Vec3i blockInWorld, BlockFace face, int layer) { TS stack = getTilesOrNull(blockInWorld, face); - if (stack == null || stack.size() <= layer) return null; + if (stack == null || stack.size() <= layer) + return null; return stack.get(layer); } - + default boolean isChunkLoaded(Vec3i chunkPos) { return getChunk(chunkPos) != null; } - + default boolean isBlockLoaded(Vec3i blockInWorld) { return getChunkByBlock(blockInWorld) != null; } - + default void forEachChunk(Consumer action) { getChunks().forEach(action); } - + /* * Entities */ - + default void forEachEntity(Consumer action) { getEntities().forEach(action); } - + default void forEachEntityIn(Vec3i min, Vec3i max, Consumer action) { forEachEntity(e -> { Vec3 pos = e.getPosition(); @@ -129,7 +143,7 @@ public interface GenericWorld< } }); } - + default void forEachEntityIn(Vec3 min, Vec3 max, Consumer action) { forEachEntity(e -> { Vec3 pos = e.getPosition(); @@ -138,33 +152,33 @@ public interface GenericWorld< } }); } - + default void forEachEntityInChunk(Vec3i pos, Consumer action) { Vec3i v = Vectors.grab3i(); - + forEachEntity(e -> { e.getChunkCoords(v); if (Glm.equals(v, pos)) { action.accept(e); } }); - + Vectors.release(v); } - + default void forEachEntityInChunk(C chunk, Consumer action) { Vec3i v = Vectors.grab3i(); - + forEachEntity(e -> { e.getChunkCoords(v); if (Glm.equals(v, chunk.getPosition())) { action.accept(e); } }); - + Vectors.release(v); } - + default void forEachEntityWithId(String id, Consumer action) { forEachEntity(e -> { if (id.equals(e.getId())) { @@ -172,5 +186,5 @@ public interface GenericWorld< } }); } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java index 80c7e17..2fbc912 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkMap.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Collection; @@ -10,7 +28,7 @@ import ru.windcorp.progressia.common.util.CoordinatePacker; import ru.windcorp.progressia.common.util.Vectors; public class LongBasedChunkMap implements ChunkMap { - + protected final TLongObjectMap impl; private final ChunkSet keys; @@ -22,7 +40,7 @@ public class LongBasedChunkMap implements ChunkMap { private static long getKey(Vec3i v) { return CoordinatePacker.pack3IntsIntoLong(v); } - + private static Vec3i getVector(long key, Vec3i output) { return CoordinatePacker.unpack3IntsFromLong(key, output); } @@ -65,11 +83,11 @@ public class LongBasedChunkMap implements ChunkMap { @Override public boolean removeIf(BiPredicate condition) { Vec3i v = Vectors.grab3i(); - + boolean result = impl.retainEntries((key, value) -> { return !condition.test(getVector(key, v), value); }); - + Vectors.release(v); return result; } @@ -77,12 +95,12 @@ public class LongBasedChunkMap implements ChunkMap { @Override public void forEach(BiConsumer action) { Vec3i v = Vectors.grab3i(); - + impl.forEachEntry((key, value) -> { action.accept(getVector(key, v), value); return true; }); - + Vectors.release(v); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java index ad4c0cb..cd5a755 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/LongBasedChunkSet.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.generic; import java.util.Iterator; @@ -12,21 +30,21 @@ import ru.windcorp.progressia.common.util.Vectors; public class LongBasedChunkSet implements ChunkSet { protected final TLongSet impl; - + public LongBasedChunkSet(TLongSet impl) { this.impl = impl; } - + public LongBasedChunkSet(TLongSet impl, ChunkSet copyFrom) { this(impl); addAll(copyFrom); } - + public LongBasedChunkSet(TLongSet impl, Iterable copyFrom) { this(impl); addAll(copyFrom); } - + public LongBasedChunkSet(TLongSet impl, GenericWorld copyFrom) { this(impl); addAllChunks(copyFrom.getChunks()); @@ -35,7 +53,7 @@ public class LongBasedChunkSet implements ChunkSet { private static long getKey(Vec3i v) { return CoordinatePacker.pack3IntsIntoLong(v); } - + private static Vec3i getVector(long key, Vec3i output) { return CoordinatePacker.unpack3IntsFromLong(key, output); } @@ -70,7 +88,7 @@ public class LongBasedChunkSet implements ChunkSet { if (other instanceof LongBasedChunkSet) { return impl.containsAll(((LongBasedChunkSet) other).impl); } - + return ChunkSet.super.containsAll((Iterable) other); } @@ -85,7 +103,7 @@ public class LongBasedChunkSet implements ChunkSet { impl.addAll(((LongBasedChunkSet) other).impl); return; } - + ChunkSet.super.addAll((Iterable) other); } @@ -95,7 +113,7 @@ public class LongBasedChunkSet implements ChunkSet { impl.removeAll(((LongBasedChunkSet) other).impl); return; } - + ChunkSet.super.removeAll((Iterable) other); } @@ -105,7 +123,7 @@ public class LongBasedChunkSet implements ChunkSet { impl.retainAll(((LongBasedChunkSet) other).impl); return; } - + ChunkSet.super.retainAll((Iterable) other); } @@ -113,22 +131,22 @@ public class LongBasedChunkSet implements ChunkSet { public void clear() { impl.clear(); } - + @Override public void forEach(Consumer action) { Vec3i v = Vectors.grab3i(); - + impl.forEach(key -> { getVector(key, v); action.accept(v); return true; }); - + Vectors.release(v); } - + private class IteratorImpl implements Iterator { - + private final Vec3i vector = new Vec3i(); private final TLongIterator parent = LongBasedChunkSet.this.impl.iterator(); @@ -141,7 +159,7 @@ public class LongBasedChunkSet implements ChunkSet { public Vec3i next() { return getVector(parent.next(), vector); } - + @Override public void remove() { parent.remove(); diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java index b3f13db..7c2a35c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkCodec.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.io; import java.io.DataInputStream; @@ -12,26 +30,28 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public abstract class ChunkCodec extends Namespaced { - + private final byte signature; - + public ChunkCodec(String id, byte signature) { super(id); this.signature = signature; } - + public ChunkCodec(String id, int signature) { this(id, (byte) signature); } - + public byte getSignature() { return signature; } - public abstract ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) throws DecodingException, IOException; - + public abstract ChunkData decode(WorldData world, Vec3i position, DataInputStream input, IOContext context) + throws DecodingException, + IOException; + public abstract boolean shouldEncode(ChunkData chunk, IOContext context); - + public abstract void encode(ChunkData chunk, DataOutputStream output, IOContext context) throws IOException; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java index 6ea35dd..025738f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/io/ChunkIO.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.io; import java.io.DataInputStream; @@ -18,40 +36,47 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public class ChunkIO { - + private static final TByteObjectMap CODECS_BY_ID = new TByteObjectHashMap<>(); private static final List CODECS_BY_PRIORITY = new ArrayList<>(); - + public static ChunkData load(WorldData world, Vec3i position, DataInputStream data, IOContext context) - throws DecodingException, IOException - { - if (CODECS_BY_ID.isEmpty()) throw new IllegalStateException("No codecs registered"); - + throws DecodingException, + IOException { + if (CODECS_BY_ID.isEmpty()) + throw new IllegalStateException("No codecs registered"); + int signature = data.read(); - if (signature < 0) throw new EOFException("Expected codec signature, got EOF"); - + if (signature < 0) + throw new EOFException("Expected codec signature, got EOF"); + ChunkCodec codec = getCodec((byte) signature); if (codec == null) { - throw new DecodingException("Unknown codec signature " + Integer.toHexString(signature) + "; is it from the future?"); + throw new DecodingException( + "Unknown codec signature " + Integer.toHexString(signature) + "; is it from the future?" + ); } - + try { return codec.decode(world, position, data, context); } catch (IOException | DecodingException e) { throw e; } catch (Throwable t) { throw CrashReports.report( - t, "Codec %s has failed to decode chunk (%d; %d; %d)", - codec.getId(), position.x, position.y, position.z + t, + "Codec %s has failed to decode chunk (%d; %d; %d)", + codec.getId(), + position.x, + position.y, + position.z ); } } - + public static void save(ChunkData chunk, DataOutputStream output, IOContext context) - throws IOException - { + throws IOException { ChunkCodec codec = getCodec(chunk, context); - + try { output.write(codec.getSignature()); codec.encode(chunk, output, context); @@ -59,17 +84,22 @@ public class ChunkIO { throw e; } catch (Throwable t) { throw CrashReports.report( - t, "Codec %s has failed to encode chunk (%d; %d; %d)", - codec.getId(), chunk.getPosition().x, chunk.getPosition().y, chunk.getPosition().z + t, + "Codec %s has failed to encode chunk (%d; %d; %d)", + codec.getId(), + chunk.getPosition().x, + chunk.getPosition().y, + chunk.getPosition().z ); } } - + public static ChunkCodec getCodec(byte signature) { - if (CODECS_BY_ID.isEmpty()) throw new IllegalStateException("No codecs registered"); + if (CODECS_BY_ID.isEmpty()) + throw new IllegalStateException("No codecs registered"); return CODECS_BY_ID.get(signature); } - + public static ChunkCodec getCodec(ChunkData chunk, IOContext context) { for (ChunkCodec codec : CODECS_BY_PRIORITY) { if (codec.shouldEncode(chunk, context)) { @@ -77,23 +107,26 @@ public class ChunkIO { } } - if (CODECS_BY_ID.isEmpty()) throw new IllegalStateException("No codecs registered"); + if (CODECS_BY_ID.isEmpty()) + throw new IllegalStateException("No codecs registered"); return CODECS_BY_PRIORITY.get(0); } /** - * Sorted in order of decreasing priority + * Sorted in order of decreasing priority + * * @return */ public static List getCodecs() { return Collections.unmodifiableList(CODECS_BY_PRIORITY); } - + public static void registerCodec(ChunkCodec codec) { CODECS_BY_PRIORITY.add(0, codec); // Add to the front CODECS_BY_ID.put(codec.getSignature(), codec); } - - private ChunkIO() {} + + private ChunkIO() { + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java index e9555ae..650b4a7 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAddTile.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -10,32 +28,32 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockFace; public class PacketAddTile extends PacketAffectTile { - + private String tileId; - + public PacketAddTile() { this("Core:AddTile"); } - + protected PacketAddTile(String id) { super(id); } - + public String getTileId() { return tileId; } - + public void set(TileData tile, Vec3i blockInWorld, BlockFace face) { super.set(blockInWorld, face, -1); this.tileId = tile.getId(); } - + @Override public void read(DataInput input) throws IOException, DecodingException { super.read(input); this.tileId = input.readUTF(); } - + @Override public void write(DataOutput output) throws IOException { super.write(output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java index 6d9fcf5..b12012c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketAffectTile.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -11,40 +29,40 @@ import ru.windcorp.progressia.common.world.PacketAffectChunk; import ru.windcorp.progressia.common.world.block.BlockFace; public abstract class PacketAffectTile extends PacketAffectChunk { - + private final Vec3i blockInWorld = new Vec3i(); private BlockFace face; private int tag; - + public PacketAffectTile(String id) { super(id); } - + public Vec3i getBlockInWorld() { return blockInWorld; } - + public BlockFace getFace() { return face; } - + public int getTag() { return tag; } - + public void set(Vec3i blockInWorld, BlockFace face, int tag) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; this.tag = tag; } - + @Override public void read(DataInput input) throws IOException, DecodingException { this.blockInWorld.set(input.readInt(), input.readInt(), input.readInt()); this.face = BlockFace.getFaces().get(input.readByte()); this.tag = input.readInt(); } - + @Override public void write(DataOutput output) throws IOException { output.writeInt(this.blockInWorld.x); @@ -53,7 +71,7 @@ public abstract class PacketAffectTile extends PacketAffectChunk { output.writeByte(this.face.getId()); output.writeInt(this.tag); } - + @Override public void getAffectedChunk(Vec3i output) { Coordinates.convertInWorldToChunk(this.blockInWorld, output); diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java index e59ca37..9a8ef6c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/PacketRemoveTile.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; import java.io.DataInput; @@ -11,25 +29,25 @@ import ru.windcorp.progressia.common.world.WorldData; import ru.windcorp.progressia.common.world.block.BlockFace; public class PacketRemoveTile extends PacketAffectTile { - + public PacketRemoveTile() { this("Core:RemoveTile"); } - + protected PacketRemoveTile(String id) { super(id); } - + @Override public void set(Vec3i blockInWorld, BlockFace face, int tag) { super.set(blockInWorld, face, tag); } - + @Override public void read(DataInput input) throws IOException, DecodingException { super.read(input); } - + @Override public void write(DataOutput output) throws IOException { super.write(output); @@ -38,18 +56,21 @@ public class PacketRemoveTile extends PacketAffectTile { @Override public void apply(WorldData world) { TileDataStack stack = world.getTiles(getBlockInWorld(), getFace()); - + int index = stack.getIndexByTag(getTag()); - + if (index < 0) { - throw CrashReports.report(null, - "Could not find tile with tag %d at (%d; %d; %d; %s)", - getTag(), - getBlockInWorld().x, getBlockInWorld().y, getBlockInWorld().z, - getFace() + throw CrashReports.report( + null, + "Could not find tile with tag %d at (%d; %d; %d; %s)", + getTag(), + getBlockInWorld().x, + getBlockInWorld().y, + getBlockInWorld().z, + getFace() ); } - + stack.remove(index); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java index a08edf7..d314445 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileData.java @@ -1,29 +1,30 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world.tile; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.generic.GenericTile; - -public class TileData extends Namespaced implements GenericTile { - - public TileData(String id) { - super(id); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.tile; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.generic.GenericTile; + +public class TileData extends Namespaced implements GenericTile { + + public TileData(String id) { + super(id); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java index 6a95eae..110baea 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataRegistry.java @@ -1,30 +1,31 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.common.world.tile; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class TileDataRegistry extends NamespacedInstanceRegistry { - - private static final TileDataRegistry INSTANCE = new TileDataRegistry(); - - public static TileDataRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.common.world.tile; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class TileDataRegistry extends NamespacedInstanceRegistry { + + private static final TileDataRegistry INSTANCE = new TileDataRegistry(); + + public static TileDataRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java index 9f72116..80f0ba4 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileDataStack.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; import ru.windcorp.progressia.common.world.ChunkData; @@ -5,19 +23,18 @@ import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.generic.GenericTileStack; public abstract class TileDataStack -extends GenericTileStack< - TileDataStack, - TileData, - ChunkData -> { - + extends GenericTileStack { + /** * Inserts the specified tile at the specified position in this stack. - * Shifts the tile currently at that position (if any) and any tiles above to + * Shifts the tile currently at that position (if any) and any tiles above + * to * the top (adds one to their indices). + * * @param index index at which the specified tile is to be inserted - * @param tile tile to be inserted - * @throws TileStackIsFullException if this stack is {@linkplain #isFull() full} + * @param tile tile to be inserted + * @throws TileStackIsFullException if this stack is {@linkplain #isFull() + * full} */ /* * Impl note: AbstractList provides a useless implementation of this method, @@ -25,21 +42,27 @@ extends GenericTileStack< */ @Override public abstract void add(int index, TileData tile); - + /** - * Adds the specified tile at the end of this stack assigning it the provided tag. - * This method is useful for copying stacks when preserving tags is necessary. + * Adds the specified tile at the end of this stack assigning it the + * provided tag. + * This method is useful for copying stacks when preserving tags is + * necessary. + * * @param tile the tile to add - * @param tag the tag to assign the new tile - * @throws IllegalArgumentException if this stack already contains a tile with the - * provided tag + * @param tag the tag to assign the new tile + * @throws IllegalArgumentException if this stack already contains a tile + * with the + * provided tag */ public abstract void load(TileData tile, int tag); /** - * Replaces the tile at the specified position in this stack with the specified tile. + * Replaces the tile at the specified position in this stack with the + * specified tile. + * * @param index index of the tile to replace - * @param tile tile to be stored at the specified position + * @param tile tile to be stored at the specified position * @return the tile previously at the specified position */ /* @@ -50,9 +73,12 @@ extends GenericTileStack< public abstract TileData set(int index, TileData tile); /** - * Removes the tile at the specified position in this list. Shifts any subsequent tiles - * to the left (subtracts one from their indices). Returns the tile that was removed + * Removes the tile at the specified position in this list. Shifts any + * subsequent tiles + * to the left (subtracts one from their indices). Returns the tile that was + * removed * from the list. + * * @param index the index of the tile to be removed * @return the tile previously at the specified position */ @@ -62,75 +88,79 @@ extends GenericTileStack< */ @Override public abstract TileData remove(int index); - + public abstract TileReference getReference(int index); - + public abstract int getIndexByTag(int tag); - + public abstract int getTagByIndex(int index); - + /* * Aliases and overloads */ - + public void addClosest(TileData tile) { add(0, tile); } - + public void addFarthest(TileData tile) { add(size(), tile); } - + /** * Attempts to {@link #add(int, TileData) add} the provided {@code tile} - * at {@code index}. If the stack is {@linkplain #isFull() full}, does nothing. + * at {@code index}. If the stack is {@linkplain #isFull() full}, does + * nothing. + * * @param index the index to insert the tile at - * @param tile the tile to try to add + * @param tile the tile to try to add * @return {@code true} iff this stack has changed */ public boolean offer(int index, TileData tile) { - if (isFull()) return false; + if (isFull()) + return false; add(index, tile); return true; } - + public boolean offerClosest(TileData tile) { return offer(0, tile); } - + public boolean offerFarthest(TileData tile) { return offer(size(), tile); } - + public TileData removeClosest() { return remove(0); } - + public TileData removeFarthest() { return remove(size() - 1); } - + public TileData poll(int index) { - if (size() <= index) return null; + if (size() <= index) + return null; return remove(index); } - + public TileData pollClosest() { return poll(0); } - + public TileData pollFarthest() { return poll(size() - 1); } - + @Override public boolean add(TileData tile) { addFarthest(tile); return true; } - + public BlockData getHost() { return getChunk().getBlock(getBlockInChunk(null)); } - + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java index bcdc18d..75fde58 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileReference.java @@ -1,11 +1,31 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; public interface TileReference { - + TileData get(); + int getIndex(); + TileDataStack getStack(); - + default boolean isValid() { return get() != null; } diff --git a/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java b/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java index 55cd402..c9f6240 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java +++ b/src/main/java/ru/windcorp/progressia/common/world/tile/TileStackIsFullException.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.common.world.tile; public class TileStackIsFullException extends RuntimeException { @@ -5,11 +23,15 @@ public class TileStackIsFullException extends RuntimeException { private static final long serialVersionUID = 6665942370305610231L; public TileStackIsFullException() { - + } - public TileStackIsFullException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { + public TileStackIsFullException( + String message, + Throwable cause, + boolean enableSuppression, + boolean writableStackTrace + ) { super(message, cause, enableSuppression, writableStackTrace); } @@ -24,5 +46,5 @@ public class TileStackIsFullException extends RuntimeException { public TileStackIsFullException(Throwable cause) { super(cause); } - + } diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java b/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java index d5ae9e8..d708fe2 100644 --- a/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java +++ b/src/main/java/ru/windcorp/progressia/server/ChunkLoader.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import java.util.function.Consumer; @@ -5,7 +23,7 @@ import java.util.function.Consumer; import glm.vec._3.i.Vec3i; public interface ChunkLoader { - + void requestChunksToLoad(Consumer output); } diff --git a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java index 6b50e25..b0b0777 100644 --- a/src/main/java/ru/windcorp/progressia/server/ChunkManager.java +++ b/src/main/java/ru/windcorp/progressia/server/ChunkManager.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import java.util.Collections; @@ -14,55 +32,58 @@ import ru.windcorp.progressia.common.world.generic.ChunkSets; import ru.windcorp.progressia.test.TestWorldDiskIO; public class ChunkManager { - + private class PlayerVision { private final ChunkSet visible = ChunkSets.newSyncHashSet(); private final ChunkSet requested = ChunkSets.newHashSet(); private final ChunkSet toSend = ChunkSets.newHashSet(); private final ChunkSet toRevoke = ChunkSets.newHashSet(); - + public boolean isChunkVisible(Vec3i chunkPos) { return visible.contains(chunkPos); } - + public void gatherRequests(Player player) { requested.clear(); player.requestChunksToLoad(requested::add); } - + public void updateQueues(Player player) { toSend.clear(); - + requested.forEachIn(server.getWorld(), chunk -> { - if (!chunk.isReady()) return; - if (visible.contains(chunk)) return; + if (!chunk.isReady()) + return; + if (visible.contains(chunk)) + return; toSend.add(chunk); }); - + toRevoke.clear(); toRevoke.addAll(visible); toRevoke.removeIf(v -> loaded.contains(v) && requested.contains(v)); } - + public void processQueues(Player player) { toRevoke.forEach(chunkPos -> revokeChunk(player, chunkPos)); toRevoke.clear(); - + toSend.forEach(chunkPos -> sendChunk(player, chunkPos)); toSend.clear(); } - + } private final Server server; - + private final ChunkSet loaded; private final ChunkSet requested = ChunkSets.newHashSet(); private final ChunkSet toLoad = ChunkSets.newHashSet(); private final ChunkSet toUnload = ChunkSets.newHashSet(); - - // TODO replace with a normal Map managed by some sort of PlayerListener, weak maps are weak + + // TODO replace with a normal Map managed by some sort of PlayerListener, + // weak maps are weak private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); public ChunkManager(Server server) { @@ -82,23 +103,23 @@ public class ChunkManager { private void gatherRequests() { requested.clear(); - + server.getPlayerManager().getPlayers().forEach(p -> { PlayerVision vision = getVision(p, true); vision.gatherRequests(p); requested.addAll(vision.requested); }); } - + private void updateQueues() { toLoad.clear(); toLoad.addAll(requested); toLoad.removeAll(loaded); - + toUnload.clear(); toUnload.addAll(loaded); toUnload.removeAll(requested); - + visions.forEach((p, v) -> { v.updateQueues(p); }); @@ -109,92 +130,100 @@ public class ChunkManager { toUnload.clear(); toLoad.forEach(this::loadChunk); toLoad.clear(); - + visions.forEach((p, v) -> { v.processQueues(p); }); } - + private PlayerVision getVision(Player player, boolean createIfMissing) { return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); } - + public void loadChunk(Vec3i chunkPos) { WorldData world = getServer().getWorld().getData(); - + ChunkData chunk = TestWorldDiskIO.tryToLoad(chunkPos, world, getServer()); if (chunk != null) { - world.addChunk(chunk); + world.addChunk(chunk); } else { getServer().getWorld().generate(chunkPos); } - + } - + public void unloadChunk(Vec3i chunkPos) { - + WorldData world = getServer().getWorld().getData(); - + ChunkData chunk = world.getChunk(chunkPos); if (chunk == null) { - throw new IllegalStateException(String.format( + throw new IllegalStateException( + String.format( "Chunk (%d; %d; %d) not loaded, cannot unload", - chunkPos.x, chunkPos.y, chunkPos.z - )); + chunkPos.x, + chunkPos.y, + chunkPos.z + ) + ); } - + world.removeChunk(chunk); - + TestWorldDiskIO.saveChunk(chunk, getServer()); - + } public void sendChunk(Player player, Vec3i chunkPos) { ChunkData chunk = server.getWorld().getData().getChunk(chunkPos); - + if (chunk == null) { - throw new IllegalStateException(String.format( + throw new IllegalStateException( + String.format( "Chunk (%d; %d; %d) is not loaded, cannot send", - chunkPos.x, chunkPos.y, chunkPos.z - )); + chunkPos.x, + chunkPos.y, + chunkPos.z + ) + ); } - + PacketSendChunk packet = new PacketSendChunk(); - packet.set(chunk); + packet.set(chunk); player.getClient().sendPacket(packet); - + getVision(player, true).visible.add(chunkPos); } - + public void revokeChunk(Player player, Vec3i chunkPos) { PacketRevokeChunk packet = new PacketRevokeChunk(); packet.set(chunkPos); player.getClient().sendPacket(packet); - + PlayerVision vision = getVision(player, false); if (vision != null) { vision.visible.remove(chunkPos); } } - + public boolean isChunkVisible(Vec3i chunkPos, Player player) { PlayerVision vision = getVision(player, false); - + if (vision == null) { return false; } - + return vision.isChunkVisible(chunkPos); } - + public ChunkSet getVisibleChunks(Player player) { PlayerVision vision = getVision(player, false); - + if (vision == null) { return ChunkSets.empty(); } - + return vision.visible; } diff --git a/src/main/java/ru/windcorp/progressia/server/EntityManager.java b/src/main/java/ru/windcorp/progressia/server/EntityManager.java index ea4b813..d904c83 100644 --- a/src/main/java/ru/windcorp/progressia/server/EntityManager.java +++ b/src/main/java/ru/windcorp/progressia/server/EntityManager.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import java.util.Collections; @@ -17,41 +35,41 @@ import ru.windcorp.progressia.common.world.entity.PacketSendEntity; import ru.windcorp.progressia.common.world.generic.ChunkSet; public class EntityManager { - + private class PlayerVision { private final TLongSet visible = TCollections.synchronizedSet(new TLongHashSet()); private final TLongSet requested = new TLongHashSet(); private final TLongSet toSend = new TLongHashSet(); private final TLongSet toRevoke = new TLongHashSet(); - + public boolean isEntityVisible(long entityId) { return visible.contains(entityId); } - + public void gatherRequests(Player player) { requested.clear(); - + ChunkSet visibleChunks = player.getClient().getVisibleChunks(); Vec3i v = Vectors.grab3i(); - + getServer().getWorld().forEachEntity(entity -> { if (visibleChunks.contains(entity.getChunkCoords(v))) { requested.add(entity.getEntityId()); } }); - + Vectors.release(v); } - + public void updateQueues(Player player) { toSend.clear(); toSend.addAll(requested); toSend.removeAll(visible); toSend.retainAll(loaded); - + toRevoke.clear(); - + for (TLongIterator it = visible.iterator(); it.hasNext();) { long entityId = it.next(); if (!loaded.contains(entityId) || !requested.contains(entityId)) { @@ -59,28 +77,29 @@ public class EntityManager { } } } - + public void processQueues(Player player) { toRevoke.forEach(entityId -> { revokeEntity(player, entityId); return true; }); toRevoke.clear(); - + toSend.forEach(entityId -> { sendEntity(player, entityId); return true; }); toSend.clear(); } - + } private final Server server; - + private final TLongSet loaded; - - // TODO replace with a normal Map managed by some sort of PlayerListener, weak maps are weak + + // TODO replace with a normal Map managed by some sort of PlayerListener, + // weak maps are weak private final Map visions = Collections.synchronizedMap(new WeakHashMap<>()); public EntityManager(Server server) { @@ -104,7 +123,7 @@ public class EntityManager { vision.gatherRequests(p); }); } - + private void updateQueues() { visions.forEach((p, v) -> { v.updateQueues(p); @@ -116,61 +135,61 @@ public class EntityManager { v.processQueues(p); }); } - + private PlayerVision getVision(Player player, boolean createIfMissing) { return createIfMissing ? visions.computeIfAbsent(player, k -> new PlayerVision()) : visions.get(player); } - + public void sendEntity(Player player, long entityId) { - + EntityData entity = server.getWorld().getData().getEntity(entityId); - + if (entity == null) { throw new IllegalStateException( - "Entity with entity ID " + new String(StringUtil.toFullHex(entityId)) + " is not loaded, cannot send" + "Entity with entity ID " + new String(StringUtil.toFullHex(entityId)) + " is not loaded, cannot send" ); } - + PacketSendEntity packet = new PacketSendEntity(); packet.set(entity); player.getClient().sendPacket(packet); - + getVision(player, true).visible.add(entityId); } - + public void revokeEntity(Player player, long entityId) { PacketRevokeEntity packet = new PacketRevokeEntity(); packet.set(entityId); player.getClient().sendPacket(packet); - + PlayerVision vision = getVision(player, false); if (vision != null) { vision.visible.remove(entityId); } } - + public boolean isEntityVisible(long entityId, Player player) { PlayerVision vision = getVision(player, false); - + if (vision == null) { return false; } - + return vision.isEntityVisible(entityId); } - + private static final TLongSet EMPTY_LONG_SET = TCollections.unmodifiableSet(new TLongHashSet()); - + public TLongSet getVisibleEntities(Player player) { PlayerVision vision = getVision(player, false); - + if (vision == null) { return EMPTY_LONG_SET; } - + return vision.visible; } - + public Server getServer() { return server; } diff --git a/src/main/java/ru/windcorp/progressia/server/Player.java b/src/main/java/ru/windcorp/progressia/server/Player.java index 8b1b82f..ea373a8 100644 --- a/src/main/java/ru/windcorp/progressia/server/Player.java +++ b/src/main/java/ru/windcorp/progressia/server/Player.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import java.util.function.Consumer; @@ -11,7 +29,7 @@ import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.server.comms.ClientPlayer; public class Player extends PlayerData implements ChunkLoader { - + private final Server server; private final ClientPlayer client; @@ -19,14 +37,14 @@ public class Player extends PlayerData implements ChunkLoader { super(entity); this.server = server; this.client = client; - + client.setPlayer(this); } - + public Server getServer() { return server; } - + public ClientPlayer getClient() { return client; } @@ -35,22 +53,22 @@ public class Player extends PlayerData implements ChunkLoader { public void requestChunksToLoad(Consumer chunkConsumer) { Vec3i start = getEntity().getPosition().round_(); Coordinates.convertInWorldToChunk(start, start); - + Vec3i cursor = new Vec3i(); float radius = getServer().getLoadDistance(this) / Units.get(ChunkData.BLOCKS_PER_CHUNK, "m"); - + float radiusSq = radius * radius; int iRadius = (int) Math.ceil(radius); - + for (cursor.x = -iRadius; cursor.x <= +iRadius; ++cursor.x) { for (cursor.y = -iRadius; cursor.y <= +iRadius; ++cursor.y) { for (cursor.z = -iRadius; cursor.z <= +iRadius; ++cursor.z) { if (cursor.x * cursor.x + cursor.y * cursor.y + (cursor.z * 2) * (cursor.z * 2) <= radiusSq) { - + cursor.add(start); chunkConsumer.accept(cursor); cursor.sub(start); - + } } } @@ -60,5 +78,5 @@ public class Player extends PlayerData implements ChunkLoader { public String getLogin() { return getClient().getLogin(); } - + } diff --git a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java index ec352b1..38d0f32 100644 --- a/src/main/java/ru/windcorp/progressia/server/PlayerManager.java +++ b/src/main/java/ru/windcorp/progressia/server/PlayerManager.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import java.util.ArrayList; @@ -11,23 +29,23 @@ import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; import ru.windcorp.progressia.test.TestContent; public class PlayerManager { - + private final Server server; - + private final Collection players = Collections.synchronizedCollection(new ArrayList<>()); public PlayerManager(Server server) { this.server = server; } - + public Collection getPlayers() { return players; } - + public void addPlayer(Player player) { this.players.add(player); } - + public EntityData conjurePlayerEntity(String login) { // TODO Live up to the name if (TestContent.PLAYER_LOGIN.equals(login)) { @@ -37,18 +55,21 @@ public class PlayerManager { throw CrashReports.report(null, "Unknown login %s, javahorse stupid", login); } } - + private EntityData spawnPlayerEntity(String login) { EntityData player = EntityDataRegistry.getInstance().create("Test:Player"); - + player.setEntityId(TestContent.PLAYER_ENTITY_ID); player.setPosition(TestContent.SPAWN); - player.setDirection(new Vec2( - Math.toRadians(40), Math.toRadians(10) - )); - + player.setDirection( + new Vec2( + Math.toRadians(40), + Math.toRadians(10) + ) + ); + getServer().getWorld().getData().addEntity(player); - + return player; } diff --git a/src/main/java/ru/windcorp/progressia/server/Server.java b/src/main/java/ru/windcorp/progressia/server/Server.java index e5098ae..8aca03c 100644 --- a/src/main/java/ru/windcorp/progressia/server/Server.java +++ b/src/main/java/ru/windcorp/progressia/server/Server.java @@ -1,219 +1,259 @@ -package ru.windcorp.progressia.server; - -import java.util.function.Consumer; - -import org.apache.logging.log4j.LogManager; - -import ru.windcorp.jputil.functions.ThrowingRunnable; -import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.util.TaskQueue; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.server.comms.ClientManager; -import ru.windcorp.progressia.server.world.WorldLogic; -import ru.windcorp.progressia.server.world.tasks.WorldAccessor; -import ru.windcorp.progressia.server.world.ticking.Change; -import ru.windcorp.progressia.server.world.ticking.Evaluation; -import ru.windcorp.progressia.test.gen.TestWorldGenerator; - -public class Server { - - /** - * Returns the {@link Server} instance whose main thread is the current thread. - * @return the server that operates in this thread - */ - public static Server getCurrentServer() { - return ServerThread.getCurrentServer(); - } - - private final WorldLogic world; - private final WorldAccessor worldAccessor = new WorldAccessor(this); - - private final ServerThread serverThread; - - private final ClientManager clientManager; - private final PlayerManager playerManager; - private final ChunkManager chunkManager; - private final EntityManager entityManager; - - private final TaskQueue taskQueue = new TaskQueue(this::isServerThread); - - private final TickingSettings tickingSettings = new TickingSettings(); - - public Server(WorldData world) { - this.world = new WorldLogic(world, this, TestWorldGenerator::new); - this.serverThread = new ServerThread(this); - - this.clientManager = new ClientManager(this); - this.playerManager = new PlayerManager(this); - this.chunkManager = new ChunkManager(this); - this.entityManager = new EntityManager(this); - - schedule(this::scheduleWorldTicks); - schedule(chunkManager::tick); - schedule(entityManager::tick); - } - - /** - * Returns this server's world. - * @return this server's {@link WorldLogic} - */ - public WorldLogic getWorld() { - return world; - } - - /** - * Returns this server's {@link ClientManager}. - * Use this to deal with communications, e.g. send packets. - * @return the {@link ClientManager} that handles this server - */ - public ClientManager getClientManager() { - return clientManager; - } - - public PlayerManager getPlayerManager() { - return playerManager; - } - - public ChunkManager getChunkManager() { - return chunkManager; - } - - /** - * Checks if this thread is the main thread of this server. - * @return {@code true} iff the invocation occurs in server main thread - */ - public boolean isServerThread() { - return getCurrentServer() == this; - } - - /** - * Requests that the provided task is executed once on next server tick. - * The task will be run in the main server thread. The task object is - * discarded after execution. - * - *

Use this method to request a one-time (rare) action that must necessarily - * happen in the main server thread, such as initialization tasks or reconfiguration. - * - * @param task the task to run - * @see #invokeNow(Runnable) - * @see #schedule(Consumer) - */ - public void invokeLater(Runnable task) { - taskQueue.invokeLater(task); - } - - /** - * Executes the tasks in the server main thread as soon as possible. - * - *

If this method is invoked in the server main thread, then the task is - * run immediately (the method blocks until the task finishes). Otherwise - * this method behaves exactly like {@link #invokeLater(Runnable)}. - * - *

Use this method to make sure that a piece of code is run in the main server - * thread. - * - * @param task the task to run - * @see #invokeLater(Runnable) - * @see #schedule(Consumer) - */ - public void invokeNow(Runnable task) { - taskQueue.invokeNow(task); - } - - public void waitAndInvoke( - ThrowingRunnable task - ) throws InterruptedException, E { - taskQueue.waitAndInvoke(task); - } - - public void schedule(Runnable task) { - taskQueue.schedule(task); - } - - public void schedule(Consumer task) { - schedule(() -> task.accept(this)); - } - - public void requestChange(Change change) { - serverThread.getTicker().requestChange(change); - } - - public void requestEvaluation(Evaluation evaluation) { - serverThread.getTicker().requestEvaluation(evaluation); - } - - /** - * Returns the duration of the last server tick. Server logic should assume that this much in-world time has passed. - * @return the length of the last server tick - */ - public double getTickLength() { - return this.serverThread.getTicker().getTickLength(); - } - - public double getTPS() { - return this.serverThread.getTicker().getTPS(); - } - - /** - * Returns the {@link WorldAccessor} object for this server. Use the provided accessor to - * request common {@link Evaluation}s and {@link Change}s. - * @return a {@link WorldAccessor} - * @see #requestChange(Change) - * @see #requestEvaluation(Evaluation) - */ - public WorldAccessor getWorldAccessor() { - return worldAccessor; - } - - /** - * Returns the ticking settings for this server. - * @return a {@link TickingSettings} object - */ - public TickingSettings getTickingSettings() { - return tickingSettings; - } - - public float getLoadDistance(Player player) { - return Units.get(150.0f, "m"); - } - - /** - * Starts the server. This method blocks until the server enters normal operation or fails to start. - */ - public void start() { - this.serverThread.start(); - } - - /** - * Performs the tasks from tasks queues and repeating tasks. - */ - public void tick() { - taskQueue.runTasks(); - } - - /** - * Shuts the server down, disconnecting the clients with the provided message. - * This method blocks until the shutdown is complete. - * @param message the message to send to the clients as the disconnect reason - */ - public void shutdown(String message) { - LogManager.getLogger().warn("Server.shutdown() is not yet implemented"); - serverThread.stop(); - } - - private void scheduleWorldTicks(Server server) { - server.getWorld().getChunks().forEach(chunk -> requestEvaluation(chunk.getTickTask())); - requestEvaluation(server.getWorld().getTickEntitiesTask()); - } - - /** - * Returns an instance of {@link java.util.Random Random} that can be used as a source of indeterministic - * randomness. World generation and other algorithms that must have random but reproducible results should - * not use this. - * @return a thread-safe indeterministic instance of {@link java.util.Random}. - */ - public java.util.Random getAdHocRandom() { - return java.util.concurrent.ThreadLocalRandom.current(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server; + +import java.util.function.Consumer; + +import org.apache.logging.log4j.LogManager; + +import ru.windcorp.jputil.functions.ThrowingRunnable; +import ru.windcorp.progressia.common.Units; +import ru.windcorp.progressia.common.util.TaskQueue; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.comms.ClientManager; +import ru.windcorp.progressia.server.world.WorldLogic; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; +import ru.windcorp.progressia.server.world.ticking.Change; +import ru.windcorp.progressia.server.world.ticking.Evaluation; +import ru.windcorp.progressia.test.gen.TestWorldGenerator; + +public class Server { + + /** + * Returns the {@link Server} instance whose main thread is the current + * thread. + * + * @return the server that operates in this thread + */ + public static Server getCurrentServer() { + return ServerThread.getCurrentServer(); + } + + private final WorldLogic world; + private final WorldAccessor worldAccessor = new WorldAccessor(this); + + private final ServerThread serverThread; + + private final ClientManager clientManager; + private final PlayerManager playerManager; + private final ChunkManager chunkManager; + private final EntityManager entityManager; + + private final TaskQueue taskQueue = new TaskQueue(this::isServerThread); + + private final TickingSettings tickingSettings = new TickingSettings(); + + public Server(WorldData world) { + this.world = new WorldLogic(world, this, TestWorldGenerator::new); + this.serverThread = new ServerThread(this); + + this.clientManager = new ClientManager(this); + this.playerManager = new PlayerManager(this); + this.chunkManager = new ChunkManager(this); + this.entityManager = new EntityManager(this); + + schedule(this::scheduleWorldTicks); + schedule(chunkManager::tick); + schedule(entityManager::tick); + } + + /** + * Returns this server's world. + * + * @return this server's {@link WorldLogic} + */ + public WorldLogic getWorld() { + return world; + } + + /** + * Returns this server's {@link ClientManager}. + * Use this to deal with communications, e.g. send packets. + * + * @return the {@link ClientManager} that handles this server + */ + public ClientManager getClientManager() { + return clientManager; + } + + public PlayerManager getPlayerManager() { + return playerManager; + } + + public ChunkManager getChunkManager() { + return chunkManager; + } + + /** + * Checks if this thread is the main thread of this server. + * + * @return {@code true} iff the invocation occurs in server main thread + */ + public boolean isServerThread() { + return getCurrentServer() == this; + } + + /** + * Requests that the provided task is executed once on next server tick. + * The task will be run in the main server thread. The task object is + * discarded after execution. + *

+ * Use this method to request a one-time (rare) action that must necessarily + * happen in the main server thread, such as initialization tasks or + * reconfiguration. + * + * @param task the task to run + * @see #invokeNow(Runnable) + * @see #schedule(Consumer) + */ + public void invokeLater(Runnable task) { + taskQueue.invokeLater(task); + } + + /** + * Executes the tasks in the server main thread as soon as possible. + *

+ * If this method is invoked in the server main thread, then the task is + * run immediately (the method blocks until the task finishes). Otherwise + * this method behaves exactly like {@link #invokeLater(Runnable)}. + *

+ * Use this method to make sure that a piece of code is run in the main + * server + * thread. + * + * @param task the task to run + * @see #invokeLater(Runnable) + * @see #schedule(Consumer) + */ + public void invokeNow(Runnable task) { + taskQueue.invokeNow(task); + } + + public void waitAndInvoke( + ThrowingRunnable task + ) + throws InterruptedException, + E { + taskQueue.waitAndInvoke(task); + } + + public void schedule(Runnable task) { + taskQueue.schedule(task); + } + + public void schedule(Consumer task) { + schedule(() -> task.accept(this)); + } + + public void requestChange(Change change) { + serverThread.getTicker().requestChange(change); + } + + public void requestEvaluation(Evaluation evaluation) { + serverThread.getTicker().requestEvaluation(evaluation); + } + + /** + * Returns the duration of the last server tick. Server logic should assume + * that this much in-world time has passed. + * + * @return the length of the last server tick + */ + public double getTickLength() { + return this.serverThread.getTicker().getTickLength(); + } + + public double getTPS() { + return this.serverThread.getTicker().getTPS(); + } + + /** + * Returns the {@link WorldAccessor} object for this server. Use the + * provided accessor to + * request common {@link Evaluation}s and {@link Change}s. + * + * @return a {@link WorldAccessor} + * @see #requestChange(Change) + * @see #requestEvaluation(Evaluation) + */ + public WorldAccessor getWorldAccessor() { + return worldAccessor; + } + + /** + * Returns the ticking settings for this server. + * + * @return a {@link TickingSettings} object + */ + public TickingSettings getTickingSettings() { + return tickingSettings; + } + + public float getLoadDistance(Player player) { + return Units.get(150.0f, "m"); + } + + /** + * Starts the server. This method blocks until the server enters normal + * operation or fails to start. + */ + public void start() { + this.serverThread.start(); + } + + /** + * Performs the tasks from tasks queues and repeating tasks. + */ + public void tick() { + taskQueue.runTasks(); + } + + /** + * Shuts the server down, disconnecting the clients with the provided + * message. + * This method blocks until the shutdown is complete. + * + * @param message the message to send to the clients as the disconnect + * reason + */ + public void shutdown(String message) { + LogManager.getLogger().warn("Server.shutdown() is not yet implemented"); + serverThread.stop(); + } + + private void scheduleWorldTicks(Server server) { + server.getWorld().getChunks().forEach(chunk -> requestEvaluation(chunk.getTickTask())); + requestEvaluation(server.getWorld().getTickEntitiesTask()); + } + + /** + * Returns an instance of {@link java.util.Random Random} that can be used + * as a source of indeterministic + * randomness. World generation and other algorithms that must have random + * but reproducible results should + * not use this. + * + * @return a thread-safe indeterministic instance of + * {@link java.util.Random}. + */ + public java.util.Random getAdHocRandom() { + return java.util.concurrent.ThreadLocalRandom.current(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/ServerState.java b/src/main/java/ru/windcorp/progressia/server/ServerState.java index d8071f6..774f17d 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerState.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerState.java @@ -1,25 +1,44 @@ -package ru.windcorp.progressia.server; - -import ru.windcorp.progressia.common.world.WorldData; - -public class ServerState { - - private static Server instance = null; - - public static Server getInstance() { - return instance; - } - - public static void setInstance(Server instance) { - ServerState.instance = instance; - } - - public static void startServer() { - Server server = new Server(new WorldData()); - setInstance(server); - server.start(); - } - - private ServerState() {} - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server; + +import ru.windcorp.progressia.common.world.WorldData; + +public class ServerState { + + private static Server instance = null; + + public static Server getInstance() { + return instance; + } + + public static void setInstance(Server instance) { + ServerState.instance = instance; + } + + public static void startServer() { + Server server = new Server(new WorldData()); + setInstance(server); + server.start(); + } + + private ServerState() { + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/ServerThread.java b/src/main/java/ru/windcorp/progressia/server/ServerThread.java index e05c98d..90f3ce9 100644 --- a/src/main/java/ru/windcorp/progressia/server/ServerThread.java +++ b/src/main/java/ru/windcorp/progressia/server/ServerThread.java @@ -1,82 +1,98 @@ -package ru.windcorp.progressia.server; - -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import org.apache.logging.log4j.LogManager; - -import ru.windcorp.progressia.common.util.crash.CrashReports; -import ru.windcorp.progressia.server.world.ticking.TickerCoordinator; - -public class ServerThread implements Runnable { - - private static final ThreadLocal SERVER_THREADS_MAP = - new ThreadLocal<>(); - - public static Server getCurrentServer() { - return SERVER_THREADS_MAP.get(); - } - - private class ServerThreadTracker implements Runnable { - - private final Runnable payload; - - public ServerThreadTracker(Runnable payload) { - this.payload = payload; - } - - @Override - public void run() { - SERVER_THREADS_MAP.set(getServer()); - payload.run(); - } - - } - - private final Server server; - private final ScheduledExecutorService executor = - Executors.newSingleThreadScheduledExecutor( - r -> new Thread(new ServerThreadTracker(r), "Server thread") - ); - - private final TickerCoordinator ticker; - - public ServerThread(Server server) { - this.server = server; - this.ticker = new TickerCoordinator(server, 1); - } - - public void start() { - ticker.start(); - executor.scheduleAtFixedRate(this, 0, 1000 / 20, TimeUnit.MILLISECONDS); - } - - @Override - public void run() { - try { - server.tick(); - ticker.runOneTick(); - } catch (Throwable e) { - CrashReports.crash(e, "Got a throwable in the server thread"); - } - } - - public void stop() { - try { - executor.awaitTermination(10, TimeUnit.MINUTES); - } catch (InterruptedException e) { - LogManager.getLogger().warn("Received interrupt in ServerThread.stop(), aborting wait"); - } - - getTicker().stop(); - } - - public Server getServer() { - return server; - } - - public TickerCoordinator getTicker() { - return ticker; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.LogManager; + +import ru.windcorp.progressia.common.util.crash.CrashReports; +import ru.windcorp.progressia.server.world.ticking.TickerCoordinator; + +public class ServerThread implements Runnable { + + private static final ThreadLocal SERVER_THREADS_MAP = new ThreadLocal<>(); + + public static Server getCurrentServer() { + return SERVER_THREADS_MAP.get(); + } + + private class ServerThreadTracker implements Runnable { + + private final Runnable payload; + + public ServerThreadTracker(Runnable payload) { + this.payload = payload; + } + + @Override + public void run() { + SERVER_THREADS_MAP.set(getServer()); + payload.run(); + } + + } + + private final Server server; + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( + r -> new Thread(new ServerThreadTracker(r), "Server thread") + ); + + private final TickerCoordinator ticker; + + public ServerThread(Server server) { + this.server = server; + this.ticker = new TickerCoordinator(server, 1); + } + + public void start() { + ticker.start(); + executor.scheduleAtFixedRate(this, 0, 1000 / 20, TimeUnit.MILLISECONDS); + } + + @Override + public void run() { + try { + server.tick(); + ticker.runOneTick(); + } catch (Throwable e) { + CrashReports.crash(e, "Got a throwable in the server thread"); + } + } + + public void stop() { + try { + executor.awaitTermination(10, TimeUnit.MINUTES); + } catch (InterruptedException e) { + LogManager.getLogger().warn("Received interrupt in ServerThread.stop(), aborting wait"); + } + + getTicker().stop(); + } + + public Server getServer() { + return server; + } + + public TickerCoordinator getTicker() { + return ticker; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/TickingSettings.java b/src/main/java/ru/windcorp/progressia/server/TickingSettings.java index 0ac8777..743da10 100644 --- a/src/main/java/ru/windcorp/progressia/server/TickingSettings.java +++ b/src/main/java/ru/windcorp/progressia/server/TickingSettings.java @@ -1,13 +1,32 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server; import ru.windcorp.progressia.common.Units; public class TickingSettings { - + private float randomTickFrequency = Units.get("1 min^-1"); - + /** * Returns the average rate of random ticks in a single block. + * * @return ticking frequency */ public float getRandomTickFrequency() { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/Client.java b/src/main/java/ru/windcorp/progressia/server/comms/Client.java index 6903289..f439e27 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/Client.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/Client.java @@ -1,22 +1,40 @@ -package ru.windcorp.progressia.server.comms; - -import ru.windcorp.progressia.common.comms.CommsChannel; - -public abstract class Client extends CommsChannel { - - private final int id; - - public Client(int id) { - this.id = id; - } - - public int getId() { - return id; - } - - @Override - public String toString() { - return getClass().getSimpleName() + " " + id; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.comms; + +import ru.windcorp.progressia.common.comms.CommsChannel; + +public abstract class Client extends CommsChannel { + + private final int id; + + public Client(int id) { + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " " + id; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java index cf01486..35b9ca2 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientChat.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.comms; public abstract class ClientChat extends Client { diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java index 9d84304..cb4b80b 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientManager.java @@ -1,127 +1,156 @@ -package ru.windcorp.progressia.server.comms; - -import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.atomic.AtomicInteger; - -import glm.vec._3.i.Vec3i; -import gnu.trove.TCollections; -import gnu.trove.map.TIntObjectMap; -import gnu.trove.map.hash.TIntObjectHashMap; -import ru.windcorp.progressia.common.comms.CommsChannel.State; -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.Player; -import ru.windcorp.progressia.server.Server; - -public class ClientManager { - - private final Server server; - - private final TIntObjectMap clientsById = - TCollections.synchronizedMap(new TIntObjectHashMap<>()); - - private final Collection clients = - Collections.unmodifiableCollection(clientsById.valueCollection()); - - private final AtomicInteger nextId = new AtomicInteger(0); - - public ClientManager(Server server) { - this.server = server; - } - - public int grabClientId() { - return nextId.getAndIncrement(); - } - - public void addClient(Client client) { - synchronized (client) { - clientsById.put(client.getId(), client); - - if (client instanceof ClientChat) { - addClientChat((ClientChat) client); - - if (client instanceof ClientPlayer) { - addClientPlayer((ClientPlayer) client); - } - } - - client.addListener(new DefaultServerCommsListener(this, client)); - } - } - - private void addClientChat(ClientChat client) { - // Do nothing - } - - private void addClientPlayer(ClientPlayer client) { - String login = client.getLogin(); - - EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); - Player player = new Player(entity, getServer(), client); - getServer().getPlayerManager().getPlayers().add(player); - - PacketSetLocalPlayer packet = new PacketSetLocalPlayer(); - packet.set(entity.getEntityId()); - client.sendPacket(packet); - } - - public void disconnectClient(Client client) { - client.disconnect(); - clientsById.remove(client.getId()); - } - - /** - * Sends the provided packet to all connected player clients. - * @param packet the packet to broadcast - */ - public void broadcastToAllPlayers(Packet packet) { - getClients().forEach(c -> { - if (c.getState() != State.CONNECTED) return; - if (!(c instanceof ClientPlayer)) return; - c.sendPacket(packet); - }); - } - - /** - * Sends the provided packet to all connected player clients that can see the chunk identified by {@code chunkPos}. - * @param packet the packet to broadcast - * @param chunkPos the chunk coordinates of the chunk that must be visible - */ - public void broadcastLocal(Packet packet, Vec3i chunkPos) { - getClients().forEach(c -> { - if (c.getState() != State.CONNECTED) return; - if (!(c instanceof ClientPlayer)) return; - if (!((ClientPlayer) c).isChunkVisible(chunkPos)) return; - c.sendPacket(packet); - }); - } - - /** - * Sends the provided packet to all connected player clients that can see the entity identified by {@code entityId}. - * @param packet the packet to broadcast - * @param entityId the ID of the entity that must be visible - */ - public void broadcastLocal(Packet packet, long entityId) { - getClients().forEach(c -> { - if (c.getState() != State.CONNECTED) return; - if (!(c instanceof ClientPlayer)) return; - if (!((ClientPlayer) c).isChunkVisible(entityId)) return; - c.sendPacket(packet); - }); - } - - public Collection getClients() { - return clients; - } - - public Client getById(int id) { - return clientsById.get(id); - } - - public Server getServer() { - return server; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.comms; + +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.atomic.AtomicInteger; + +import glm.vec._3.i.Vec3i; +import gnu.trove.TCollections; +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import ru.windcorp.progressia.common.comms.CommsChannel.State; +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.server.Player; +import ru.windcorp.progressia.server.Server; + +public class ClientManager { + + private final Server server; + + private final TIntObjectMap clientsById = TCollections.synchronizedMap(new TIntObjectHashMap<>()); + + private final Collection clients = Collections.unmodifiableCollection(clientsById.valueCollection()); + + private final AtomicInteger nextId = new AtomicInteger(0); + + public ClientManager(Server server) { + this.server = server; + } + + public int grabClientId() { + return nextId.getAndIncrement(); + } + + public void addClient(Client client) { + synchronized (client) { + clientsById.put(client.getId(), client); + + if (client instanceof ClientChat) { + addClientChat((ClientChat) client); + + if (client instanceof ClientPlayer) { + addClientPlayer((ClientPlayer) client); + } + } + + client.addListener(new DefaultServerCommsListener(this, client)); + } + } + + private void addClientChat(ClientChat client) { + // Do nothing + } + + private void addClientPlayer(ClientPlayer client) { + String login = client.getLogin(); + + EntityData entity = getServer().getPlayerManager().conjurePlayerEntity(login); + Player player = new Player(entity, getServer(), client); + getServer().getPlayerManager().getPlayers().add(player); + + PacketSetLocalPlayer packet = new PacketSetLocalPlayer(); + packet.set(entity.getEntityId()); + client.sendPacket(packet); + } + + public void disconnectClient(Client client) { + client.disconnect(); + clientsById.remove(client.getId()); + } + + /** + * Sends the provided packet to all connected player clients. + * + * @param packet the packet to broadcast + */ + public void broadcastToAllPlayers(Packet packet) { + getClients().forEach(c -> { + if (c.getState() != State.CONNECTED) + return; + if (!(c instanceof ClientPlayer)) + return; + c.sendPacket(packet); + }); + } + + /** + * Sends the provided packet to all connected player clients that can see + * the chunk identified by {@code chunkPos}. + * + * @param packet the packet to broadcast + * @param chunkPos the chunk coordinates of the chunk that must be visible + */ + public void broadcastLocal(Packet packet, Vec3i chunkPos) { + getClients().forEach(c -> { + if (c.getState() != State.CONNECTED) + return; + if (!(c instanceof ClientPlayer)) + return; + if (!((ClientPlayer) c).isChunkVisible(chunkPos)) + return; + c.sendPacket(packet); + }); + } + + /** + * Sends the provided packet to all connected player clients that can see + * the entity identified by {@code entityId}. + * + * @param packet the packet to broadcast + * @param entityId the ID of the entity that must be visible + */ + public void broadcastLocal(Packet packet, long entityId) { + getClients().forEach(c -> { + if (c.getState() != State.CONNECTED) + return; + if (!(c instanceof ClientPlayer)) + return; + if (!((ClientPlayer) c).isChunkVisible(entityId)) + return; + c.sendPacket(packet); + }); + } + + public Collection getClients() { + return clients; + } + + public Client getById(int id) { + return clientsById.get(id); + } + + public Server getServer() { + return server; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java index 00db77c..c455b8e 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/ClientPlayer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.comms; import glm.vec._3.i.Vec3i; @@ -6,33 +24,35 @@ import ru.windcorp.progressia.common.world.generic.ChunkSets; import ru.windcorp.progressia.server.Player; public abstract class ClientPlayer extends ClientChat { - + private Player player; public ClientPlayer(int id) { super(id); } - + public Player getPlayer() { return player; } - + public void setPlayer(Player player) { this.player = player; } - + public abstract String getLogin(); - + public boolean isChunkVisible(Vec3i chunkPos) { - if (player == null) return false; + if (player == null) + return false; return player.getServer().getChunkManager().isChunkVisible(chunkPos, player); } - + public ChunkSet getVisibleChunks() { - if (player == null) return ChunkSets.empty(); + if (player == null) + return ChunkSets.empty(); return player.getServer().getChunkManager().getVisibleChunks(player); } - + public boolean isChunkVisible(long entityId) { return true; } diff --git a/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java b/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java index 6583f60..d570e01 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/DefaultServerCommsListener.java @@ -1,39 +1,57 @@ -package ru.windcorp.progressia.server.comms; - -import java.io.IOException; - -import ru.windcorp.progressia.common.comms.controls.PacketControl; -import ru.windcorp.progressia.common.comms.CommsListener; -import ru.windcorp.progressia.common.comms.packets.Packet; -import ru.windcorp.progressia.server.comms.controls.ControlLogicRegistry; - -public class DefaultServerCommsListener implements CommsListener { - - private final ClientManager manager; - private final Client client; - - public DefaultServerCommsListener(ClientManager manager, Client client) { - this.manager = manager; - this.client = client; - } - - @Override - public void onPacketReceived(Packet packet) { - if (client instanceof ClientPlayer) { - if (packet instanceof PacketControl) { - PacketControl packetControl = (PacketControl) packet; - - ControlLogicRegistry.getInstance().get( - packetControl.getControl().getId() - ).apply(manager.getServer(), packetControl, client); - } - } - } - - @Override - public void onIOError(IOException reason) { - // TODO Auto-generated method stub - - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.comms; + +import java.io.IOException; + +import ru.windcorp.progressia.common.comms.controls.PacketControl; +import ru.windcorp.progressia.common.comms.CommsListener; +import ru.windcorp.progressia.common.comms.packets.Packet; +import ru.windcorp.progressia.server.comms.controls.ControlLogicRegistry; + +public class DefaultServerCommsListener implements CommsListener { + + private final ClientManager manager; + private final Client client; + + public DefaultServerCommsListener(ClientManager manager, Client client) { + this.manager = manager; + this.client = client; + } + + @Override + public void onPacketReceived(Packet packet) { + if (client instanceof ClientPlayer) { + if (packet instanceof PacketControl) { + PacketControl packetControl = (PacketControl) packet; + + ControlLogicRegistry.getInstance().get( + packetControl.getControl().getId() + ).apply(manager.getServer(), packetControl, client); + } + } + } + + @Override + public void onIOError(IOException reason) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java index 28aca40..31e97a2 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogic.java @@ -1,38 +1,56 @@ -package ru.windcorp.progressia.server.comms.controls; - -import ru.windcorp.progressia.common.comms.controls.PacketControl; -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.comms.Client; - -public abstract class ControlLogic extends Namespaced { - - @FunctionalInterface - public static interface Lambda { - void apply( - Server server, - PacketControl packet, - Client client - ); - } - - public ControlLogic(String id) { - super(id); - } - - public abstract void apply( - Server server, - PacketControl packet, - Client client - ); - - public static ControlLogic of(String id, Lambda logic) { - return new ControlLogic(id) { - @Override - public void apply(Server server, PacketControl packet, Client client) { - logic.apply(server, packet, client); - } - }; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.comms.controls; + +import ru.windcorp.progressia.common.comms.controls.PacketControl; +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.comms.Client; + +public abstract class ControlLogic extends Namespaced { + + @FunctionalInterface + public static interface Lambda { + void apply( + Server server, + PacketControl packet, + Client client + ); + } + + public ControlLogic(String id) { + super(id); + } + + public abstract void apply( + Server server, + PacketControl packet, + Client client + ); + + public static ControlLogic of(String id, Lambda logic) { + return new ControlLogic(id) { + @Override + public void apply(Server server, PacketControl packet, Client client) { + logic.apply(server, packet, client); + } + }; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java index 403644d..18ece0a 100644 --- a/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/comms/controls/ControlLogicRegistry.java @@ -1,14 +1,31 @@ -package ru.windcorp.progressia.server.comms.controls; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class ControlLogicRegistry extends NamespacedInstanceRegistry { - - private static final ControlLogicRegistry INSTANCE = - new ControlLogicRegistry(); - - public static ControlLogicRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.comms.controls; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class ControlLogicRegistry extends NamespacedInstanceRegistry { + + private static final ControlLogicRegistry INSTANCE = new ControlLogicRegistry(); + + public static ControlLogicRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java index d26b308..37685d2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkLogic.java @@ -1,184 +1,199 @@ -package ru.windcorp.progressia.server.world; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.function.BiConsumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericChunk; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; -import ru.windcorp.progressia.server.world.block.TickableBlock; -import ru.windcorp.progressia.server.world.tasks.TickChunk; -import ru.windcorp.progressia.server.world.ticking.TickingPolicy; -import ru.windcorp.progressia.server.world.tile.TickableTile; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; - -public class ChunkLogic implements GenericChunk< - ChunkLogic, - BlockLogic, - TileLogic, - TileLogicStack -> { - - private final WorldLogic world; - private final ChunkData data; - - private final Collection tickingBlocks = new ArrayList<>(); - private final Collection tickingTiles = new ArrayList<>(); - - private final TickChunk tickTask = new TickChunk(this); - - private final Map tileLogicLists = - Collections.synchronizedMap(new WeakHashMap<>()); - - public ChunkLogic(WorldLogic world, ChunkData data) { - this.world = world; - this.data = data; - - tmp_generateTickLists(); - } - - @Override - public Vec3i getPosition() { - return getData().getPosition(); - } - - @Override - public BlockLogic getBlock(Vec3i blockInChunk) { - return BlockLogicRegistry.getInstance().get( - getData().getBlock(blockInChunk).getId() - ); - } - - @Override - public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { - return getTileStackWrapper(getData().getTiles(blockInChunk, face)); - } - - @Override - public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { - return getData().hasTiles(blockInChunk, face); - } - - private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { - return tileLogicLists.computeIfAbsent( - tileDataList, - TileLogicStackImpl::new - ); - } - - public WorldLogic getWorld() { - return world; - } - - public ChunkData getData() { - return data; - } - - public boolean isReady() { - return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); - } - - public boolean hasTickingBlocks() { - return !tickingBlocks.isEmpty(); - } - - public boolean hasTickingTiles() { - return !tickingTiles.isEmpty(); - } - - public void forEachTickingBlock(BiConsumer action) { - tickingBlocks.forEach(blockInChunk -> { - action.accept(blockInChunk, getBlock(blockInChunk)); - }); - } - - public void forEachTickingTile(BiConsumer action) { - tickingTiles.forEach(ref -> { - action.accept( - ref, - TileLogicRegistry.getInstance().get(ref.get().getId()) - ); - }); - } - - public TickChunk getTickTask() { - return tickTask; - } - - private class TileLogicStackImpl extends TileLogicStack { - - private final TileDataStack parent; - - public TileLogicStackImpl(TileDataStack parent) { - this.parent = parent; - } - - @Override - public Vec3i getBlockInChunk(Vec3i output) { - return parent.getBlockInChunk(output); - } - - @Override - public ChunkLogic getChunk() { - return ChunkLogic.this; - } - - @Override - public BlockFace getFace() { - return parent.getFace(); - } - - @Override - public TileLogic get(int index) { - return TileLogicRegistry.getInstance().get(parent.get(index).getId()); - } - - @Override - public int size() { - return parent.size(); - } - - @Override - public TileDataStack getData() { - return parent; - } - - } - - private void tmp_generateTickLists() { - ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); - - context.forEachBlock(bctxt -> { - BlockLogic block = bctxt.getBlock(); - - if (!(block instanceof TickableBlock)) return; - - if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { - tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); - } - - bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { - TileLogic tile = tctxt.getTile(); - - if (!(tile instanceof TickableTile)) return; - - if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { - tickingTiles.add(tctxt.getReference()); - } - })); - }); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.function.BiConsumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericChunk; +import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.tile.TileReference; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.block.BlockLogicRegistry; +import ru.windcorp.progressia.server.world.block.TickableBlock; +import ru.windcorp.progressia.server.world.tasks.TickChunk; +import ru.windcorp.progressia.server.world.ticking.TickingPolicy; +import ru.windcorp.progressia.server.world.tile.TickableTile; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicRegistry; +import ru.windcorp.progressia.server.world.tile.TileLogicStack; + +public class ChunkLogic implements GenericChunk { + + private final WorldLogic world; + private final ChunkData data; + + private final Collection tickingBlocks = new ArrayList<>(); + private final Collection tickingTiles = new ArrayList<>(); + + private final TickChunk tickTask = new TickChunk(this); + + private final Map tileLogicLists = Collections + .synchronizedMap(new WeakHashMap<>()); + + public ChunkLogic(WorldLogic world, ChunkData data) { + this.world = world; + this.data = data; + + tmp_generateTickLists(); + } + + @Override + public Vec3i getPosition() { + return getData().getPosition(); + } + + @Override + public BlockLogic getBlock(Vec3i blockInChunk) { + return BlockLogicRegistry.getInstance().get( + getData().getBlock(blockInChunk).getId() + ); + } + + @Override + public TileLogicStack getTiles(Vec3i blockInChunk, BlockFace face) { + return getTileStackWrapper(getData().getTiles(blockInChunk, face)); + } + + @Override + public boolean hasTiles(Vec3i blockInChunk, BlockFace face) { + return getData().hasTiles(blockInChunk, face); + } + + private TileLogicStack getTileStackWrapper(TileDataStack tileDataList) { + return tileLogicLists.computeIfAbsent( + tileDataList, + TileLogicStackImpl::new + ); + } + + public WorldLogic getWorld() { + return world; + } + + public ChunkData getData() { + return data; + } + + public boolean isReady() { + return getWorld().getGenerator().isChunkReady(getData().getGenerationHint()); + } + + public boolean hasTickingBlocks() { + return !tickingBlocks.isEmpty(); + } + + public boolean hasTickingTiles() { + return !tickingTiles.isEmpty(); + } + + public void forEachTickingBlock(BiConsumer action) { + tickingBlocks.forEach(blockInChunk -> { + action.accept(blockInChunk, getBlock(blockInChunk)); + }); + } + + public void forEachTickingTile(BiConsumer action) { + tickingTiles.forEach(ref -> { + action.accept( + ref, + TileLogicRegistry.getInstance().get(ref.get().getId()) + ); + }); + } + + public TickChunk getTickTask() { + return tickTask; + } + + private class TileLogicStackImpl extends TileLogicStack { + + private final TileDataStack parent; + + public TileLogicStackImpl(TileDataStack parent) { + this.parent = parent; + } + + @Override + public Vec3i getBlockInChunk(Vec3i output) { + return parent.getBlockInChunk(output); + } + + @Override + public ChunkLogic getChunk() { + return ChunkLogic.this; + } + + @Override + public BlockFace getFace() { + return parent.getFace(); + } + + @Override + public TileLogic get(int index) { + return TileLogicRegistry.getInstance().get(parent.get(index).getId()); + } + + @Override + public int size() { + return parent.size(); + } + + @Override + public TileDataStack getData() { + return parent; + } + + } + + private void tmp_generateTickLists() { + ChunkTickContext context = TickContextMutable.start().withChunk(this).build(); + + context.forEachBlock(bctxt -> { + BlockLogic block = bctxt.getBlock(); + + if (!(block instanceof TickableBlock)) + return; + + if (((TickableBlock) block).getTickingPolicy(bctxt) == TickingPolicy.REGULAR) { + tickingBlocks.add(Coordinates.convertInWorldToInChunk(bctxt.getBlockInWorld(), null)); + } + + bctxt.forEachFace(fctxt -> fctxt.forEachTile(tctxt -> { + TileLogic tile = tctxt.getTile(); + + if (!(tile instanceof TickableTile)) + return; + + if (((TickableTile) tile).getTickingPolicy(tctxt) == TickingPolicy.REGULAR) { + tickingTiles.add(tctxt.getReference()); + } + })); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java index b8816a0..5eed263 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ChunkTickContext.java @@ -1,31 +1,49 @@ -package ru.windcorp.progressia.server.world; - -import java.util.function.Consumer; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.server.world.block.BlockTickContext; - -public interface ChunkTickContext extends TickContext { - - Vec3i getChunk(); - - default ChunkLogic getChunkLogic() { - return getWorld().getChunk(getChunk()); - } - - default ChunkData getChunkData() { - ChunkLogic chunkLogic = getChunkLogic(); - return chunkLogic == null ? null : chunkLogic.getData(); - } - - default void forEachBlock(Consumer action) { - TickContextMutable context = TickContextMutable.uninitialized(); - - getChunkData().forEachBlock(blockInChunk -> { - context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); - action.accept(context); - }); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.function.Consumer; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.server.world.block.BlockTickContext; + +public interface ChunkTickContext extends TickContext { + + Vec3i getChunk(); + + default ChunkLogic getChunkLogic() { + return getWorld().getChunk(getChunk()); + } + + default ChunkData getChunkData() { + ChunkLogic chunkLogic = getChunkLogic(); + return chunkLogic == null ? null : chunkLogic.getData(); + } + + default void forEachBlock(Consumer action) { + TickContextMutable context = TickContextMutable.uninitialized(); + + getChunkData().forEachBlock(blockInChunk -> { + context.rebuild().withServer(getServer()).withChunk(getChunk()).withBlockInChunk(blockInChunk).build(); + action.accept(context); + }); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java index a64419f..22d106e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickAndUpdateUtil.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; @@ -17,7 +35,7 @@ import ru.windcorp.progressia.server.world.tile.TileTickContext; import ru.windcorp.progressia.server.world.tile.UpdateableTile; public class TickAndUpdateUtil { - + public static void tickBlock(TickableBlock block, BlockTickContext context) { try { block.tick(context); @@ -25,15 +43,16 @@ public class TickAndUpdateUtil { throw CrashReports.report(e, "Could not tick block %s", block); } } - + public static void tickBlock(WorldLogic world, Vec3i blockInWorld) { BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof TickableBlock)) return; // also checks nulls - + if (!(block instanceof TickableBlock)) + return; // also checks nulls + BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); tickBlock((TickableBlock) block, tickContext); } - + public static void tickTile(TickableTile tile, TileTickContext context) { try { tile.tick(context); @@ -41,24 +60,27 @@ public class TickAndUpdateUtil { throw CrashReports.report(e, "Could not tick tile %s", tile); } } - + public static void tickTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof TickableTile)) return; - - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).withLayer(layer); + if (!(tile instanceof TickableTile)) + return; + + TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) + .withLayer(layer); tickTile((TickableTile) tile, tickContext); } - + public static void tickTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build().forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof TickableTile) { - tickTile((TickableTile) tile, context); - } - }); + TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() + .forEachTile(context -> { + TileLogic tile = context.getTile(); + if (tile instanceof TickableTile) { + tickTile((TickableTile) tile, context); + } + }); } - + public static void updateBlock(UpdateableBlock block, BlockTickContext context) { try { block.update(context); @@ -66,15 +88,16 @@ public class TickAndUpdateUtil { throw CrashReports.report(e, "Could not update block {}", block); } } - + public static void updateBlock(WorldLogic world, Vec3i blockInWorld) { BlockLogic block = world.getBlock(blockInWorld); - if (!(block instanceof UpdateableBlock)) return; // also checks nulls - + if (!(block instanceof UpdateableBlock)) + return; // also checks nulls + BlockTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).build(); updateBlock((UpdateableBlock) block, tickContext); } - + public static void updateTile(UpdateableTile tile, TileTickContext context) { try { tile.update(context); @@ -82,24 +105,27 @@ public class TickAndUpdateUtil { throw CrashReports.report(e, "Could not update tile {}", tile); } } - + public static void updateTile(WorldLogic world, Vec3i blockInWorld, BlockFace face, int layer) { TileLogic tile = world.getTile(blockInWorld, face, layer); - if (!(tile instanceof UpdateableTile)) return; + if (!(tile instanceof UpdateableTile)) + return; - TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).withLayer(layer); + TileTickContext tickContext = TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face) + .withLayer(layer); updateTile((UpdateableTile) tile, tickContext); } - + public static void updateTiles(WorldLogic world, Vec3i blockInWorld, BlockFace face) { - TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build().forEachTile(context -> { - TileLogic tile = context.getTile(); - if (tile instanceof UpdateableTile) { - updateTile((UpdateableTile) tile, context); - } - }); + TickContextMutable.start().withWorld(world).withBlock(blockInWorld).withFace(face).build() + .forEachTile(context -> { + TileLogic tile = context.getTile(); + if (tile instanceof UpdateableTile) { + updateTile((UpdateableTile) tile, context); + } + }); } - + public static void tickEntity(EntityLogic logic, EntityData data, TickContext context) { try { logic.tick(data, context); @@ -107,11 +133,16 @@ public class TickAndUpdateUtil { throw CrashReports.report(e, "Could not tick entity {}", logic); } } - + public static void tickEntity(EntityData data, Server server) { - tickEntity(EntityLogicRegistry.getInstance().get(data.getId()), data, TickContextMutable.start().withServer(server).build()); + tickEntity( + EntityLogicRegistry.getInstance().get(data.getId()), + data, + TickContextMutable.start().withServer(server).build() + ); + } + + private TickAndUpdateUtil() { } - - private TickAndUpdateUtil() {} } diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java b/src/main/java/ru/windcorp/progressia/server/world/TickContext.java index 58b6880..50dda55 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContext.java @@ -1,31 +1,49 @@ -package ru.windcorp.progressia.server.world; - -import java.util.Random; - -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.tasks.WorldAccessor; - -public interface TickContext { - - float getTickLength(); - - Server getServer(); - - default WorldLogic getWorld() { - return getServer().getWorld(); - } - - default WorldAccessor getAccessor() { - return getServer().getWorldAccessor(); - } - - default Random getRandom() { - return getServer().getAdHocRandom(); - } - - default WorldData getWorldData() { - return getWorld().getData(); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.Random; + +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.tasks.WorldAccessor; + +public interface TickContext { + + float getTickLength(); + + Server getServer(); + + default WorldLogic getWorld() { + return getServer().getWorld(); + } + + default WorldAccessor getAccessor() { + return getServer().getWorldAccessor(); + } + + default Random getRandom() { + return getServer().getAdHocRandom(); + } + + default WorldData getWorldData() { + return getWorld().getData(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java index f5ce2db..68185d9 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java +++ b/src/main/java/ru/windcorp/progressia/server/world/TickContextMutable.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world; import java.util.Objects; @@ -17,127 +35,130 @@ import ru.windcorp.progressia.server.world.tile.TSTickContext; import ru.windcorp.progressia.server.world.tile.TileTickContext; public abstract class TickContextMutable implements BlockTickContext, TSTickContext, TileTickContext { - + private static enum Role { NONE, WORLD, CHUNK, BLOCK, TILE_STACK, TILE; } - + /* * TickContextMutable interface */ - + // Only TickContextMutable.Impl can extend; extend Impl if need be - private TickContextMutable() {} - + private TickContextMutable() { + } + public abstract Builder.Empty rebuild(); - + /* * Static methods */ - + public static TickContextMutable uninitialized() { return new Impl(); } - + public static Builder.Empty start() { return uninitialized().rebuild(); } - + public static Builder.World copyWorld(TickContext context) { return start().withServer(context.getServer()); } - + public static Builder.Chunk copyChunk(ChunkTickContext context) { return start().withChunk(context.getChunkLogic()); } - + public static Builder.Block copyBlock(BlockTickContext context) { return copyWorld(context).withBlock(context.getBlockInWorld()); } - + public static Builder.TileStack copyTS(TSTickContext context) { return copyBlock(context).withFace(context.getFace()); } - + public static TileTickContext copyTile(TileTickContext context) { return copyTS(context).withLayer(context.getLayer()); } - + /* * Builder interfaces */ - + public static interface Builder { TickContextMutable build(); - - public static interface Empty /*does not extend Builder*/ { + + public static interface Empty /* does not extend Builder */ { World withServer(Server server); - + default Builder.World withWorld(WorldLogic world) { Objects.requireNonNull(world, "world"); return withServer(world.getServer()); } - + default Builder.Chunk withChunk(ChunkLogic chunk) { Objects.requireNonNull(chunk, "chunk"); return withWorld(chunk.getWorld()).withChunk(chunk.getPosition()); } } - + public static interface World extends Builder { Chunk withChunk(Vec3i chunk); + Block withBlock(Vec3i blockInWorld); + TileStack withTS(GenericTileStack tileStack); - + default Builder.Chunk withChunk(ChunkData chunk) { Objects.requireNonNull(chunk, "chunk"); return withChunk(chunk.getPosition()); } - + default TileTickContext withTile(TileReference ref) { Objects.requireNonNull(ref, "ref"); return withTS(ref.getStack()).withLayer(ref.getIndex()); } } - + public static interface Chunk extends Builder { Builder.Block withBlockInChunk(Vec3i blockInChunk); } - + public static interface Block extends Builder { Builder.TileStack withFace(BlockFace face); } - + public static interface TileStack extends Builder { TickContextMutable withLayer(int layer); } } - + /* * Impl */ - + public static class Impl - extends TickContextMutable - implements Builder.Empty, Builder.World, Builder.Chunk, Builder.Block, Builder.TileStack - { - - protected Impl() {} + extends TickContextMutable + implements Builder.Empty, Builder.World, Builder.Chunk, Builder.Block, Builder.TileStack { + + protected Impl() { + } protected Server server; protected final Vec3i chunk = new Vec3i(); protected final Vec3i blockInWorld = new Vec3i(); protected BlockFace face; protected int layer; - + protected Role role = Role.NONE; protected boolean isBeingBuilt = false; - + /** * Updated lazily */ protected final Vec3i blockInChunk = new Vec3i(); - + /* * TickContextMutable */ @@ -153,7 +174,7 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont checkContextState(Role.WORLD); return (float) this.server.getTickLength(); } - + @Override public Vec3i getChunk() { checkContextState(Role.CHUNK); @@ -177,33 +198,33 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont checkContextState(Role.TILE); return this.layer; } - + @Override public Builder.Empty rebuild() { this.role = Role.NONE; this.isBeingBuilt = true; - + this.server = null; this.chunk.set(0); this.blockInWorld.set(0); this.face = null; this.layer = -1; - + return this; } - + /* * Builder - * memo: do NOT use Context getters, they throw ISEs + * memo: do NOT use Context getters, they throw ISEs */ - + @Override public TickContextMutable build() { checkBuilderState(null); this.isBeingBuilt = false; return this; } - + @Override public World withServer(Server server) { Objects.requireNonNull(server, "server"); @@ -212,97 +233,97 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont this.role = Role.WORLD; return this; } - + @Override public Chunk withChunk(Vec3i chunk) { Objects.requireNonNull(chunk, "chunk"); checkBuilderState(Role.WORLD); - + this.chunk.set(chunk.x, chunk.y, chunk.z); - + this.role = Role.CHUNK; return this; } - + @Override public Block withBlock(Vec3i blockInWorld) { Objects.requireNonNull(blockInWorld, "blockInWorld"); checkBuilderState(Role.WORLD); - + this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); Coordinates.convertInWorldToChunk(blockInWorld, this.chunk); - + this.role = Role.BLOCK; return this; } - + @Override public TileStack withTS(GenericTileStack tileStack) { Objects.requireNonNull(tileStack, "tileStack"); - + return withBlock(tileStack.getBlockInWorld(this.blockInWorld)).withFace(tileStack.getFace()); - // ^^^^^^^^^^^^^^^^^ This is safe + // ^^^^^^^^^^^^^^^^^ This is safe } - + @Override public Block withBlockInChunk(Vec3i blockInChunk) { Objects.requireNonNull(blockInChunk, "blockInChunk"); checkBuilderState(Role.CHUNK); - + Coordinates.getInWorld(this.chunk, blockInChunk, this.blockInWorld); - + this.role = Role.BLOCK; return this; } - + @Override public TileStack withFace(BlockFace face) { Objects.requireNonNull(face, "face"); checkBuilderState(Role.BLOCK); - + this.face = face; - + this.role = Role.TILE_STACK; return this; } - + @Override public TickContextMutable withLayer(int layer) { checkBuilderState(Role.TILE); - + this.layer = layer; - + this.role = Role.TILE; return build(); } - + /* * Optimization */ - + @Override public Vec3i getBlockInChunk() { return Coordinates.convertInWorldToInChunk(getBlockInWorld(), this.blockInChunk); } - + @Override public void forEachBlock(Consumer action) { checkContextState(Role.CHUNK); - + Vec3i v = this.blockInWorld; - + int previousX = v.x; int previousY = v.y; int previousZ = v.z; Role previousRole = this.role; - + this.role = Role.BLOCK; - + final int minX = Coordinates.getInWorld(chunk.x, 0); final int minY = Coordinates.getInWorld(chunk.y, 0); final int minZ = Coordinates.getInWorld(chunk.z, 0); final int size = ChunkData.BLOCKS_PER_CHUNK; - + for (v.x = minX; v.x < minX + size; ++v.x) { for (v.y = minY; v.y < minY + size; ++v.y) { for (v.z = minZ; v.z < minZ + size; ++v.z) { @@ -310,76 +331,77 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont } } } - + this.role = previousRole; blockInWorld.set(previousX, previousY, previousZ); } - + @Override public void forEachFace(Consumer action) { checkContextState(Role.BLOCK); BlockFace previousFace = this.face; Role previousRole = this.role; - + this.role = Role.TILE_STACK; for (int i = 0; i < BlockFace.BLOCK_FACE_COUNT; ++i) { this.face = BlockFace.getFaces().get(i); action.accept(this); } - + this.role = previousRole; this.face = previousFace; } - + @Override public R evalNeighbor(Vec3i direction, Function action) { this.blockInWorld.add(direction); R result = action.apply(this); this.blockInWorld.sub(direction); - + return result; } - + @Override public void forNeighbor(Vec3i direction, Consumer action) { this.blockInWorld.add(direction); action.accept(this); this.blockInWorld.sub(direction); } - + @Override public boolean forEachTile(Consumer action) { checkContextState(Role.TILE_STACK); int previousLayer = this.layer; Role previousRole = this.role; - + this.role = Role.TILE; TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) return false; - + if (stack == null || stack.isEmpty()) + return false; + for (this.layer = 0; this.layer < stack.size(); ++this.layer) { action.accept(this); } - + this.role = previousRole; this.layer = previousLayer; return true; } - + @Override public R evalComplementary(Function action) { Objects.requireNonNull(action, "action"); checkContextState(Role.TILE_STACK); - + this.blockInWorld.add(this.face.getVector()); this.face = this.face.getCounter(); R result = action.apply(this); this.face = this.face.getCounter(); this.blockInWorld.sub(this.face.getVector()); - + return result; } - + @Override public void forComplementary(Consumer action) { Objects.requireNonNull(action, "action"); @@ -391,41 +413,45 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont this.face = this.face.getCounter(); this.blockInWorld.sub(this.face.getVector()); } - + /* * Misc */ - + protected void checkContextState(Role requiredRole) { if (isBeingBuilt) { throw new IllegalStateException("This context is still being built"); } - + if ((role == null) || (requiredRole.compareTo(role) > 0)) { - throw new IllegalStateException("This context is currently initialized as " + role + "; requested " + requiredRole); + throw new IllegalStateException( + "This context is currently initialized as " + role + "; requested " + requiredRole + ); } } - + protected void checkBuilderState(Role requiredRole) { if (!isBeingBuilt) { throw new IllegalStateException("This context is already built"); } - + if (requiredRole == null) { if (role == Role.NONE) { throw new IllegalStateException("This context is currently not initialized"); } } else { if (role != requiredRole) { - throw new IllegalStateException("This context is currently initialized as " + role + "; requested " + requiredRole); + throw new IllegalStateException( + "This context is currently initialized as " + role + "; requested " + requiredRole + ); } } } - + @Override public String toString() { final String format; - + switch (this.role) { case WORLD: format = "TickContext"; @@ -447,17 +473,17 @@ public abstract class TickContextMutable implements BlockTickContext, TSTickCont format = "Uninitialized TickContextMutable"; break; } - + return String.format( - format, - this.chunk.x, - this.chunk.y, - this.chunk.z, - this.blockInWorld.x, - this.blockInWorld.y, - this.blockInWorld.z, - this.face, - this.layer + format, + this.chunk.x, + this.chunk.y, + this.chunk.z, + this.blockInWorld.x, + this.blockInWorld.y, + this.blockInWorld.z, + this.face, + this.layer ); } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java index ffc54f7..511170e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java +++ b/src/main/java/ru/windcorp/progressia/server/world/UpdateTriggerer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world; import glm.vec._3.i.Vec3i; @@ -19,15 +37,21 @@ public class UpdateTriggerer implements ChunkDataListener { @Override public void onChunkBlockChanged( - ChunkData chunk, Vec3i blockInChunk, BlockData previous, BlockData current + ChunkData chunk, + Vec3i blockInChunk, + BlockData previous, + BlockData current ) { server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null)); } - + @Override public void onChunkTilesChanged( - ChunkData chunk, Vec3i blockInChunk, BlockFace face, TileData tile, - boolean wasAdded + ChunkData chunk, + Vec3i blockInChunk, + BlockFace face, + TileData tile, + boolean wasAdded ) { server.getWorldAccessor().triggerUpdates(Coordinates.getInWorld(chunk.getPosition(), blockInChunk, null), face); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java index 2c8cc48..93a1028 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/WorldLogic.java @@ -1,100 +1,119 @@ -package ru.windcorp.progressia.server.world; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.ChunkData; -import ru.windcorp.progressia.common.world.ChunkDataListeners; -import ru.windcorp.progressia.common.world.WorldData; -import ru.windcorp.progressia.common.world.WorldDataListener; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.common.world.generic.GenericWorld; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.world.block.BlockLogic; -import ru.windcorp.progressia.server.world.generation.WorldGenerator; -import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; -import ru.windcorp.progressia.server.world.ticking.Evaluation; -import ru.windcorp.progressia.server.world.tile.TileLogic; -import ru.windcorp.progressia.server.world.tile.TileLogicStack; - -public class WorldLogic -implements GenericWorld< - BlockLogic, - TileLogic, - TileLogicStack, - ChunkLogic, - EntityData // not using EntityLogic because it is stateless -> { - - private final WorldData data; - private final Server server; - - private final WorldGenerator generator; - - private final Map chunks = new HashMap<>(); - - private final Evaluation tickEntitiesTask = new TickEntitiesTask(); - - public WorldLogic(WorldData data, Server server, Function worldGeneratorConstructor) { - this.data = data; - this.server = server; - this.generator = worldGeneratorConstructor.apply(this); - - data.addListener(new WorldDataListener() { - @Override - public void onChunkLoaded(WorldData world, ChunkData chunk) { - chunks.put(chunk, new ChunkLogic(WorldLogic.this, chunk)); - } - - @Override - public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { - chunks.remove(chunk); - } - }); - - data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); - } - - @Override - public ChunkLogic getChunk(Vec3i pos) { - return chunks.get(getData().getChunk(pos)); - } - - @Override - public Collection getChunks() { - return chunks.values(); - } - - @Override - public Collection getEntities() { - return getData().getEntities(); - } - - public Evaluation getTickEntitiesTask() { - return tickEntitiesTask; - } - - public Server getServer() { - return server; - } - - public WorldData getData() { - return data; - } - - public WorldGenerator getGenerator() { - return generator; - } - - public ChunkData generate(Vec3i chunkPos) { - return getGenerator().generate(chunkPos, getData()); - } - - public ChunkLogic getChunk(ChunkData chunkData) { - return chunks.get(chunkData); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.ChunkData; +import ru.windcorp.progressia.common.world.ChunkDataListeners; +import ru.windcorp.progressia.common.world.WorldData; +import ru.windcorp.progressia.common.world.WorldDataListener; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.GenericWorld; +import ru.windcorp.progressia.server.Server; +import ru.windcorp.progressia.server.world.block.BlockLogic; +import ru.windcorp.progressia.server.world.generation.WorldGenerator; +import ru.windcorp.progressia.server.world.tasks.TickEntitiesTask; +import ru.windcorp.progressia.server.world.ticking.Evaluation; +import ru.windcorp.progressia.server.world.tile.TileLogic; +import ru.windcorp.progressia.server.world.tile.TileLogicStack; + +public class WorldLogic + implements GenericWorld { + + private final WorldData data; + private final Server server; + + private final WorldGenerator generator; + + private final Map chunks = new HashMap<>(); + + private final Evaluation tickEntitiesTask = new TickEntitiesTask(); + + public WorldLogic(WorldData data, Server server, Function worldGeneratorConstructor) { + this.data = data; + this.server = server; + this.generator = worldGeneratorConstructor.apply(this); + + data.addListener(new WorldDataListener() { + @Override + public void onChunkLoaded(WorldData world, ChunkData chunk) { + chunks.put(chunk, new ChunkLogic(WorldLogic.this, chunk)); + } + + @Override + public void beforeChunkUnloaded(WorldData world, ChunkData chunk) { + chunks.remove(chunk); + } + }); + + data.addListener(ChunkDataListeners.createAdder(new UpdateTriggerer(server))); + } + + @Override + public ChunkLogic getChunk(Vec3i pos) { + return chunks.get(getData().getChunk(pos)); + } + + @Override + public Collection getChunks() { + return chunks.values(); + } + + @Override + public Collection getEntities() { + return getData().getEntities(); + } + + public Evaluation getTickEntitiesTask() { + return tickEntitiesTask; + } + + public Server getServer() { + return server; + } + + public WorldData getData() { + return data; + } + + public WorldGenerator getGenerator() { + return generator; + } + + public ChunkData generate(Vec3i chunkPos) { + return getGenerator().generate(chunkPos, getData()); + } + + public ChunkLogic getChunk(ChunkData chunkData) { + return chunks.get(chunkData); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java index cb8fa6d..794259f 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogic.java @@ -1,29 +1,47 @@ -package ru.windcorp.progressia.server.world.block; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericBlock; - -public class BlockLogic extends Namespaced implements GenericBlock { - - public BlockLogic(String id) { - super(id); - } - - public boolean isSolid(BlockTickContext context, BlockFace face) { - return isSolid(face); - } - - public boolean isSolid(BlockFace face) { - return true; - } - - public boolean isTransparent(BlockTickContext context) { - return isTransparent(); - } - - public boolean isTransparent() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.block; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericBlock; + +public class BlockLogic extends Namespaced implements GenericBlock { + + public BlockLogic(String id) { + super(id); + } + + public boolean isSolid(BlockTickContext context, BlockFace face) { + return isSolid(face); + } + + public boolean isSolid(BlockFace face) { + return true; + } + + public boolean isTransparent(BlockTickContext context) { + return isTransparent(); + } + + public boolean isTransparent() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java index 5cdb1f0..df18ff7 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockLogicRegistry.java @@ -1,13 +1,31 @@ -package ru.windcorp.progressia.server.world.block; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class BlockLogicRegistry extends NamespacedInstanceRegistry { - - private static final BlockLogicRegistry INSTANCE = new BlockLogicRegistry(); - - public static BlockLogicRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.block; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class BlockLogicRegistry extends NamespacedInstanceRegistry { + + private static final BlockLogicRegistry INSTANCE = new BlockLogicRegistry(); + + public static BlockLogicRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java index 6ee1138..a305b9a 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/BlockTickContext.java @@ -1,95 +1,114 @@ -package ru.windcorp.progressia.server.world.block; - -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; - -import glm.vec._3.i.Vec3i; -import ru.windcorp.progressia.common.world.Coordinates; -import ru.windcorp.progressia.common.world.block.BlockData; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.block.BlockRelation; -import ru.windcorp.progressia.server.world.ChunkTickContext; -import ru.windcorp.progressia.server.world.TickContextMutable; -import ru.windcorp.progressia.server.world.tile.TSTickContext; - -public interface BlockTickContext extends ChunkTickContext { - - /** - * Returns the current world coordinates. - * @return the world coordinates of the block being ticked - */ - Vec3i getBlockInWorld(); - - default Vec3i getBlockInChunk() { - return Coordinates.convertInWorldToInChunk(getBlockInWorld(), null); - } - - default BlockLogic getBlock() { - return getWorld().getBlock(getBlockInWorld()); - } - - default BlockData getBlockData() { - return getWorldData().getBlock(getBlockInWorld()); - } - - default void forEachFace(Consumer action) { - Objects.requireNonNull(action, "action"); - TickContextMutable context = TickContextMutable.uninitialized(); - - for (BlockFace face : BlockFace.getFaces()) { - context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build(); - action.accept(context); - } - } - - default BlockTickContext getNeighbor(Vec3i direction) { - Objects.requireNonNull(direction, "direction"); - return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); - } - - default BlockTickContext getNeighbor(BlockRelation relation) { - Objects.requireNonNull(relation, "relation"); - return getNeighbor(relation.getVector()); - } - - default R evalNeighbor(Vec3i direction, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - return action.apply(getNeighbor(direction)); - } - - default R evalNeighbor(BlockRelation relation, Function action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - return evalNeighbor(relation.getVector(), action); - } - - default void forNeighbor(Vec3i direction, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(direction, "direction"); - evalNeighbor(direction, (Function) ctxt -> { - action.accept(ctxt); - return null; - }); - } - - default void forNeighbor(BlockRelation relation, Consumer action) { - Objects.requireNonNull(action, "action"); - Objects.requireNonNull(relation, "relation"); - forNeighbor(relation.getVector(), action); - } - - /* - * Convenience methods - changes - */ - - default void setThisBlock(BlockData block) { - getAccessor().setBlock(getBlockInWorld(), block); - } - - default void setThisBlock(String id) { - getAccessor().setBlock(getBlockInWorld(), id); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.block; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.Coordinates; +import ru.windcorp.progressia.common.world.block.BlockData; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.block.BlockRelation; +import ru.windcorp.progressia.server.world.ChunkTickContext; +import ru.windcorp.progressia.server.world.TickContextMutable; +import ru.windcorp.progressia.server.world.tile.TSTickContext; + +public interface BlockTickContext extends ChunkTickContext { + + /** + * Returns the current world coordinates. + * + * @return the world coordinates of the block being ticked + */ + Vec3i getBlockInWorld(); + + default Vec3i getBlockInChunk() { + return Coordinates.convertInWorldToInChunk(getBlockInWorld(), null); + } + + default BlockLogic getBlock() { + return getWorld().getBlock(getBlockInWorld()); + } + + default BlockData getBlockData() { + return getWorldData().getBlock(getBlockInWorld()); + } + + default void forEachFace(Consumer action) { + Objects.requireNonNull(action, "action"); + TickContextMutable context = TickContextMutable.uninitialized(); + + for (BlockFace face : BlockFace.getFaces()) { + context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(face).build(); + action.accept(context); + } + } + + default BlockTickContext getNeighbor(Vec3i direction) { + Objects.requireNonNull(direction, "direction"); + return TickContextMutable.copyWorld(this).withBlock(getBlockInWorld().add_(direction)).build(); + } + + default BlockTickContext getNeighbor(BlockRelation relation) { + Objects.requireNonNull(relation, "relation"); + return getNeighbor(relation.getVector()); + } + + default R evalNeighbor(Vec3i direction, Function action) { + Objects.requireNonNull(action, "action"); + Objects.requireNonNull(direction, "direction"); + return action.apply(getNeighbor(direction)); + } + + default R evalNeighbor(BlockRelation relation, Function action) { + Objects.requireNonNull(action, "action"); + Objects.requireNonNull(relation, "relation"); + return evalNeighbor(relation.getVector(), action); + } + + default void forNeighbor(Vec3i direction, Consumer action) { + Objects.requireNonNull(action, "action"); + Objects.requireNonNull(direction, "direction"); + evalNeighbor(direction, (Function) ctxt -> { + action.accept(ctxt); + return null; + }); + } + + default void forNeighbor(BlockRelation relation, Consumer action) { + Objects.requireNonNull(action, "action"); + Objects.requireNonNull(relation, "relation"); + forNeighbor(relation.getVector(), action); + } + + /* + * Convenience methods - changes + */ + + default void setThisBlock(BlockData block) { + getAccessor().setBlock(getBlockInWorld(), block); + } + + default void setThisBlock(String id) { + getAccessor().setBlock(getBlockInWorld(), id); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java index fb804b0..56ba938 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/TickableBlock.java @@ -1,11 +1,29 @@ -package ru.windcorp.progressia.server.world.block; - -import ru.windcorp.progressia.server.world.ticking.TickingPolicy; - -public interface TickableBlock { - - void tick(BlockTickContext context); - - TickingPolicy getTickingPolicy(BlockTickContext context); - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.block; + +import ru.windcorp.progressia.server.world.ticking.TickingPolicy; + +public interface TickableBlock { + + void tick(BlockTickContext context); + + TickingPolicy getTickingPolicy(BlockTickContext context); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java index c500515..1497c92 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/block/UpdateableBlock.java @@ -1,11 +1,35 @@ -package ru.windcorp.progressia.server.world.block; - -import org.apache.logging.log4j.LogManager; - -public interface UpdateableBlock { - - default void update(BlockTickContext context) { - LogManager.getLogger().info("Updating block {} @ ({}; {}; {})", context.getBlock(), context.getBlockInWorld().x, context.getBlockInWorld().y, context.getBlockInWorld().z); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.block; + +import org.apache.logging.log4j.LogManager; + +public interface UpdateableBlock { + + default void update(BlockTickContext context) { + LogManager.getLogger().info( + "Updating block {} @ ({}; {}; {})", + context.getBlock(), + context.getBlockInWorld().x, + context.getBlockInWorld().y, + context.getBlockInWorld().z + ); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java index 3dc67f7..7725612 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogic.java @@ -1,17 +1,35 @@ -package ru.windcorp.progressia.server.world.entity; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.entity.EntityData; -import ru.windcorp.progressia.server.world.TickContext; - -public class EntityLogic extends Namespaced { - - public EntityLogic(String id) { - super(id); - } - - public void tick(EntityData entity, TickContext context) { - entity.incrementAge(context.getTickLength()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.entity; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.server.world.TickContext; + +public class EntityLogic extends Namespaced { + + public EntityLogic(String id) { + super(id); + } + + public void tick(EntityData entity, TickContext context) { + entity.incrementAge(context.getTickLength()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java index 012ee09..d8b05d4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/entity/EntityLogicRegistry.java @@ -1,14 +1,31 @@ -package ru.windcorp.progressia.server.world.entity; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class EntityLogicRegistry extends NamespacedInstanceRegistry { - - private static final EntityLogicRegistry INSTANCE = - new EntityLogicRegistry(); - - public static EntityLogicRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.entity; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class EntityLogicRegistry extends NamespacedInstanceRegistry { + + private static final EntityLogicRegistry INSTANCE = new EntityLogicRegistry(); + + public static EntityLogicRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java index 1cae29d..ffb5c06 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/AbstractWorldGenerator.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.generation; import java.io.DataInputStream; @@ -9,38 +27,39 @@ import ru.windcorp.progressia.common.world.ChunkData; import ru.windcorp.progressia.common.world.DecodingException; public abstract class AbstractWorldGenerator extends WorldGenerator { - + private final Class hintClass; public AbstractWorldGenerator(String id, Class hintClass) { super(id); this.hintClass = Objects.requireNonNull(hintClass, "hintClass"); } - + @Override public final Object readGenerationHint(DataInputStream input) throws IOException, DecodingException { return doReadGenerationHint(input); } - + @Override public final void writeGenerationHint(DataOutputStream output, Object hint) throws IOException { doWriteGenerationHint(output, hintClass.cast(hint)); } - + protected abstract H doReadGenerationHint(DataInputStream input) throws IOException, DecodingException; + protected abstract void doWriteGenerationHint(DataOutputStream output, H hint) throws IOException; - + @Override public final boolean isChunkReady(Object hint) { return checkIsChunkReady(hintClass.cast(hint)); } - + protected abstract boolean checkIsChunkReady(H hint); - + protected H getHint(ChunkData chunk) { return hintClass.cast(chunk.getGenerationHint()); } - + protected void setHint(ChunkData chunk, H hint) { chunk.setGenerationHint(hint); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java index 25b48df..afed281 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/WorldGenerator.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.generation; import java.io.DataInputStream; @@ -11,15 +29,18 @@ import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.WorldData; public abstract class WorldGenerator extends Namespaced { - + WorldGenerator(String id) { super(id); // package-private constructor; extend AbstractWorldGeneration } - + public abstract ChunkData generate(Vec3i chunkPos, WorldData world); + public abstract Object readGenerationHint(DataInputStream input) throws IOException, DecodingException; + public abstract void writeGenerationHint(DataOutputStream output, Object hint) throws IOException; + public abstract boolean isChunkReady(Object hint); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java index 358acdd..6e9ea47 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/AddTile.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -10,4 +28,4 @@ class AddTile extends CachedTileChange { super(disposer, new PacketAddTile()); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java index e56e233..331a5c4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/BlockTriggeredUpdate.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -10,7 +28,7 @@ import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; class BlockTriggeredUpdate extends CachedEvaluation { - + private final Vec3i blockInWorld = new Vec3i(); public BlockTriggeredUpdate(Consumer disposer) { @@ -20,9 +38,9 @@ class BlockTriggeredUpdate extends CachedEvaluation { @Override public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - + WorldLogic world = server.getWorld(); - + for (BlockFace face : BlockFace.getFaces()) { TickAndUpdateUtil.updateTiles(world, cursor, face); cursor.add(face.getVector()); @@ -31,7 +49,7 @@ class BlockTriggeredUpdate extends CachedEvaluation { cursor.sub(face.getVector()); } } - + public void init(Vec3i blockInWorld) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java index 589fa15..b005285 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedBlockChange.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -11,12 +29,12 @@ public class CachedBlockChange

extends CachedChunkC public CachedBlockChange(Consumer disposer, P packet) { super(disposer, packet); } - + @Override public int hashCode() { PacketAffectBlock packet = getPacket(); Vec3i biw = packet.getBlockInWorld(); - + final int prime = 31; int result = 1; result = prime * result + biw.x; @@ -24,21 +42,22 @@ public class CachedBlockChange

extends CachedChunkC result = prime * result + biw.z; return result; } - + @Override public boolean equals(Object obj) { - if (obj == null || getClass() != obj.getClass()) return false; - + if (obj == null || getClass() != obj.getClass()) + return false; + PacketAffectBlock my = getPacket(); PacketAffectBlock other = ((CachedBlockChange) obj).getPacket(); - + return Glm.equals(my.getBlockInWorld(), other.getBlockInWorld()); } - + @Override public String toString() { Vec3i biw = getPacket().getBlockInWorld(); - + return getClass().getSimpleName() + " (" + biw.x + "; " + biw.y + "; " + biw.z + ")"; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java index 081ce8e..e1eb5ca 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChange.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -5,9 +23,9 @@ import java.util.function.Consumer; import ru.windcorp.progressia.server.world.ticking.Change; public abstract class CachedChange extends Change { - + private final Consumer disposer; - + public CachedChange(Consumer disposer) { this.disposer = disposer; } @@ -16,5 +34,5 @@ public abstract class CachedChange extends Change { public void dispose() { disposer.accept(this); } - -} \ No newline at end of file + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java index 4f03486..d98c001 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedChunkChange.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -15,7 +33,7 @@ public abstract class CachedChunkChange

extends Cac public void getRelevantChunk(Vec3i output) { getPacket().getAffectedChunk(output); } - + @Override protected Vec3i getAffectedChunk(Vec3i output) { getPacket().getAffectedChunk(output); diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java index d10a203..da865b4 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedEvaluation.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -5,9 +23,9 @@ import java.util.function.Consumer; import ru.windcorp.progressia.server.world.ticking.Evaluation; public abstract class CachedEvaluation extends Evaluation { - + private final Consumer disposer; - + public CachedEvaluation(Consumer disposer) { this.disposer = disposer; } @@ -16,5 +34,5 @@ public abstract class CachedEvaluation extends Evaluation { public void dispose() { disposer.accept(this); } - -} \ No newline at end of file + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java index ee76f86..1b6cde2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedTileChange.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.Objects; @@ -12,12 +30,12 @@ public class CachedTileChange

extends CachedChunkCha public CachedTileChange(Consumer disposer, P packet) { super(disposer, packet); } - + @Override public int hashCode() { PacketAffectTile packet = getPacket(); Vec3i biw = packet.getBlockInWorld(); - + final int prime = 31; int result = 1; result = prime * result + biw.x; @@ -27,28 +45,31 @@ public class CachedTileChange

extends CachedChunkCha result = prime * result + packet.getTag(); return result; } - + @Override public boolean equals(Object obj) { - if (!(obj instanceof CachedTileChange)) return false; - + if (!(obj instanceof CachedTileChange)) + return false; + PacketAffectTile my = getPacket(); PacketAffectTile other = ((CachedTileChange) obj).getPacket(); - + // Tag of -1 signals that we should ignore it - if (my.getTag() == -1 || other.getTag() == -1) return false; - + if (my.getTag() == -1 || other.getTag() == -1) + return false; + return Glm.equals(my.getBlockInWorld(), other.getBlockInWorld()) - && (my.getFace() == other.getFace()) - && (my.getTag() == other.getTag()); + && (my.getFace() == other.getFace()) + && (my.getTag() == other.getTag()); } - + @Override public String toString() { PacketAffectTile packet = getPacket(); Vec3i biw = packet.getBlockInWorld(); - - return getClass().getSimpleName() + " (" + biw.x + "; " + biw.y + "; " + biw.z + "; " + packet.getFace() + "; tag: " + packet.getTag() + ")"; + + return getClass().getSimpleName() + " (" + biw.x + "; " + biw.y + "; " + biw.z + "; " + packet.getFace() + + "; tag: " + packet.getTag() + ")"; } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java index 9230961..711bd5d 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/CachedWorldChange.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -8,7 +26,7 @@ import ru.windcorp.progressia.common.world.PacketAffectWorld; import ru.windcorp.progressia.server.Server; public abstract class CachedWorldChange

extends CachedChange { - + private final P packet; public CachedWorldChange(Consumer disposer, P packet) { @@ -25,24 +43,24 @@ public abstract class CachedWorldChange

extends Cac protected void affectLocal(Server server) { packet.apply(server.getWorld().getData()); } - + protected void sendPacket(Server server) { Vec3i v = Vectors.grab3i(); Vec3i chunkPos = getAffectedChunk(v); - + if (chunkPos == null) { server.getClientManager().broadcastToAllPlayers(packet); } else { server.getClientManager().broadcastLocal(packet, chunkPos); } - + Vectors.release(chunkPos); } protected Vec3i getAffectedChunk(Vec3i output) { return null; } - + public P getPacket() { return packet; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java index 847b9ae..08f1212 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/ChangeEntity.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -21,10 +39,10 @@ class ChangeEntity extends CachedChange { public void set(T entity, StateChange change) { if (this.entity != null) throw new IllegalStateException("Entity is not null. Current: " + this.entity + "; requested: " + entity); - + if (this.change != null) throw new IllegalStateException("Change is not null. Current: " + this.change + "; requested: " + change); - + this.entity = entity; this.change = change; @@ -35,36 +53,37 @@ class ChangeEntity extends CachedChange { public void affect(Server server) { ((StateChange) change).change(entity); packet.set(entity); - + server.getClientManager().broadcastLocal(packet, entity.getEntityId()); } - + @Override public void getRelevantChunk(Vec3i output) { // Do nothing } - + @Override public boolean isThreadSensitive() { return false; } - + @Override public void dispose() { super.dispose(); this.entity = null; this.change = null; } - + @Override public int hashCode() { return System.identityHashCode(entity); } - + @Override public boolean equals(Object obj) { - if (!(obj instanceof ChangeEntity)) return false; + if (!(obj instanceof ChangeEntity)) + return false; return ((ChangeEntity) obj).entity == entity; } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java index 17512b2..42dea30 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/RemoveTile.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -10,4 +28,4 @@ class RemoveTile extends CachedTileChange { super(disposer, new PacketRemoveTile()); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java index 9b9d869..330333b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/SetBlock.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -10,4 +28,4 @@ class SetBlock extends CachedBlockChange { super(disposer, new PacketSetBlock()); } -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java index 826096b..93d5f08 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/StateChange.java @@ -1,6 +1,24 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; @FunctionalInterface public interface StateChange { void change(T object); -} \ No newline at end of file +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java index daa30ae..c0895e1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickChunk.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.ArrayList; @@ -25,27 +43,26 @@ import ru.windcorp.progressia.server.world.tile.TileLogic; import static ru.windcorp.progressia.common.world.ChunkData.BLOCKS_PER_CHUNK; public class TickChunk extends Evaluation { - - private static final int CHUNK_VOLUME = - ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK * - ChunkData.BLOCKS_PER_CHUNK; - + + private static final int CHUNK_VOLUME = ChunkData.BLOCKS_PER_CHUNK * + ChunkData.BLOCKS_PER_CHUNK * + ChunkData.BLOCKS_PER_CHUNK; + private final List> randomTickMethods; - + { List> randomTickMethods = new ArrayList<>(); randomTickMethods.add(this::tickRandomBlock); - + for (BlockFace face : BlockFace.getFaces()) { randomTickMethods.add(s -> this.tickRandomTile(s, face)); } - + this.randomTickMethods = ImmutableList.copyOf(randomTickMethods); } - + private final ChunkLogic chunk; - + public TickChunk(ChunkLogic chunk) { this.chunk = chunk; } @@ -62,10 +79,11 @@ public class TickChunk extends Evaluation { } private void tickRegularBlocks(Server server) { - if (!chunk.hasTickingBlocks()) return; - + if (!chunk.hasTickingBlocks()) + return; + TickContextMutable context = TickContextMutable.uninitialized(); - + chunk.forEachTickingBlock((blockInChunk, block) -> { context.rebuild().withChunk(chunk).withBlockInChunk(blockInChunk).build(); ((TickableBlock) block).tick(context); @@ -73,10 +91,11 @@ public class TickChunk extends Evaluation { } private void tickRegularTiles(Server server) { - if (!chunk.hasTickingTiles()) return; - + if (!chunk.hasTickingTiles()) + return; + TickContextMutable context = TickContextMutable.uninitialized(); - + chunk.forEachTickingTile((ref, tile) -> { context.rebuild().withServer(server).withTile(ref); ((TickableTile) tile).tick(context); @@ -85,7 +104,7 @@ public class TickChunk extends Evaluation { private void tickRandom(Server server) { float ticks = computeRandomTicks(server); - + /* * If we are expected to run 3.25 random ticks per tick * on average, then run 3 random ticks unconditionally @@ -93,74 +112,76 @@ public class TickChunk extends Evaluation { */ float unconditionalTicks = FloatMathUtil.floor(ticks); float extraTickChance = ticks - unconditionalTicks; - + for (int i = 0; i < unconditionalTicks; ++i) { tickRandomOnce(server); } - + if (server.getAdHocRandom().nextFloat() < extraTickChance) { tickRandomOnce(server); } } - + private void tickRandomOnce(Server server) { // Pick a target at random: a block or one of 3 primary block faces randomTickMethods.get( - server.getAdHocRandom().nextInt(randomTickMethods.size()) + server.getAdHocRandom().nextInt(randomTickMethods.size()) ).accept(server); } - + private void tickRandomBlock(Server server) { Random random = server.getAdHocRandom(); - + Vec3i blockInChunk = new Vec3i( - random.nextInt(BLOCKS_PER_CHUNK), - random.nextInt(BLOCKS_PER_CHUNK), - random.nextInt(BLOCKS_PER_CHUNK) + random.nextInt(BLOCKS_PER_CHUNK), + random.nextInt(BLOCKS_PER_CHUNK), + random.nextInt(BLOCKS_PER_CHUNK) ); BlockLogic block = this.chunk.getBlock(blockInChunk); - - if (!(block instanceof TickableBlock)) return; + + if (!(block instanceof TickableBlock)) + return; TickableBlock tickable = (TickableBlock) block; - - TickContextMutable context = - TickContextMutable.start().withChunk(chunk).withBlockInChunk(blockInChunk).build(); - - if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM) return; + + TickContextMutable context = TickContextMutable.start().withChunk(chunk).withBlockInChunk(blockInChunk).build(); + + if (tickable.getTickingPolicy(context) != TickingPolicy.RANDOM) + return; tickable.tick(context); } - + private void tickRandomTile(Server server, BlockFace face) { Random random = server.getAdHocRandom(); - + Vec3i blockInChunk = new Vec3i( - random.nextInt(BLOCKS_PER_CHUNK), - random.nextInt(BLOCKS_PER_CHUNK), - random.nextInt(BLOCKS_PER_CHUNK) + random.nextInt(BLOCKS_PER_CHUNK), + random.nextInt(BLOCKS_PER_CHUNK), + random.nextInt(BLOCKS_PER_CHUNK) ); TileDataStack tiles = this.chunk.getData().getTilesOrNull(blockInChunk, face); - if (tiles == null || tiles.isEmpty()) return; - + if (tiles == null || tiles.isEmpty()) + return; + TSTickContext context = TickContextMutable.start().withServer(server).withTS(tiles).build(); - + context.forEachTile(tctxt -> { TileLogic logic = tctxt.getTile(); - if (!(logic instanceof TickableTile)) return; + if (!(logic instanceof TickableTile)) + return; TickableTile tickable = (TickableTile) logic; - - if (tickable.getTickingPolicy(tctxt) != TickingPolicy.RANDOM) return; + + if (tickable.getTickingPolicy(tctxt) != TickingPolicy.RANDOM) + return; tickable.tick(tctxt); }); } private float computeRandomTicks(Server server) { - return (float) ( - server.getTickingSettings().getRandomTickFrequency() * - CHUNK_VOLUME * randomTickMethods.size() * - server.getTickLength() - ); + return (float) (server.getTickingSettings().getRandomTickFrequency() * + CHUNK_VOLUME * randomTickMethods.size() * + server.getTickLength()); } @Override diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java index da964bd..1e76b23 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TickEntitiesTask.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import glm.vec._3.i.Vec3i; @@ -18,7 +36,7 @@ public class TickEntitiesTask extends Evaluation { public void getRelevantChunk(Vec3i output) { // Do nothing } - + @Override public boolean isThreadSensitive() { return false; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java index bef9a55..76fc414 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/TileTriggeredUpdate.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -10,7 +28,7 @@ import ru.windcorp.progressia.server.world.TickAndUpdateUtil; import ru.windcorp.progressia.server.world.WorldLogic; class TileTriggeredUpdate extends CachedEvaluation { - + private final Vec3i blockInWorld = new Vec3i(); private BlockFace face = null; @@ -21,16 +39,20 @@ class TileTriggeredUpdate extends CachedEvaluation { @Override public void evaluate(Server server) { Vec3i cursor = new Vec3i(blockInWorld.x, blockInWorld.y, blockInWorld.z); - + WorldLogic world = server.getWorld(); - - TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates (also self) - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on one side + + TickAndUpdateUtil.updateTiles(world, cursor, face); // Update facemates + // (also self) + TickAndUpdateUtil.updateBlock(world, cursor); // Update block on one + // side cursor.add(face.getVector()); - TickAndUpdateUtil.updateBlock(world, cursor); // Update block on the other side - TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); // Update complement + TickAndUpdateUtil.updateBlock(world, cursor); // Update block on the + // other side + TickAndUpdateUtil.updateTiles(world, cursor, face.getCounter()); // Update + // complement } - + public void init(Vec3i blockInWorld, BlockFace face) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); this.face = face; diff --git a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java index 85b6fa5..2c83ccd 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tasks/WorldAccessor.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tasks; import java.util.function.Consumer; @@ -14,24 +32,24 @@ import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.world.ticking.TickerTask; public class WorldAccessor { - + private final MultiLOC cache; { MultiLOC mloc = new MultiLOC(); Consumer disposer = mloc::release; - + cache = mloc - .addClass(SetBlock.class, () -> new SetBlock(disposer)) - .addClass(AddTile.class, () -> new AddTile(disposer)) - .addClass(RemoveTile.class, () -> new RemoveTile(disposer)) - .addClass(ChangeEntity.class, () -> new ChangeEntity(disposer)) - - .addClass(BlockTriggeredUpdate.class, () -> new BlockTriggeredUpdate(disposer)) - .addClass(TileTriggeredUpdate.class, () -> new TileTriggeredUpdate(disposer)); + .addClass(SetBlock.class, () -> new SetBlock(disposer)) + .addClass(AddTile.class, () -> new AddTile(disposer)) + .addClass(RemoveTile.class, () -> new RemoveTile(disposer)) + .addClass(ChangeEntity.class, () -> new ChangeEntity(disposer)) + + .addClass(BlockTriggeredUpdate.class, () -> new BlockTriggeredUpdate(disposer)) + .addClass(TileTriggeredUpdate.class, () -> new TileTriggeredUpdate(disposer)); } - + private final Server server; - + public WorldAccessor(Server server) { this.server = server; } @@ -41,7 +59,7 @@ public class WorldAccessor { change.getPacket().set(block, blockInWorld); server.requestChange(change); } - + public void setBlock(Vec3i blockInWorld, String id) { setBlock(blockInWorld, BlockDataRegistry.getInstance().get(id)); } @@ -51,7 +69,7 @@ public class WorldAccessor { change.getPacket().set(tile, blockInWorld, face); server.requestChange(change); } - + public void addTile(Vec3i blockInWorld, BlockFace face, String id) { addTile(blockInWorld, face, TileDataRegistry.getInstance().get(id)); } @@ -63,19 +81,21 @@ public class WorldAccessor { } public void changeEntity( - T entity, StateChange stateChange + T entity, + StateChange stateChange ) { ChangeEntity change = cache.grab(ChangeEntity.class); change.set(entity, stateChange); server.requestChange(change); } - + public void tickBlock(Vec3i blockInWorld) { // TODO } - + /** * When a block is the trigger + * * @param blockInWorld */ // TODO rename to something meaningful @@ -84,9 +104,10 @@ public class WorldAccessor { evaluation.init(blockInWorld); server.requestEvaluation(evaluation); } - + /** * When a tile is the trigger + * * @param blockInWorld * @param face */ diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java index 314aef7..b0fc7f2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Change.java @@ -1,35 +1,59 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.Server; /** - * A {@link TickerTask} that aims to perform a predetermined set of changes on the world. + * A {@link TickerTask} that aims to perform a predetermined set of changes on + * the world. + * * @author javapony */ public abstract class Change extends TickerTask { - + /** * Performs the changes on the provided server instance. *

- * This method will be executed when the world is in an inconsistent state and may not be queried, - * only changed. Therefore, all necessary inspection must be performed before this method is invoked, - * typically by an {@link Evaluation}. Failure to abide by this contract may lead to race conditions + * This method will be executed when the world is in an inconsistent state + * and may not be queried, + * only changed. Therefore, all necessary inspection must be performed + * before this method is invoked, + * typically by an {@link Evaluation}. Failure to abide by this contract may + * lead to race conditions * and/or devil invasions. + * * @param server the {@link Server} instance to affect */ public abstract void affect(Server server); - + @Override void run(Server server) { affect(server); } - + @Override public int hashCode() { // Use instance hash code by default return super.hashCode(); } - + @Override public boolean equals(Object obj) { // Use instance-based equals() by default diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java index 64721af..50ff69c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/DevilInvasionException.java @@ -1,9 +1,27 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; public class DevilInvasionException extends RuntimeException { private static final long serialVersionUID = "devil666satan".hashCode(); - + private DevilInvasionException() { // You don't choose when an invasion occurs. // _They_ do. diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java index a6cee9b..f4f3922 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Evaluation.java @@ -1,9 +1,28 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.Server; /** * A {@link TickerTask} that needs to access the world for analysis. + * * @author javapony */ public abstract class Evaluation extends TickerTask { @@ -17,13 +36,14 @@ public abstract class Evaluation extends TickerTask { * is prohibited. Evaluations are expected to request {@link Change}s * to interact with the world. Failure to abide by this contract may * lead to race conditions and/or devil invasions. + * * @param server the server instance to inspect */ public abstract void evaluate(Server server); - + @Override void run(Server server) { evaluate(server); } - + } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java index 366dead..5c4b83e 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/Ticker.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import java.util.ArrayList; @@ -11,87 +29,88 @@ import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.server.Server; class Ticker { - + private final String name; private final int id; - + private Thread thread = null; private final TickerCoordinator coordinator; - + private volatile boolean shouldRun = true; - + // Expected to implement RandomAccess private final List tasks = new ArrayList<>(TickerCoordinator.INITIAL_QUEUE_SIZE); - + private final Logger logger; - + public Ticker(String name, int id, TickerCoordinator coordinator) { this.name = Objects.requireNonNull(name, "name"); this.id = id; this.coordinator = Objects.requireNonNull(coordinator, "coordinator"); - + this.logger = LogManager.getLogger(this.name); } - + public synchronized void start() { if (thread != null) throw new IllegalStateException("Ticker already started in thread " + thread); - + thread = new Thread(this::run, this.name); logger.debug("Starting"); thread.start(); } - + public String getName() { return name; } - + public int getId() { return id; } - + public Thread getThread() { return thread; } - + public TickerCoordinator getCoordinator() { return coordinator; } - + public synchronized void stop() { if (thread == null) return; - + shouldRun = false; thread.interrupt(); - + logger.debug("Stopping"); } - + public synchronized void requestWork(Collection tasks) { int currentTaskCount = this.tasks.size(); if (currentTaskCount != 0) { throw new IllegalStateException("Ticker already has " + currentTaskCount + " tasks"); } - + this.tasks.addAll(Objects.requireNonNull(tasks, "tasks")); this.notifyAll(); - + logger.debug("Work {} requested", tasks.size()); } - + private void run() { try { logger.debug("Started"); - + while (!Thread.interrupted()) { boolean shouldStop = sleep(); - if (shouldStop) break; + if (shouldStop) + break; work(); } - + logger.debug("Stopped"); - + // Do not release Thread reference so start() still throws ISE } catch (Exception e) { getCoordinator().crash(e, this.name); @@ -100,7 +119,7 @@ class Ticker { private synchronized boolean sleep() { logger.debug("Entering sleep"); - + try { while (true) { @@ -108,8 +127,8 @@ class Ticker { logger.debug("Exiting sleep: received stop request"); return true; } - - int taskCount = tasks.size(); + + int taskCount = tasks.size(); if (taskCount > 0) { logger.debug("Exiting sleep: received {} tasks", taskCount); return false; @@ -117,7 +136,7 @@ class Ticker { logger.debug("Waiting"); this.wait(); - + } } catch (InterruptedException e) { logger.debug("Exiting sleep: interrupted"); @@ -127,32 +146,32 @@ class Ticker { private void work() { logger.debug("Starting work"); - + int tasksCompleted = runTasks(); resetState(); - + logger.debug("Work complete; run {} tasks", tasksCompleted); } private int runTasks() { int tasksCompleted = 0; - + Server srv = getCoordinator().getServer(); - + for (int i = 0; i < tasks.size(); ++i) { TickerTask task = tasks.get(i); - + assert task != null : "Encountered null task"; - + try { task.run(srv); } catch (Exception e) { throw CrashReports.report(e, "Could not run %s task %s", task.getClass().getSimpleName(), task); } - + tasksCompleted++; } - + return tasksCompleted; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java index ebc548f..fa2a2d2 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerCoordinator.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import java.util.ArrayList; @@ -22,58 +40,68 @@ import ru.windcorp.progressia.common.world.ChunkDataListeners; import ru.windcorp.progressia.server.Server; /** - * Central control point for serverside ticking. This class provides an interface to + * Central control point for serverside ticking. This class provides an + * interface to * interact with Tickers. + * * @author javapony */ public class TickerCoordinator { - + static final int INITIAL_QUEUE_SIZE = 1024; - + private final Server server; - + // Synchronized manually private final Collection pendingChanges = new HashSet<>(INITIAL_QUEUE_SIZE); // Synchronized manually private final Collection pendingEvaluations = new ArrayList<>(INITIAL_QUEUE_SIZE); - + /** * A cached ArrayList used to transfer tasks from Coordinator to Tickers. - * This list must be empty when not in {@link #startPassStage(Collection, String)}. + * This list must be empty when not in + * {@link #startPassStage(Collection, String)}. */ private final Collection cachedTransferList = new ArrayList<>(INITIAL_QUEUE_SIZE); - + /** - * All tasks that must be {@linkplain TickerTask#dispose() disposed of} at the end of the current - * tick. This list must be empty when not in {@link #runPassStage(Collection, String)}. + * All tasks that must be {@linkplain TickerTask#dispose() disposed of} at + * the end of the current + * tick. This list must be empty when not in + * {@link #runPassStage(Collection, String)}. */ private final Collection toDispose = new ArrayList<>(INITIAL_QUEUE_SIZE); - + private final Collection tickers; private final Collection threads; - + private final AtomicInteger workingTickers = new AtomicInteger(); - + private final AtomicBoolean canChange = new AtomicBoolean(true); - + private boolean isTickStartSet = false; private long tickStart = -1; private double tickLength = 1.0 / 20; // Do something about it - + private final Logger logger = LogManager.getLogger("Ticker Coordinator"); public TickerCoordinator(Server server, int tickers) { this.server = Objects.requireNonNull(server, "server"); - + Collection tickerCollection = new ArrayList<>(); - + for (int i = 0; i < tickers; ++i) { tickerCollection.add(new Ticker("Ticker " + i, i, this)); } - + this.tickers = ImmutableList.copyOf(tickerCollection); - this.threads = Collections2.transform(this.tickers, Ticker::getThread); // Immutable because it is a view - + this.threads = Collections2.transform(this.tickers, Ticker::getThread); // Immutable + // because + // it + // is + // a + // view + server.getWorld().getData().addListener(ChunkDataListeners.createAdder(new ChunkDataListener() { @Override public void onChunkChanged(ChunkData chunk) { @@ -83,59 +111,59 @@ public class TickerCoordinator { } })); } - + /* * Public API */ - + public synchronized void start() { logger.debug("Starting tickers"); tickers.forEach(Ticker::start); logger.debug("Tickers started"); } - + public synchronized void stop() { logger.debug("Stopping tickers"); tickers.forEach(Ticker::stop); logger.debug("Tickers requested to stop"); } - + public synchronized void requestChange(Change change) { pendingChanges.add(change); } - + public synchronized void requestEvaluation(Evaluation evaluation) { pendingEvaluations.add(evaluation); } - + public Server getServer() { return server; } - + public Collection getThreads() { return this.threads; } - + public double getTickLength() { return tickLength; } - + public double getTPS() { return 1 / tickLength; } - + private void onTickStart() { long now = System.currentTimeMillis(); - + if (isTickStartSet) { tickLength = (now - tickStart) * Units.MILLISECONDS; } else { isTickStartSet = true; } - + tickStart = System.currentTimeMillis(); } - + /* * runOneTick & Friends */ @@ -143,23 +171,23 @@ public class TickerCoordinator { public void runOneTick() { try { onTickStart(); - + int passes = 0; - + logger.debug("Beginning tick"); - + while (hasPending()) { logger.debug("Starting pass"); runOnePass(); logger.debug("Pass complete"); passes++; } - + logger.debug("Tick complete; run {} passes", passes); - + } catch (InterruptedException e) { // Exit silently - + // ...or almost silently logger.debug("Tick interrupted. WTF?"); } catch (Exception e) { @@ -171,7 +199,7 @@ public class TickerCoordinator { // Race condition? return !(pendingChanges.isEmpty() && pendingEvaluations.isEmpty()); } - + private synchronized void runOnePass() throws InterruptedException { canChange.set(false); runPassStage(pendingEvaluations, "EVALUATION"); @@ -180,69 +208,70 @@ public class TickerCoordinator { } private synchronized void runPassStage( - Collection tasks, - String stageName - ) throws InterruptedException { + Collection tasks, + String stageName + ) + throws InterruptedException { if (!toDispose.isEmpty()) throw new IllegalStateException("toDispose is not empty: " + toDispose); - + Collection toDispose = this.toDispose; - + startPassStage(tasks, toDispose, stageName); sync(); dispose(toDispose); } - + private void dispose(Collection toDispose) { toDispose.forEach(TickerTask::dispose); toDispose.clear(); } private synchronized void startPassStage( - Collection tasks, - Collection toDispose, - String stageName + Collection tasks, + Collection toDispose, + String stageName ) { if (tasks.isEmpty()) { logger.debug("Skipping stage {}: tasks is empty", stageName); return; } - + logger.debug("Starting stage {}", stageName); if (!cachedTransferList.isEmpty()) throw new IllegalStateException("cachedTransferList is not empty: " + cachedTransferList); - + workingTickers.set(0); - + for (Ticker ticker : tickers) { workingTickers.incrementAndGet(); - + Collection selectedTasks = cachedTransferList; ticker.requestWork(selectTasks(ticker, tasks, selectedTasks)); selectedTasks.clear(); } - + toDispose.addAll(tasks); tasks.clear(); - + logger.debug("Stage started"); } private Collection selectTasks( - Ticker ticker, - Collection tasks, - Collection output + Ticker ticker, + Collection tasks, + Collection output ) { // TODO implement properly - + for (TickerTask task : tasks) { // Assign to one ticker randomly if (task.hashCode() % tickers.size() == ticker.getId()) { output.add(task); } } - + return output; } @@ -254,36 +283,36 @@ public class TickerCoordinator { } logger.debug("Sync achieved"); } - + /* * Interface for Tickers */ - + synchronized void reportWorkComplete() { int stillWorking = workingTickers.decrementAndGet(); if (stillWorking < 0) throw new IllegalStateException("stillWorking = " + stillWorking); - + if (stillWorking != 0) { logger.debug("stillWorking = {}, not notifying sync", stillWorking); return; } - + logger.debug("All tickers reported completion, notifying sync"); - + this.notifyAll(); } - + void crash(Throwable t, String thread) { if (t instanceof ConcurrentModificationException) { logger.debug("javahorse kill urself"); } throw CrashReports.crash( - t, - "Something has gone horribly wrong in server ticker code " + t, + "Something has gone horribly wrong in server ticker code " + "(thread %s) and it is (probably) not related to mods or devils.", - thread + thread ); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java index afbecc5..4a075c0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickerTask.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import glm.vec._3.i.Vec3i; @@ -6,42 +24,54 @@ import ru.windcorp.progressia.server.Server; /** * A task that can be executed by a Ticker. - * This is a superinterface for {@link Change} and {@link Evaluation} and is not meant to be extended further. - * This interface is used to determine the Ticker that is suitable for the execution of this task. + * This is a superinterface for {@link Change} and {@link Evaluation} and is not + * meant to be extended further. + * This interface is used to determine the Ticker that is suitable for the + * execution of this task. + * * @author javapony */ public abstract class TickerTask { - + /** * Returns {@code false} iff this task is thread-safe and may be executed by * any Ticker. If and only if a task returns {@code true} in this method * is its {@link #getRelevantChunk(Vec3i)} method invoked. - * @implNote Default implementation returns {@code true}, making this task thread-sensitive - * @return {@code true} iff this task must be run in a Ticker implied by {@link #getRelevantChunk(Vec3i)} + * + * @implNote Default implementation returns {@code true}, making this task + * thread-sensitive + * @return {@code true} iff this task must be run in a Ticker implied by + * {@link #getRelevantChunk(Vec3i)} */ public boolean isThreadSensitive() { return true; } - + /** - * Sets {@code output} to be equal to the {@linkplain Coordinates#chunk coordinates of chunk} - * of the chunk that must be owned by the Ticker will execute this task. This method + * Sets {@code output} to be equal to the {@linkplain Coordinates#chunk + * coordinates of chunk} + * of the chunk that must be owned by the Ticker will execute this task. + * This method * is not invoked iff {@link #isThreadSensitive()} returned {@code false}. + * * @param output a {@link Vec3i} to set to the requested value */ public abstract void getRelevantChunk(Vec3i output); - + /** * Invoked when this task has completed and will no longer be used. * This method is guaranteed to be invoked in the main server thread. + * * @implNote Default implementation does nothing */ public void dispose() { // Do nothing } - + /** - * Executes this task. This method is provided for the convenience of Tickers. + * Executes this task. This method is provided for the convenience of + * Tickers. + * * @param server the server to run on */ abstract void run(Server server); diff --git a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java index 70e3a6b..a5836fe 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java +++ b/src/main/java/ru/windcorp/progressia/server/world/ticking/TickingPolicy.java @@ -1,33 +1,60 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.ticking; import ru.windcorp.progressia.server.world.block.TickableBlock; import ru.windcorp.progressia.server.world.tile.TickableTile; /** - * Various ticking policies that {@link TickableBlock} or {@link TickableTile} can have. + * Various ticking policies that {@link TickableBlock} or {@link TickableTile} + * can have. * Ticking policy determines when, and if, the block or tile is ticked. + * * @author javapony */ public enum TickingPolicy { - + /** * The ticking policy that requests that no ticks happen. - * This is typically used for blocks or tiles that only tick under certain conditions, + * This is typically used for blocks or tiles that only tick under certain + * conditions, * which are not meant at the moment. */ NONE, - + /** - * The ticking policy that requests that the object is ticked every server tick exactly once. - * This should not be used for objects that only change rarely; consider using {@link RANDOM} + * The ticking policy that requests that the object is ticked every server + * tick exactly once. + * This should not be used for objects that only change rarely; consider + * using {@link RANDOM} * instead. */ REGULAR, - + /** - * The ticking policy that requests that the object is ticked only once every + * The ticking policy that requests that the object is ticked only once + * every + * *

-	 * Server.getTickingSettings().getRandomTickFrequency()
+ * Server.getTickingSettings().getRandomTickFrequency() + * + * * seconds on average (this value is only determined at runtime). Note that * the block might sometimes tick more than once per single server tick. */ diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java index 8d11430..745f289 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/HangingTileLogic.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.server.world.block.BlockLogic; @@ -7,29 +25,32 @@ public class HangingTileLogic extends TileLogic implements UpdateableTile { public HangingTileLogic(String id) { super(id); } - + @Override public void update(TileTickContext context) { if (!canOccupyFace(context)) { context.removeThisTile(); } } - + @Override public boolean canOccupyFace(TileTickContext context) { BlockLogic host = context.getBlock(); - if (host == null) return false; - - if (!host.isSolid(context, context.getFace())) return false; - - if (canBeSquashed(context)) return true; - + if (host == null) + return false; + + if (!host.isSolid(context, context.getFace())) + return false; + + if (canBeSquashed(context)) + return true; + return context.evalComplementary(ctxt -> { BlockLogic complHost = ctxt.getBlock(); return complHost == null || !complHost.isSolid(ctxt, context.getFace()); }); } - + public boolean canBeSquashed(TileTickContext context) { return false; } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java index 97fd925..399f7b8 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TSTickContext.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tile; import java.util.Objects; @@ -12,73 +30,77 @@ import ru.windcorp.progressia.server.world.TickContextMutable; import ru.windcorp.progressia.server.world.block.BlockTickContext; public interface TSTickContext extends BlockTickContext { - + /* * Specifications */ - + BlockFace getFace(); - + /* * Getters */ - + default TileLogicStack getTLSOrNull() { ChunkLogic chunkLogic = getChunkLogic(); - if (chunkLogic == null) return null; - + if (chunkLogic == null) + return null; + return chunkLogic.getTilesOrNull(getBlockInChunk(), getFace()); } - + default TileLogicStack getTLS() { return getChunkLogic().getTiles(getBlockInChunk(), getFace()); } - + default TileDataStack getTDSOrNull() { ChunkData chunkData = getChunkData(); - if (chunkData == null) return null; - + if (chunkData == null) + return null; + return chunkData.getTilesOrNull(getBlockInChunk(), getFace()); } - + default TileDataStack getTDS() { return getChunkData().getTiles(getBlockInChunk(), getFace()); } - + /* * Contexts */ - + default TileTickContext forLayer(int layer) { - return TickContextMutable.start().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()).withLayer(layer); + return TickContextMutable.start().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()) + .withLayer(layer); } - + default boolean forEachTile(Consumer action) { TickContextMutable context = TickContextMutable.uninitialized(); - + TileDataStack stack = getTDSOrNull(); - if (stack == null || stack.isEmpty()) return false; - + if (stack == null || stack.isEmpty()) + return false; + for (int layer = 0; layer < stack.size(); ++layer) { context.rebuild().withServer(getServer()).withBlock(getBlockInWorld()).withFace(getFace()).withLayer(layer); action.accept(context); } - + return true; } - + default TSTickContext getComplementary() { return TickContextMutable.copyWorld(this) - .withBlock(getBlockInWorld().add_(getFace().getVector())) - .withFace(getFace().getCounter()) - .build(); + .withBlock(getBlockInWorld().add_(getFace().getVector())) + .withFace(getFace().getCounter()) + .build(); } - + default R evalComplementary(Function action) { Objects.requireNonNull(action, "action"); return action.apply(getComplementary()); } - + default void forComplementary(Consumer action) { Objects.requireNonNull(action, "action"); evalComplementary((Function) ctxt -> { diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java index cf49856..4def3b0 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TickableTile.java @@ -1,11 +1,29 @@ -package ru.windcorp.progressia.server.world.tile; - -import ru.windcorp.progressia.server.world.ticking.TickingPolicy; - -public interface TickableTile { - - void tick(TileTickContext context); - - TickingPolicy getTickingPolicy(TileTickContext context); - -} \ No newline at end of file +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.tile; + +import ru.windcorp.progressia.server.world.ticking.TickingPolicy; + +public interface TickableTile { + + void tick(TileTickContext context); + + TickingPolicy getTickingPolicy(TileTickContext context); + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java index 3521143..4a97ead 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogic.java @@ -1,29 +1,47 @@ -package ru.windcorp.progressia.server.world.tile; - -import ru.windcorp.progressia.common.util.namespaces.Namespaced; -import ru.windcorp.progressia.common.world.block.BlockFace; -import ru.windcorp.progressia.common.world.generic.GenericTile; - -public class TileLogic extends Namespaced implements GenericTile { - - public TileLogic(String id) { - super(id); - } - - public boolean canOccupyFace(TileTickContext context) { - return canOccupyFace(context.getFace()); - } - - public boolean canOccupyFace(BlockFace face) { - return true; - } - - public boolean isSolid(TileTickContext context) { - return isSolid(); - } - - public boolean isSolid() { - return false; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.tile; + +import ru.windcorp.progressia.common.util.namespaces.Namespaced; +import ru.windcorp.progressia.common.world.block.BlockFace; +import ru.windcorp.progressia.common.world.generic.GenericTile; + +public class TileLogic extends Namespaced implements GenericTile { + + public TileLogic(String id) { + super(id); + } + + public boolean canOccupyFace(TileTickContext context) { + return canOccupyFace(context.getFace()); + } + + public boolean canOccupyFace(BlockFace face) { + return true; + } + + public boolean isSolid(TileTickContext context) { + return isSolid(); + } + + public boolean isSolid() { + return false; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java index 2424e46..d8bceaf 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicRegistry.java @@ -1,13 +1,31 @@ -package ru.windcorp.progressia.server.world.tile; - -import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; - -public class TileLogicRegistry extends NamespacedInstanceRegistry { - - private static final TileLogicRegistry INSTANCE = new TileLogicRegistry(); - - public static TileLogicRegistry getInstance() { - return INSTANCE; - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.tile; + +import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry; + +public class TileLogicRegistry extends NamespacedInstanceRegistry { + + private static final TileLogicRegistry INSTANCE = new TileLogicRegistry(); + + public static TileLogicRegistry getInstance() { + return INSTANCE; + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java index 6c0b6ec..5e91963 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileLogicStack.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.server.world.tile; import ru.windcorp.progressia.common.world.generic.GenericTileStack; @@ -5,12 +23,8 @@ import ru.windcorp.progressia.common.world.tile.TileDataStack; import ru.windcorp.progressia.server.world.ChunkLogic; public abstract class TileLogicStack -extends GenericTileStack< - TileLogicStack, - TileLogic, - ChunkLogic -> { - + extends GenericTileStack { + public abstract TileDataStack getData(); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java index 02a5164..45f41ec 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/TileTickContext.java @@ -1,55 +1,76 @@ -package ru.windcorp.progressia.server.world.tile; - -import ru.windcorp.progressia.common.world.tile.TileData; -import ru.windcorp.progressia.common.world.tile.TileDataStack; -import ru.windcorp.progressia.common.world.tile.TileReference; - -public interface TileTickContext extends TSTickContext { - - /* - * Specifications - */ - - /** - * Returns the current layer. - * @return the layer that the tile being ticked occupies in the tile stack - */ - int getLayer(); - - /* - * Getters - */ - - default TileLogic getTile() { - TileLogicStack stack = getTLSOrNull(); - if (stack == null) return null; - return stack.get(getLayer()); - } - - default TileData getTileData() { - TileDataStack stack = getTDSOrNull(); - if (stack == null) return null; - return stack.get(getLayer()); - } - - default TileReference getReference() { - return getTDS().getReference(getLayer()); - } - - default int getTag() { - return getTDS().getTagByIndex(getLayer()); - } - - /* - * Contexts - */ - - /* - * Convenience methods - changes - */ - - default void removeThisTile() { - getAccessor().removeTile(getBlockInWorld(), getFace(), getTag()); - } - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.tile; + +import ru.windcorp.progressia.common.world.tile.TileData; +import ru.windcorp.progressia.common.world.tile.TileDataStack; +import ru.windcorp.progressia.common.world.tile.TileReference; + +public interface TileTickContext extends TSTickContext { + + /* + * Specifications + */ + + /** + * Returns the current layer. + * + * @return the layer that the tile being ticked occupies in the tile stack + */ + int getLayer(); + + /* + * Getters + */ + + default TileLogic getTile() { + TileLogicStack stack = getTLSOrNull(); + if (stack == null) + return null; + return stack.get(getLayer()); + } + + default TileData getTileData() { + TileDataStack stack = getTDSOrNull(); + if (stack == null) + return null; + return stack.get(getLayer()); + } + + default TileReference getReference() { + return getTDS().getReference(getLayer()); + } + + default int getTag() { + return getTDS().getTagByIndex(getLayer()); + } + + /* + * Contexts + */ + + /* + * Convenience methods - changes + */ + + default void removeThisTile() { + getAccessor().removeTile(getBlockInWorld(), getFace(), getTag()); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java index e96d3cd..bf114fa 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java +++ b/src/main/java/ru/windcorp/progressia/server/world/tile/UpdateableTile.java @@ -1,7 +1,25 @@ -package ru.windcorp.progressia.server.world.tile; - -public interface UpdateableTile { - - void update(TileTickContext context); - -} +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package ru.windcorp.progressia.server.world.tile; + +public interface UpdateableTile { + + void update(TileTickContext context); + +} diff --git a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java index 3a4c432..4c7ca68 100644 --- a/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java +++ b/src/main/java/ru/windcorp/progressia/test/CollisionModelRenderer.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.test; import glm.mat._4.Mat4; @@ -13,10 +31,12 @@ import ru.windcorp.progressia.common.collision.CollisionModel; import ru.windcorp.progressia.common.collision.CompoundCollisionModel; public class CollisionModelRenderer { - - private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(1.0f, 0.7f, 0.2f).create(); - private static final Shape CUBE_GRAY = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null).setColorMultiplier(0.5f, 0.5f, 0.5f).create(); - + + private static final Shape CUBE = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setColorMultiplier(1.0f, 0.7f, 0.2f).create(); + private static final Shape CUBE_GRAY = new Shapes.PppBuilder(WorldRenderProgram.getDefault(), (Texture) null) + .setColorMultiplier(0.5f, 0.5f, 0.5f).create(); + public static void renderCollisionModel(CollisionModel model, ShapeRenderHelper helper) { if (model instanceof AABBoid) { renderAABBoid((AABBoid) model, helper); @@ -26,29 +46,29 @@ public class CollisionModelRenderer { // Ignore silently } } - + private static void renderAABBoid(AABBoid aabb, ShapeRenderHelper helper) { Mat4 mat = helper.pushTransform(); Vec3 tmp = new Vec3(); - + aabb.getOrigin(tmp); mat.translate(tmp); aabb.getSize(tmp); mat.scale(tmp); - + CUBE.render(helper); helper.popTransform(); } - + private static void renderCompound( - CompoundCollisionModel model, - ShapeRenderHelper helper + CompoundCollisionModel model, + ShapeRenderHelper helper ) { for (CollisionModel part : model.getModels()) { renderCollisionModel(part, helper); } } - + public static void renderBlock(Vec3i coords, ShapeRenderHelper helper) { helper.pushTransform().translate(coords.x, coords.y, coords.z).scale(0.25f); CUBE_GRAY.render(helper); diff --git a/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java index 23761e5..a9df57a 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlBreakBlockData.java @@ -1,20 +1,38 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.comms.controls.ControlData; public class ControlBreakBlockData extends ControlData { - + private final Vec3i blockInWorld = new Vec3i(); public ControlBreakBlockData(String id) { super(id); } - + public Vec3i getBlockInWorld() { return blockInWorld; } - + public void setBlockInWorld(Vec3i blockInWorld) { this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); } diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java index 25a72e9..f3e45e2 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceBlockData.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; @@ -5,22 +23,22 @@ import ru.windcorp.progressia.common.comms.controls.ControlData; import ru.windcorp.progressia.common.world.block.BlockData; public class ControlPlaceBlockData extends ControlData { - + private BlockData block; private final Vec3i blockInWorld = new Vec3i(); public ControlPlaceBlockData(String id) { super(id); } - + public BlockData getBlock() { return block; } - + public Vec3i getBlockInWorld() { return blockInWorld; } - + public void set(BlockData block, Vec3i blockInWorld) { this.block = block; this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); diff --git a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java index 90ab2ee..5a37b6f 100644 --- a/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java +++ b/src/main/java/ru/windcorp/progressia/test/ControlPlaceTileData.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.test; import glm.vec._3.i.Vec3i; @@ -6,7 +24,7 @@ import ru.windcorp.progressia.common.world.block.BlockFace; import ru.windcorp.progressia.common.world.tile.TileData; public class ControlPlaceTileData extends ControlData { - + private TileData tile; private final Vec3i blockInWorld = new Vec3i(); private BlockFace face; @@ -14,19 +32,19 @@ public class ControlPlaceTileData extends ControlData { public ControlPlaceTileData(String id) { super(id); } - + public TileData getTile() { return tile; } - + public Vec3i getBlockInWorld() { return blockInWorld; } - + public BlockFace getFace() { return face; } - + public void set(TileData block, Vec3i blockInWorld, BlockFace face) { this.tile = block; this.blockInWorld.set(blockInWorld.x, blockInWorld.y, blockInWorld.z); diff --git a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java index dda74a8..3ba5aba 100644 --- a/src/main/java/ru/windcorp/progressia/test/LayerAbout.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerAbout.java @@ -1,3 +1,21 @@ +/* + * Progressia + * Copyright (C) 2020-2021 Wind Corporation and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package ru.windcorp.progressia.test; import ru.windcorp.progressia.client.graphics.Colors; @@ -14,29 +32,38 @@ public class LayerAbout extends GUILayer { public LayerAbout() { super("LayerAbout", new LayoutAlign(1, 1, 5)); - + Panel panel = new Panel("ControlDisplays", new LayoutVertical(5)); - + Font font = new Font().withColor(Colors.WHITE).deriveOutlined().withAlign(Typeface.ALIGN_RIGHT); Font aboutFont = font.withColor(0xFF37A3E6).deriveBold(); - - panel.addChild(new Label( - "About", aboutFont, + + panel.addChild( + new Label( + "About", + aboutFont, new MutableStringLocalized("LayerAbout.Title") - )); - - panel.addChild(new Label( - "Version", font, + ) + ); + + panel.addChild( + new Label( + "Version", + font, new MutableStringLocalized("LayerAbout.Version").format("pre-TechDemo") - )); - - panel.addChild(new Label( - "DebugHint", font, + ) + ); + + panel.addChild( + new Label( + "DebugHint", + font, new MutableStringLocalized("LayerAbout.DebugHint") - )); - + ) + ); + getRoot().addChild(panel); - + } } diff --git a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java index 201a77a..30cca35 100755 --- a/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/test/LayerTestGUI.java @@ -1,338 +1,391 @@ -/******************************************************************************* - * Progressia - * Copyright (C) 2020 Wind Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *******************************************************************************/ -package ru.windcorp.progressia.test; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Objects; -import java.util.function.Supplier; - -import glm.vec._3.Vec3; -import glm.vec._4.Vec4; -import ru.windcorp.progressia.client.Client; -import ru.windcorp.progressia.client.ClientState; -import ru.windcorp.progressia.client.graphics.Colors; -import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface; -import ru.windcorp.progressia.client.graphics.font.Font; -import ru.windcorp.progressia.client.graphics.gui.DynamicLabel; -import ru.windcorp.progressia.client.graphics.gui.GUILayer; -import ru.windcorp.progressia.client.graphics.gui.Label; -import ru.windcorp.progressia.client.graphics.gui.Panel; -import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; -import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; -import ru.windcorp.progressia.client.localization.Localizer; -import ru.windcorp.progressia.client.localization.MutableString; -import ru.windcorp.progressia.client.localization.MutableStringLocalized; -import ru.windcorp.progressia.common.Units; -import ru.windcorp.progressia.common.util.dynstr.DynamicStrings; -import ru.windcorp.progressia.server.Server; -import ru.windcorp.progressia.server.ServerState; - -public class LayerTestGUI extends GUILayer { - - public LayerTestGUI() { - super("LayerTestGui", new LayoutAlign(0, 1, 5)); - - Panel panel = new Panel("ControlDisplays", new LayoutVertical(5)); - - Vec4 color = Colors.WHITE; - Font font = new Font().withColor(color).deriveOutlined(); - - TestPlayerControls tpc = TestPlayerControls.getInstance(); - - panel.addChild(new Label( - "IsFlyingDisplay", font, - tmp_dynFormat("LayerTestGUI.IsFlyingDisplay", tpc::isFlying) - )); - - panel.addChild(new Label( - "IsSprintingDisplay", font, - tmp_dynFormat("LayerTestGUI.IsSprintingDisplay", tpc::isSprinting) - )); - - panel.addChild(new Label( - "IsMouseCapturedDisplay", font, - tmp_dynFormat("LayerTestGUI.IsMouseCapturedDisplay", tpc::isMouseCaptured) - )); - - panel.addChild(new Label( - "CameraModeDisplay", font, - tmp_dynFormat("LayerTestGUI.CameraModeDisplay", ClientState.getInstance().getCamera()::getCurrentModeIndex) - )); - - panel.addChild(new Label( - "GravityModeDisplay", font, - tmp_dynFormat("LayerTestGUI.GravityModeDisplay", () -> tpc.useMinecraftGravity() ? "Minecraft" : "Realistic") - )); - - panel.addChild(new Label( - "LanguageDisplay", font, - tmp_dynFormat("LayerTestGUI.LanguageDisplay", Localizer.getInstance()::getLanguage) - )); - - panel.addChild(new DynamicLabel( - "FPSDisplay", font, - DynamicStrings.builder() - .addDyn(new MutableStringLocalized("LayerTestGUI.FPSDisplay")) - .addDyn(() -> FPS_RECORD.update(GraphicsInterface.getFPS()), 5, 1) - .buildSupplier(), - 128 - )); - - panel.addChild(new DynamicLabel( - "TPSDisplay", font, - LayerTestGUI::getTPS, - 128 - )); - - panel.addChild(new DynamicLabel( - "ChunkUpdatesDisplay", font, - DynamicStrings.builder() - .addDyn(new MutableStringLocalized("LayerTestGUI.ChunkUpdatesDisplay")) - .addDyn(ClientState.getInstance().getWorld()::getPendingChunkUpdates) - .buildSupplier(), - 128 - )); - - panel.addChild(new DynamicLabel( - "PosDisplay", font, - LayerTestGUI::getPos, - 128 - )); - - panel.addChild(new Label( - "SelectedBlockDisplay", font, - tmp_dynFormat("LayerTestGUI.SelectedBlockDisplay", - () -> tpc.isBlockSelected() ? ">" : " ", - () -> tpc.getSelectedBlock().getId() - ) - )); - panel.addChild(new Label( - "SelectedTileDisplay", font, - tmp_dynFormat("LayerTestGUI.SelectedTileDisplay", - () -> tpc.isBlockSelected() ? " " : ">", - () -> tpc.getSelectedTile().getId() - ) - )); - panel.addChild(new Label( - "PlacementModeHint", font, - new MutableStringLocalized("LayerTestGUI.PlacementModeHint").format("\u2B04") - )); - - getRoot().addChild(panel); - } - - public Runnable getUpdateCallback() { - Collection