Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/frontend/StarWireInterface.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/frontend/StarWireInterface.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/frontend/StarWireInterface.cpp')
-rw-r--r--source/frontend/StarWireInterface.cpp332
1 files changed, 332 insertions, 0 deletions
diff --git a/source/frontend/StarWireInterface.cpp b/source/frontend/StarWireInterface.cpp
new file mode 100644
index 0000000..6ea0bce
--- /dev/null
+++ b/source/frontend/StarWireInterface.cpp
@@ -0,0 +1,332 @@
+#include "StarWireInterface.hpp"
+#include "StarGuiReader.hpp"
+#include "StarRoot.hpp"
+#include "StarWorldClient.hpp"
+#include "StarWireEntity.hpp"
+#include "StarWorldGeometry.hpp"
+#include "StarWorldPainter.hpp"
+#include "StarPlayer.hpp"
+#include "StarTools.hpp"
+#include "StarAssets.hpp"
+
+namespace Star {
+
+WirePane::WirePane(WorldClientPtr worldClient, PlayerPtr player, WorldPainterPtr worldPainter) {
+ m_worldClient = worldClient;
+ m_player = player;
+ m_worldPainter = worldPainter;
+
+ m_connecting = false;
+
+ auto assets = Root::singleton().assets();
+ GuiReader reader;
+ reader.construct(assets->json("/interface/wires/wires.config:gui"), this);
+
+ m_insize = Vec2F(context()->textureSize("/interface/wires/inbound.png")) / TilePixels;
+ m_outsize = Vec2F(context()->textureSize("/interface/wires/outbound.png")) / TilePixels;
+ m_nodesize = Vec2F(1.8f, 1.8f);
+
+ setTitle({}, "", "Wire you looking at me like that?");
+ disableScissoring();
+ markAsContainer();
+}
+
+void WirePane::reset() {
+ m_connecting = false;
+}
+
+void WirePane::update() {
+ if (!active())
+ return;
+ if (!m_worldClient->inWorld()) {
+ dismiss();
+ return;
+ }
+
+ if (m_connecting) {
+ for (auto entity : m_worldClient->atTile<WireEntity>(m_sourceConnector.entityLocation)) {
+ if (m_sourceConnector.nodeIndex < entity->nodeCount(m_sourceDirection))
+ return;
+ }
+
+ // stop pending connection if node has been removed
+ m_connecting = false;
+ }
+}
+
+void WirePane::renderWire(Vec2F from, Vec2F to, Color baseColor) {
+ if (m_worldClient->isTileProtected(Vec2I::floor(from)) || m_worldClient->isTileProtected(Vec2I::floor(to)))
+ return;
+
+ from = m_worldPainter->camera().worldToScreen(from);
+ to = m_worldPainter->camera().worldToScreen(to);
+
+ auto rangeRand = [&](float dev, float min, float max) {
+ return clamp<float>(Random::nrandf(dev, max), min, max);
+ };
+
+ float m_beamWidthDev;
+ float m_minBeamWidth;
+ float m_maxBeamWidth;
+ float m_beamTransDev;
+ float m_minBeamTrans;
+ float m_maxBeamTrans;
+ float m_innerBrightnessScale;
+ float m_firstStripeThickness;
+ float m_secondStripeThickness;
+
+ auto assets = Root::singleton().assets();
+ JsonObject config = assets->json("/player.config:beamGunConfig").toObject();
+ m_minBeamWidth = config.get("minBeamWidth").toFloat();
+ m_maxBeamWidth = config.get("maxBeamWidth").toFloat();
+ m_beamWidthDev = config.value("beamWidthDev", (m_maxBeamWidth - m_minBeamWidth) / 3).toFloat();
+ m_minBeamTrans = config.get("minBeamTrans").toFloat();
+ m_maxBeamTrans = config.get("maxBeamTrans").toFloat();
+ m_beamTransDev = config.value("beamTransDev", (m_maxBeamTrans - m_minBeamTrans) / 3).toFloat();
+ m_innerBrightnessScale = config.get("innerBrightnessScale").toFloat();
+ m_firstStripeThickness = config.get("firstStripeThickness").toFloat();
+ m_secondStripeThickness = config.get("secondStripeThickness").toFloat();
+
+ float lineThickness = m_worldPainter->camera().pixelRatio() * rangeRand(m_beamWidthDev, m_minBeamWidth, m_maxBeamWidth);
+ float beamTransparency = rangeRand(m_beamTransDev, m_minBeamTrans, m_maxBeamTrans);
+ baseColor.setAlphaF(baseColor.alphaF() * beamTransparency);
+ Color innerStripe = baseColor;
+ innerStripe.setValue(1 - (1 - innerStripe.value()) / m_innerBrightnessScale);
+ innerStripe.setSaturation(innerStripe.saturation() / m_innerBrightnessScale);
+ Color firstStripe = innerStripe;
+ innerStripe.setValue(1 - (1 - innerStripe.value()) / m_innerBrightnessScale);
+ innerStripe.setSaturation(innerStripe.saturation() / m_innerBrightnessScale);
+ Color secondStripe = innerStripe;
+
+ context()->drawLine(from, to, baseColor.toRgba(), lineThickness);
+ context()->drawLine(from, to, firstStripe.toRgba(), lineThickness * m_firstStripeThickness);
+ context()->drawLine(from, to, secondStripe.toRgba(), lineThickness * m_secondStripeThickness);
+}
+
+void WirePane::renderImpl() {
+ if (!m_worldClient->inWorld())
+ return;
+
+ auto region = RectF(m_worldClient->clientWindow());
+
+ auto const& camera = m_worldPainter->camera();
+ auto highWire = Color::Red;
+ auto lowWire = Color::Red.mix(Color::Black, 0.8f);
+ auto white = Color::White.toRgba();
+ float phase = 0.5f + 0.5f * std::sin((double)Time::monotonicMilliseconds() / 100.0);
+ auto drawLineColor = Color::Red.mix(Color::White, phase);
+
+ for (auto entity : m_worldClient->query<WireEntity>(region)) {
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Input); ++i) {
+ Vec2I position = entity->tilePosition() + entity->nodePosition({WireDirection::Input, i});
+ if (!m_worldClient->isTileProtected(position)) {
+ context()->drawQuad("/interface/wires/inbound.png",
+ camera.worldToScreen(centerOfTile(position) - (m_insize / 2.0f)),
+ camera.pixelRatio(), white);
+ }
+ }
+
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Output); ++i) {
+ Vec2I position = entity->tilePosition() + entity->nodePosition({WireDirection::Output, i});
+ if (!m_worldClient->isTileProtected(position)) {
+ context()->drawQuad("/interface/wires/outbound.png",
+ camera.worldToScreen(centerOfTile(position) - (m_outsize / 2.0f)),
+ camera.pixelRatio(), white);
+ }
+ }
+ }
+
+ HashSet<pair<WireConnection, WireConnection>> visitedConnections;
+ for (auto entity : m_worldClient->query<WireEntity>(region)) {
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Input); ++i) {
+ Vec2I tilePosition = entity->tilePosition();
+ Vec2I inPosition = tilePosition + entity->nodePosition({WireDirection::Input, i});
+
+ for (auto const& connection : entity->connectionsForNode({WireDirection::Input, i})) {
+ visitedConnections.add({{tilePosition, i}, connection});
+
+ auto wire = lowWire;
+ Vec2I outPosition = connection.entityLocation;
+ if (auto sourceEntity = m_worldClient->atTile<WireEntity>(connection.entityLocation).get(0)) {
+ outPosition += sourceEntity->nodePosition({WireDirection::Output, connection.nodeIndex});
+ if (sourceEntity->nodeState(WireNode{WireDirection::Output, connection.nodeIndex}))
+ wire = highWire;
+ }
+
+ renderWire(centerOfTile(inPosition), centerOfTile(outPosition), wire);
+ }
+ }
+
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Output); ++i) {
+ Vec2I tilePosition = entity->tilePosition();
+ Vec2I outPosition = tilePosition + entity->nodePosition({WireDirection::Output, i});
+
+ auto wire = lowWire;
+ if (entity->nodeState({WireDirection::Output, i}))
+ wire = highWire;
+
+ for (auto const& connection : entity->connectionsForNode({WireDirection::Output, i})) {
+ visitedConnections.contains({connection, {tilePosition, i}});
+
+ Vec2I inPosition = connection.entityLocation;
+ if (auto sourceEntity = m_worldClient->atTile<WireEntity>(connection.entityLocation).get(0))
+ inPosition += sourceEntity->nodePosition({WireDirection::Input, connection.nodeIndex});
+
+ renderWire(centerOfTile(outPosition), centerOfTile(inPosition), wire);
+ }
+ }
+ }
+
+ if (m_connecting) {
+ Vec2F aimPos = m_worldPainter->camera().screenToWorld(Vec2F(m_mousePos) * m_context->interfaceScale());
+ Vec2I sourcePosition = m_sourceConnector.entityLocation;
+ if (auto sourceEntity = m_worldClient->atTile<WireEntity>(m_sourceConnector.entityLocation).get(0)) {
+ if (m_sourceDirection == WireDirection::Input)
+ sourcePosition += sourceEntity->nodePosition({WireDirection::Input, m_sourceConnector.nodeIndex});
+ else
+ sourcePosition += sourceEntity->nodePosition({WireDirection::Output, m_sourceConnector.nodeIndex});
+ }
+ renderWire(centerOfTile(sourcePosition), aimPos, drawLineColor);
+ }
+}
+
+bool WirePane::sendEvent(InputEvent const& event) {
+ if (event.is<MouseMoveEvent>())
+ m_mousePos = *context()->mousePosition(event);
+
+ if (event.is<MouseButtonDownEvent>())
+ m_mousePos = *context()->mousePosition(event);
+
+ return false;
+}
+
+WireConnector::SwingResult WirePane::swing(WorldGeometry const& geometry, Vec2F pos, FireMode mode) {
+ pos = geometry.xwrap(pos);
+
+ if (m_worldClient->isTileProtected((Vec2I)pos)) {
+ m_connecting = false;
+ return Protected;
+ }
+
+ RectF bounds = {pos - Vec2F(16, 16), pos + Vec2F(16, 16)};
+
+ if (mode == FireMode::Primary) {
+ Maybe<WireConnection> matchNode;
+ WireDirection matchDirection = WireDirection::Output;
+ float bestDist = 10000;
+ for (auto entity : m_worldClient->query<WireEntity>(bounds)) {
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Input); ++i) {
+ RectF inbounds = RectF::withSize(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})) - (m_nodesize / 2.0f), m_nodesize);
+ if (geometry.rectContains(inbounds, pos)) {
+ if (!matchNode) {
+ matchNode = WireConnection{entity->tilePosition(), i};
+ matchDirection = WireDirection::Input;
+ bestDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})), pos).magnitudeSquared();
+ } else {
+ float thisDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})), pos).magnitudeSquared();
+ if (thisDist < bestDist) {
+ matchNode = WireConnection{entity->tilePosition(), i};
+ matchDirection = WireDirection::Input;
+ bestDist = thisDist;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Output); ++i) {
+ RectF outbounds = RectF::withSize(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})) - (m_nodesize / 2.0f), m_nodesize);
+ if (geometry.rectContains(outbounds, pos)) {
+ if (!matchNode) {
+ matchNode = WireConnection{entity->tilePosition(), i};
+ matchDirection = WireDirection::Output;
+ bestDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})), pos).magnitudeSquared();
+ } else {
+ float thisDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})), pos).magnitudeSquared();
+ if (thisDist < bestDist) {
+ matchNode = WireConnection{entity->tilePosition(), i};
+ matchDirection = WireDirection::Output;
+ bestDist = thisDist;
+ }
+ }
+ }
+ }
+ }
+
+ if (matchNode) {
+ if (m_connecting) {
+ if (m_sourceDirection == matchDirection) {
+ return Mismatch;
+ } else if (m_sourceConnector.entityLocation == matchNode->entityLocation) {
+ return Mismatch;
+ } else {
+ m_connecting = false;
+ if (matchDirection == WireDirection::Output)
+ m_worldClient->connectWire(*matchNode, m_sourceConnector);
+ else
+ m_worldClient->connectWire(m_sourceConnector, *matchNode);
+ }
+ } else {
+ m_connecting = true;
+ m_sourceDirection = matchDirection;
+ m_sourceConnector = *matchNode;
+ }
+ return Connect;
+ }
+
+ } else {
+ m_connecting = false;
+
+ Maybe<WireNode> matchNode;
+ Maybe<Vec2I> matchPosition;
+ float bestDist = 10000;
+ for (auto entity : m_worldClient->query<WireEntity>(bounds)) {
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Input); ++i) {
+ RectF inbounds = RectF::withSize(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})) - (m_nodesize / 2.0f), m_nodesize);
+ if (geometry.rectContains(inbounds, pos) && entity->connectionsForNode({WireDirection::Input, i}).size() > 0) {
+ if (!matchNode) {
+ matchPosition = entity->tilePosition();
+ matchNode = WireNode{WireDirection::Input, i};
+ bestDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})), pos).magnitudeSquared();
+ } else {
+ float thisDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Input, i})), pos).magnitudeSquared();
+ if (thisDist < bestDist) {
+ matchPosition = entity->tilePosition();
+ matchNode = WireNode{WireDirection::Input, i};
+ bestDist = thisDist;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < entity->nodeCount(WireDirection::Output); ++i) {
+ RectF outbounds = RectF::withSize(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})) - (m_nodesize / 2.0f), m_nodesize);
+ if (geometry.rectContains(outbounds, pos) && entity->connectionsForNode({WireDirection::Output, i}).size() > 0) {
+ if (!matchNode) {
+ matchPosition = entity->tilePosition();
+ matchNode = WireNode{WireDirection::Output, i};
+ bestDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})), pos).magnitudeSquared();
+ } else {
+ float thisDist = geometry.diff(centerOfTile(entity->tilePosition() + entity->nodePosition({WireDirection::Output, i})), pos).magnitudeSquared();
+ if (thisDist < bestDist) {
+ matchPosition = entity->tilePosition();
+ matchNode = WireNode{WireDirection::Output, i};
+ bestDist = thisDist;
+ }
+ }
+ }
+ }
+ }
+
+ if (matchNode) {
+ m_worldClient->disconnectAllWires(*matchPosition, *matchNode);
+ return Connect;
+ }
+ }
+ return Nothing;
+}
+
+bool WirePane::connecting() {
+ return m_connecting;
+}
+
+}