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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-27 00:42:07 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-27 00:42:07 +1000
commit63b68b3a55a11b32b07e7b8bdbf3760722d5e7f9 (patch)
treea6e9f0b6005d20fe69a00e1a585502c7b73461cd
parent94c84ad01333850b88091f2c188e4f6173fd25e7 (diff)
Nameplate and chat bubble improvements
They should stack much better now. I also hooked up the true mouth position to the name-tag, but it's too shaky on chat bubbles.
-rw-r--r--assets/opensb/interface.config.patch3
-rw-r--r--assets/opensb/interface/windowconfig/chatbubbles.config.patch3
-rw-r--r--source/frontend/StarChatBubbleSeparation.cpp29
-rw-r--r--source/frontend/StarChatBubbleSeparation.hpp71
-rw-r--r--source/frontend/StarNameplatePainter.cpp2
-rw-r--r--source/game/StarMonster.cpp8
-rw-r--r--source/game/StarMonster.hpp2
-rw-r--r--source/game/StarNpc.cpp16
-rw-r--r--source/game/StarNpc.hpp4
-rw-r--r--source/game/StarObject.cpp4
-rw-r--r--source/game/StarObject.hpp1
-rw-r--r--source/game/StarPlayer.cpp14
-rw-r--r--source/game/StarPlayer.hpp4
-rw-r--r--source/game/interfaces/StarChattyEntity.hpp3
-rw-r--r--source/game/interfaces/StarNametagEntity.hpp1
15 files changed, 120 insertions, 45 deletions
diff --git a/assets/opensb/interface.config.patch b/assets/opensb/interface.config.patch
index eb33cb8..c76c812 100644
--- a/assets/opensb/interface.config.patch
+++ b/assets/opensb/interface.config.patch
@@ -3,7 +3,8 @@
"showMasterNames" : true,
"fontDirectives" : "?border=1;222;2220",
"inspectOpacityRate" : 0.15,
- "movementThreshold" : 0.5
+ "movementThreshold" : 0.5,
+ "offset" : [0, 13]
},
"font" : {
"defaultDirectives" : "",
diff --git a/assets/opensb/interface/windowconfig/chatbubbles.config.patch b/assets/opensb/interface/windowconfig/chatbubbles.config.patch
index 5aed747..c3da49d 100644
--- a/assets/opensb/interface/windowconfig/chatbubbles.config.patch
+++ b/assets/opensb/interface/windowconfig/chatbubbles.config.patch
@@ -1,3 +1,4 @@
{
- "movementThreshold" : 0.5
+ "movementThreshold" : 0.5,
+ "bubbleOffset" : [0, 1.875]
} \ No newline at end of file
diff --git a/source/frontend/StarChatBubbleSeparation.cpp b/source/frontend/StarChatBubbleSeparation.cpp
index 568ca37..23a34fe 100644
--- a/source/frontend/StarChatBubbleSeparation.cpp
+++ b/source/frontend/StarChatBubbleSeparation.cpp
@@ -1,4 +1,5 @@
#include "StarChatBubbleSeparation.hpp"
+#include "StarLogging.hpp"
namespace Star {
@@ -21,7 +22,7 @@ bool compareOverlapRight(RectF const& newBox, RectF const& fixedBox) {
template <typename Compare>
void appendHorizontalOverlaps(List<RectF>& overlaps,
List<RectF> const& boxes,
- List<RectF>::iterator leftBound,
+ List<RectF>::const_iterator leftBound,
Compare compare,
RectF const& box) {
auto i = leftBound;
@@ -36,7 +37,7 @@ void appendHorizontalOverlaps(List<RectF>& overlaps,
}
}
-RectF separateBubble(List<RectF>& sortedLeftEdges, List<RectF>& sortedRightEdges, RectF box) {
+RectF separateBubble(List<RectF> const& sortedLeftEdges, List<RectF> const& sortedRightEdges, List<RectF>& outLeftEdges, List<RectF>& outRightEdges, RectF box) {
// We have to maintain two lists of boxes: one sorted by the left edges and
// one
// by the right edges. This is because boxes can be different sizes, and
@@ -54,19 +55,33 @@ RectF separateBubble(List<RectF>& sortedLeftEdges, List<RectF>& sortedRightEdges
// overlap with 'box'.
while (true) {
- // While box is overlapping any other boxes, raise its Y value.
- List<RectF> overlappingBoxes =
- horizontalOverlaps.filtered([&box](RectF const& overlapper) { return box.intersects(overlapper, false); });
+ // While box is overlapping any other boxes, move it halfway away.
+ List<RectF> overlappingBoxes = horizontalOverlaps.filtered([&box](RectF const& overlapper) {
+ if (overlapper.intersects(box, false)) {
+ Vec2F oSize = overlapper.size(), bSize = box.size();
+ if (oSize[0] == bSize[0]) {
+ if (oSize[1] == bSize[1])
+ return overlapper.center()[1] <= box.center()[1];
+ else
+ return oSize[1] > bSize[1];
+ }
+ else if (oSize[0] > bSize[0])
+ return true;
+ }
+ return false;
+ });
if (overlappingBoxes.empty())
break;
RectF overlapBoundBox = fold(overlappingBoxes, box, [](RectF const& a, RectF const& b) { return a.combined(b); });
+ SpatialLogger::logPoly("screen", PolyF(box), { 255, 0, 0, 255 });
+ SpatialLogger::logPoly("screen", PolyF(overlapBoundBox), { 0, 0, 255, 255 });
auto height = box.height();
box.setYMin(overlapBoundBox.yMax());
box.setYMax(box.yMin() + height);
}
- sortedLeftEdges.insertSorted(box, compareLeft);
- sortedRightEdges.insertSorted(box, compareRight);
+ outLeftEdges.append(box);
+ outRightEdges.append(box);
return box;
}
diff --git a/source/frontend/StarChatBubbleSeparation.hpp b/source/frontend/StarChatBubbleSeparation.hpp
index 88a860c..756db27 100644
--- a/source/frontend/StarChatBubbleSeparation.hpp
+++ b/source/frontend/StarChatBubbleSeparation.hpp
@@ -20,13 +20,16 @@ struct BubbleState {
Vec2F currentDestination;
// The bound box of the nametag if it was at the destination.
RectF boundBox;
- // The position for the bubble chosen by the algorithm (which it may not
+ // The separation offset for the bubble chosen by the algorithm (which it may not
// have fully moved to yet).
- Vec2F separatedPosition;
- // The bound box of the bubble around the separatedPosition.
+ Vec2F seperatedOffset;
+ // The bound box of the bubble around the separatedOffset.
RectF separatedBox;
- // Where the bubble is now, which could be anywhere en route to the
- // separatedPosition.
+ // Where the bubble offset is now, which could be anywhere en route to the
+ // seperatedOffset.
+ Vec2F currentOffset;
+
+ // The final position.
Vec2F currentPosition;
};
@@ -63,6 +66,11 @@ private:
List<RectF> m_sortedRightEdges;
};
+bool compareLeft(RectF const& a, RectF const& b);
+bool compareRight(RectF const& a, RectF const& b);
+bool compareOverlapLeft(RectF const& newBox, RectF const& fixedBox);
+bool compareOverlapRight(RectF const& newBox, RectF const& fixedBox);
+
// Shifts box upwards until it is not overlapping any of the boxes in
// sortedLeftEdges
// and sortedRightEdges.
@@ -71,7 +79,7 @@ private:
// The two lists contain all the chat bubbles that have been separated, sorted
// by
// the X positions of their left and right edges respectively.
-RectF separateBubble(List<RectF>& sortedLeftEdges, List<RectF>& sortedRightEdges, RectF box);
+RectF separateBubble(List<RectF> const& sortedLeftEdges, List<RectF> const& sortedRightEdges, List<RectF>& outLeftEdges, List<RectF>& outRightEdges, RectF box);
template <typename T>
BubbleSeparator<T>::BubbleSeparator(float tweenFactor, float movementThreshold)
@@ -100,9 +108,10 @@ void BubbleSeparator<T>::setMovementThreshold(float movementThreshold) {
template <typename T>
void BubbleSeparator<T>::addBubble(Vec2F position, RectF boundBox, T contents, unsigned margin) {
boundBox.setYMax(boundBox.yMax() + margin);
- RectF separated = separateBubble(m_sortedLeftEdges, m_sortedRightEdges, boundBox);
- Vec2F separatedPosition = position + separated.min() - boundBox.min();
- Bubble bubble = Bubble{contents, position, position, boundBox, separatedPosition, separated, separatedPosition};
+ RectF separated = separateBubble(m_sortedLeftEdges, m_sortedRightEdges, m_sortedLeftEdges, m_sortedRightEdges, boundBox);
+ Vec2F separatedOffset = separated.min() - boundBox.min();
+ Vec2F separatedPosition = position + separatedOffset;
+ Bubble bubble = Bubble{ contents, position, position, boundBox, separatedOffset, separated, separatedOffset, separatedPosition };
m_bubbles.insertSorted(move(bubble), &BubbleSeparator<T>::compareBubbleY);
}
@@ -126,26 +135,36 @@ List<BubbleState<T>> BubbleSeparator<T>::filtered(function<bool(Bubble const&, T
template <typename T>
void BubbleSeparator<T>::forEach(function<void(Bubble&, T&)> func) {
bool anyMoved = false;
- m_bubbles.exec([this, func, &anyMoved](Bubble& bubble) {
+
+ List<Box<float, 2>> leftEdges = move(m_sortedLeftEdges);
+ List<Box<float, 2>> rightEdges = move(m_sortedRightEdges);
+
+ m_bubbles.exec([this, func, &anyMoved, &leftEdges, &rightEdges](Bubble& bubble) {
RectF oldBoundBox = bubble.boundBox;
func(bubble, bubble.contents);
+ // Kae: I'm disabling the movement threshold check for now because it also
+ // stops bubble sorting on bubbles that haven't moved, which causes problems.
+
Vec2F sizeDelta = bubble.boundBox.size() - oldBoundBox.size();
- Vec2F positionDelta = bubble.idealDestination - bubble.currentDestination;
- if (sizeDelta.magnitude() > m_movementThreshold || positionDelta.magnitude() > m_movementThreshold) {
- m_sortedLeftEdges.remove(bubble.separatedBox);
- m_sortedRightEdges.remove(bubble.separatedBox);
- RectF boundBox = bubble.boundBox.translated(positionDelta);
- RectF separated = separateBubble(m_sortedLeftEdges, m_sortedRightEdges, boundBox);
- anyMoved = true;
- bubble.currentDestination = bubble.idealDestination;
- bubble.boundBox = boundBox;
- bubble.separatedPosition = bubble.idealDestination + separated.min() - boundBox.min();
- bubble.separatedBox = separated;
- bubble.currentPosition += positionDelta;
- }
+ leftEdges.remove(bubble.separatedBox);
+ rightEdges.remove(bubble.separatedBox);
+ RectF boundBox = RectF::withCenter(bubble.idealDestination, bubble.boundBox.size());
+ RectF separated = separateBubble(leftEdges, rightEdges, m_sortedLeftEdges, m_sortedRightEdges, boundBox);
+ leftEdges.insertSorted(bubble.separatedBox, compareLeft);
+ rightEdges.insertSorted(bubble.separatedBox, compareRight);
+
+ anyMoved = true;
+ bubble.currentDestination = bubble.idealDestination;
+ bubble.boundBox = boundBox;
+ bubble.seperatedOffset = separated.min() - boundBox.min();
+ bubble.separatedBox = separated;
});
+
+ m_sortedLeftEdges.sort(compareLeft);
+ m_sortedRightEdges.sort(compareRight);
+
if (anyMoved)
m_bubbles.sort(&BubbleSeparator<T>::compareBubbleY);
}
@@ -153,8 +172,10 @@ void BubbleSeparator<T>::forEach(function<void(Bubble&, T&)> func) {
template <typename T>
void BubbleSeparator<T>::update() {
m_bubbles.exec([this](Bubble& bubble) {
- Vec2F delta = bubble.separatedPosition - bubble.currentPosition;
- bubble.currentPosition += m_tweenFactor * delta;
+ Vec2F delta = bubble.seperatedOffset - bubble.currentOffset;
+ bubble.currentOffset += m_tweenFactor * delta;
+
+ bubble.currentPosition = bubble.currentDestination + bubble.currentOffset;
});
}
diff --git a/source/frontend/StarNameplatePainter.cpp b/source/frontend/StarNameplatePainter.cpp
index d7e589a..0bc96ff 100644
--- a/source/frontend/StarNameplatePainter.cpp
+++ b/source/frontend/StarNameplatePainter.cpp
@@ -53,7 +53,7 @@ void NameplatePainter::update(WorldClientPtr const& world, WorldCamera const& ca
m_nametags.forEach([&world, &camera, this, inspectionMode](BubbleState<Nametag>& bubbleState, Nametag& nametag) {
if (auto entity = as<NametagEntity>(world->entity(nametag.entityId))) {
- bubbleState.idealDestination = camera.worldToScreen(entity->position()) + m_offset * camera.pixelRatio();
+ bubbleState.idealDestination = camera.worldToScreen(entity->nametagOrigin()) + m_offset * camera.pixelRatio();
bubbleState.boundBox = determineBoundBox(bubbleState.idealDestination, nametag);
nametag.statusText = entity->statusText();
diff --git a/source/game/StarMonster.cpp b/source/game/StarMonster.cpp
index 2b994d9..c8b69bf 100644
--- a/source/game/StarMonster.cpp
+++ b/source/game/StarMonster.cpp
@@ -810,6 +810,10 @@ Vec3B Monster::nametagColor() const {
return m_monsterVariant.nametagColor;
}
+Vec2F Monster::nametagOrigin() const {
+ return mouthPosition(false);
+}
+
bool Monster::aggressive() const {
return m_aggressive;
}
@@ -826,6 +830,10 @@ Vec2F Monster::mouthPosition() const {
return mouthOffset() + position();
}
+Vec2F Monster::mouthPosition(bool) const {
+ return mouthPosition();
+}
+
List<ChatAction> Monster::pullPendingChatActions() {
return std::move(m_pendingChatActions);
}
diff --git a/source/game/StarMonster.hpp b/source/game/StarMonster.hpp
index 891c12d..ea95521 100644
--- a/source/game/StarMonster.hpp
+++ b/source/game/StarMonster.hpp
@@ -111,6 +111,7 @@ public:
Maybe<String> statusText() const override;
bool displayNametag() const override;
Vec3B nametagColor() const override;
+ Vec2F nametagOrigin() const override;
bool aggressive() const override;
@@ -118,6 +119,7 @@ public:
Maybe<LuaValue> evalScript(String const& code) override;
virtual Vec2F mouthPosition() const override;
+ virtual Vec2F mouthPosition(bool ignoreAdjustments) const override;
virtual List<ChatAction> pullPendingChatActions() override;
List<PhysicsForceRegion> forceRegions() const override;
diff --git a/source/game/StarNpc.cpp b/source/game/StarNpc.cpp
index b7a07ae..bdeb7b5 100644
--- a/source/game/StarNpc.cpp
+++ b/source/game/StarNpc.cpp
@@ -216,9 +216,9 @@ RectF Npc::metaBoundBox() const {
return RectF(-4, -4, 4, 4);
}
-Vec2F Npc::mouthOffset() const {
- return Vec2F{m_humanoid.mouthOffset(true)[0] * numericalDirection(m_humanoid.facingDirection()),
- m_humanoid.mouthOffset(true)[1]};
+Vec2F Npc::mouthOffset(bool ignoreAdjustments) const {
+ return Vec2F{m_humanoid.mouthOffset(ignoreAdjustments)[0] * numericalDirection(m_humanoid.facingDirection()),
+ m_humanoid.mouthOffset(ignoreAdjustments)[1]};
}
Vec2F Npc::feetOffset() const {
@@ -508,6 +508,10 @@ Vec3B Npc::nametagColor() const {
return m_npcVariant.nametagColor;
}
+Vec2F Npc::nametagOrigin() const {
+ return mouthPosition(false);
+}
+
bool Npc::aggressive() const {
return m_aggressive.get();
}
@@ -804,7 +808,11 @@ void Npc::getNetStates(bool initial) {
}
Vec2F Npc::mouthPosition() const {
- return mouthOffset() + position();
+ return mouthOffset(true) + position();
+}
+
+Vec2F Npc::mouthPosition(bool ignoreAdjustments) const {
+ return mouthOffset(ignoreAdjustments) + position();
}
List<ChatAction> Npc::pullPendingChatActions() {
diff --git a/source/game/StarNpc.hpp b/source/game/StarNpc.hpp
index 854eea6..193ffce 100644
--- a/source/game/StarNpc.hpp
+++ b/source/game/StarNpc.hpp
@@ -57,7 +57,7 @@ public:
Vec2F position() const override;
RectF metaBoundBox() const override;
- Vec2F mouthOffset() const;
+ Vec2F mouthOffset(bool ignoreAdjustments = true) const;
Vec2F feetOffset() const;
Vec2F headArmorOffset() const;
Vec2F chestArmorOffset() const;
@@ -105,6 +105,7 @@ public:
Maybe<String> statusText() const override;
bool displayNametag() const override;
Vec3B nametagColor() const override;
+ Vec2F nametagOrigin() const override;
bool aggressive() const;
@@ -112,6 +113,7 @@ public:
Maybe<LuaValue> evalScript(String const& code) override;
Vec2F mouthPosition() const override;
+ Vec2F mouthPosition(bool ignoreAdjustments) const override;
List<ChatAction> pullPendingChatActions() override;
bool isInteractive() const override;
diff --git a/source/game/StarObject.cpp b/source/game/StarObject.cpp
index 43a8574..dc19d74 100644
--- a/source/game/StarObject.cpp
+++ b/source/game/StarObject.cpp
@@ -1193,6 +1193,10 @@ Vec2F Object::mouthPosition() const {
}
}
+Vec2F Object::mouthPosition(bool) const {
+ return mouthPosition();
+}
+
List<ChatAction> Object::pullPendingChatActions() {
return std::move(m_pendingChatActions);
}
diff --git a/source/game/StarObject.hpp b/source/game/StarObject.hpp
index eb039e8..de3f370 100644
--- a/source/game/StarObject.hpp
+++ b/source/game/StarObject.hpp
@@ -114,6 +114,7 @@ public:
Maybe<LuaValue> evalScript(String const& code) override;
virtual Vec2F mouthPosition() const override;
+ virtual Vec2F mouthPosition(bool ignoreAdjustments) const override;
virtual List<ChatAction> pullPendingChatActions() override;
void breakObject(bool smash = true);
diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp
index bb47704..3eb464b 100644
--- a/source/game/StarPlayer.cpp
+++ b/source/game/StarPlayer.cpp
@@ -580,9 +580,9 @@ Vec2F Player::velocity() const {
return m_movementController->velocity();
}
-Vec2F Player::mouthOffset() const {
+Vec2F Player::mouthOffset(bool ignoreAdjustments) const {
return Vec2F(
- m_humanoid->mouthOffset(true)[0] * numericalDirection(facingDirection()), m_humanoid->mouthOffset(true)[1]);
+ m_humanoid->mouthOffset(ignoreAdjustments)[0] * numericalDirection(facingDirection()), m_humanoid->mouthOffset(ignoreAdjustments)[1]);
}
Vec2F Player::feetOffset() const {
@@ -610,7 +610,11 @@ Vec2F Player::legsArmorOffset() const {
}
Vec2F Player::mouthPosition() const {
- return position() + mouthOffset();
+ return position() + mouthOffset(true);
+}
+
+Vec2F Player::mouthPosition(bool ignoreAdjustments) const {
+ return position() + mouthOffset(ignoreAdjustments);
}
RectF Player::collisionArea() const {
@@ -1933,6 +1937,10 @@ Vec3B Player::nametagColor() const {
return jsonToVec3B(assets->json("/player.config:nametagColor"));
}
+Vec2F Player::nametagOrigin() const {
+ return mouthPosition(false);
+}
+
void Player::setBodyDirectives(String const& directives) {
m_identity.bodyDirectives = directives;
m_identityUpdated = true;
diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp
index 30238c4..b4fe623 100644
--- a/source/game/StarPlayer.hpp
+++ b/source/game/StarPlayer.hpp
@@ -86,7 +86,8 @@ public:
Vec2F velocity() const override;
Vec2F mouthPosition() const override;
- Vec2F mouthOffset() const;
+ Vec2F mouthPosition(bool ignoreAdjustments) const override;
+ Vec2F mouthOffset(bool ignoreAdjustments = true) const;
Vec2F feetOffset() const;
Vec2F headArmorOffset() const;
Vec2F chestArmorOffset() const;
@@ -284,6 +285,7 @@ public:
Maybe<String> statusText() const override;
bool displayNametag() const override;
Vec3B nametagColor() const override;
+ Vec2F nametagOrigin() const override;
void setBodyDirectives(String const& directives);
void setHairType(String const& group, String const& type);
diff --git a/source/game/interfaces/StarChattyEntity.hpp b/source/game/interfaces/StarChattyEntity.hpp
index 57c590a..03c1ac9 100644
--- a/source/game/interfaces/StarChattyEntity.hpp
+++ b/source/game/interfaces/StarChattyEntity.hpp
@@ -10,7 +10,8 @@ STAR_CLASS(ChattyEntity);
class ChattyEntity : public virtual Entity {
public:
- virtual Vec2F mouthPosition() const = 0;
+ virtual Vec2F mouthPosition() const { return mouthPosition(true); };
+ virtual Vec2F mouthPosition(bool) const = 0;
virtual List<ChatAction> pullPendingChatActions() = 0;
};
diff --git a/source/game/interfaces/StarNametagEntity.hpp b/source/game/interfaces/StarNametagEntity.hpp
index c9a9008..02aa643 100644
--- a/source/game/interfaces/StarNametagEntity.hpp
+++ b/source/game/interfaces/StarNametagEntity.hpp
@@ -13,6 +13,7 @@ public:
virtual Maybe<String> statusText() const = 0;
virtual bool displayNametag() const = 0;
virtual Vec3B nametagColor() const = 0;
+ virtual Vec2F nametagOrigin() const = 0;
};
}