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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Krasheninnikov <boba09@list.ru>2025-03-16 12:49:29 +0100
committerVladimir Krasheninnikov <boba09@list.ru>2025-03-16 12:49:29 +0100
commite8309c463d58b2ff8aab2e14a5b1e5f5065cecda (patch)
tree005e6a4915092ff9c9e861638ae9c076cf9077ed
parent76d4ddd57c65269052c4784e5ffa94bfb574c6ba (diff)
parent6f51c2c129ab50872a4944e5218fcf97f89abb1d (diff)
Merge branch 'main' of https://github.com/KrashV/OpenStarbound
-rw-r--r--doc/lua/openstarbound/root.md4
-rw-r--r--source/CMakeLists.txt4
-rw-r--r--source/game/StarArmorWearer.cpp2
-rw-r--r--source/game/StarHumanoid.cpp112
-rw-r--r--source/game/StarHumanoid.hpp9
-rw-r--r--source/game/StarPlayerStorage.cpp13
-rw-r--r--source/game/scripting/StarRootLuaBindings.cpp5
7 files changed, 110 insertions, 39 deletions
diff --git a/doc/lua/openstarbound/root.md b/doc/lua/openstarbound/root.md
index e87a0fe..1009c8f 100644
--- a/doc/lua/openstarbound/root.md
+++ b/doc/lua/openstarbound/root.md
@@ -61,6 +61,10 @@ Returns the asset source path of an asset, or nil if the asset doesn't exist. If
Without metadata: Returns an array with all the asset source paths.
With metadata: Returns a table, key/value being source path/metadata.
+#### `Json` root.assetSourceMetadata(`String` path)
+
+Returns the metadata of an asset source.
+
#### `Image` root.assetImage(`String` image)
Returns an image.
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 131c6ad..98b9c6c 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -297,8 +297,8 @@ if(STAR_COMPILER_GNU)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
elseif(STAR_COMPILER_CLANG)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wuninitialized -Wno-parentheses-equality -Wno-deprecated-declarations")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wextra -Wuninitialized -Wno-parentheses-equality -Wno-deprecated-declarations")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wuninitialized -Wno-parentheses-equality -Wno-deprecated-declarations -Wno-nan-infinity-disabled")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wextra -Wuninitialized -Wno-parentheses-equality -Wno-deprecated-declarations -Wno-nan-infinity-disabled")
if(STAR_SYSTEM_MACOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
diff --git a/source/game/StarArmorWearer.cpp b/source/game/StarArmorWearer.cpp
index c95eaad..ef67686 100644
--- a/source/game/StarArmorWearer.cpp
+++ b/source/game/StarArmorWearer.cpp
@@ -100,10 +100,12 @@ void ArmorWearer::setupHumanoidClothingDrawables(Humanoid& humanoid, bool forceN
if (backNeedsSync) {
humanoid.setBackArmorFrameset(backArmor->frameset(humanoid.identity().gender));
humanoid.setBackArmorDirectives(backArmor->directives());
+ humanoid.setBackRotatesWithHead(backArmor->instanceValue("rotateWithHead", false).optBool().value());
}
bodyHidden = bodyHidden || backArmor->hideBody();
} else {
humanoid.setBackArmorFrameset("");
+ humanoid.setBackRotatesWithHead(false);
}
if (chestNeedsSync || legsNeedsSync) {
diff --git a/source/game/StarHumanoid.cpp b/source/game/StarHumanoid.cpp
index f3ac164..b56c432 100644
--- a/source/game/StarHumanoid.cpp
+++ b/source/game/StarHumanoid.cpp
@@ -258,6 +258,7 @@ Humanoid::Humanoid(Json const& config) {
m_primaryHand.holdingItem = false;
m_altHand.holdingItem = false;
+ m_backRotatesWithHead = false;
m_movingBackwards = false;
m_altHand.angle = 0;
m_facingDirection = Direction::Left;
@@ -288,6 +289,12 @@ void Humanoid::setIdentity(HumanoidIdentity const& identity) {
m_backArmFrameset = getBackArmFromIdentity();
m_frontArmFrameset = getFrontArmFromIdentity();
m_vaporTrailFrameset = getVaporTrailFrameset();
+ if (m_useBodyMask) {
+ m_bodyMaskFrameset = getBodyMaskFromIdentity();
+ }
+ if (m_useBodyHeadMask) {
+ m_bodyHeadMaskFrameset = getBodyHeadMaskFromIdentity();
+ }
}
HumanoidIdentity const& Humanoid::identity() const {
@@ -317,6 +324,8 @@ void Humanoid::loadConfig(Json merger) {
m_feetOffset = jsonToVec2F(config.get("feetOffset")) / TilePixels;
m_bodyFullbright = config.getBool("bodyFullbright", false);
+ m_useBodyMask = config.getBool("useBodyMask", false);
+ m_useBodyHeadMask = config.getBool("useBodyHeadMask", false);
m_headArmorOffset = jsonToVec2F(config.get("headArmorOffset")) / TilePixels;
m_chestArmorOffset = jsonToVec2F(config.get("chestArmorOffset")) / TilePixels;
@@ -470,6 +479,10 @@ void Humanoid::setHeadRotation(float headRotation) {
m_headRotationTarget = headRotation;
}
+void Humanoid::setBackRotatesWithHead(bool backRotatesWithHead) {
+ m_backRotatesWithHead = backRotatesWithHead;
+}
+
void Humanoid::setRotation(float rotation) {
m_rotation = rotation;
}
@@ -606,11 +619,12 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
if (backHand.recoil)
backArmFrameOffset += m_recoilOffset;
- auto addDrawable = [&](Drawable drawable, bool forceFullbright = false) {
+ auto addDrawable = [&](Drawable drawable, bool forceFullbright = false) -> Drawable& {
if (m_facingDirection == Direction::Left)
drawable.scale(Vec2F(-1, 1));
drawable.fullbright |= forceFullbright;
drawables.append(std::move(drawable));
+ return drawables.back();
};
auto backArmDrawable = [&](String const& frameSet, Directives const& directives) -> Drawable {
@@ -621,6 +635,35 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
return backArm;
};
+ Vec2F headPosition(0, bobYOffset);
+ if (dance.isValid())
+ headPosition += danceStep->headOffset / TilePixels;
+ else if (m_state == Idle)
+ headPosition += m_identity.personality.headOffset / TilePixels;
+ else if (m_state == Run)
+ headPosition += m_headRunOffset;
+ else if (m_state == Swim || m_state == SwimIdle)
+ headPosition += m_headSwimOffset;
+ else if (m_state == Duck)
+ headPosition += m_headDuckOffset;
+ else if (m_state == Sit)
+ headPosition += m_headSitOffset;
+ else if (m_state == Lay)
+ headPosition += m_headLayOffset;
+
+ auto applyHeadRotation = [&](Drawable& drawable) {
+ if (m_headRotation != 0.f) {
+ float dir = numericalDirection(m_facingDirection);
+ Vec2F rotationPoint = headPosition;
+ rotationPoint[0] *= dir;
+ rotationPoint[1] -= .25f;
+ float headX = (m_headRotation / ((float)Constants::pi * 2.f));
+ drawable.rotate(m_headRotation, rotationPoint);
+ drawable.position[0] -= state() == State::Run ? (fmaxf(headX * dir, 0.f) * 2.f) * dir : headX;
+ drawable.position[1] -= fabsf(m_headRotation / ((float)Constants::pi * 4.f));
+ }
+ };
+
if (!m_backArmorFrameset.empty()) {
auto frameGroup = frameBase(m_state);
auto prefix = m_backArmorDirectives.prefix();
@@ -636,7 +679,9 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, Vec2F());
drawable.imagePart().addDirectives(getBackDirectives(), true);
- addDrawable(std::move(drawable));
+ Drawable& applied = addDrawable(std::move(drawable));
+ if (m_backRotatesWithHead)
+ applyHeadRotation(applied);
}
if (backHand.holdingItem && !dance.isValid() && withItems) {
@@ -695,36 +740,11 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
}
}
- Vec2F headPosition(0, bobYOffset);
- if (dance.isValid())
- headPosition += danceStep->headOffset / TilePixels;
- else if (m_state == Idle)
- headPosition += m_identity.personality.headOffset / TilePixels;
- else if (m_state == Run)
- headPosition += m_headRunOffset;
- else if (m_state == Swim || m_state == SwimIdle)
- headPosition += m_headSwimOffset;
- else if (m_state == Duck)
- headPosition += m_headDuckOffset;
- else if (m_state == Sit)
- headPosition += m_headSitOffset;
- else if (m_state == Lay)
- headPosition += m_headLayOffset;
-
auto addHeadDrawable = [&](Drawable drawable, bool forceFullbright = false) {
if (m_facingDirection == Direction::Left)
drawable.scale(Vec2F(-1, 1));
drawable.fullbright |= forceFullbright;
- if (m_headRotation != 0.f) {
- float dir = numericalDirection(m_facingDirection);
- Vec2F rotationPoint = headPosition;
- rotationPoint[0] *= dir;
- rotationPoint[1] -= .25f;
- float headX = (m_headRotation / ((float)Constants::pi * 2.f));
- drawable.rotate(m_headRotation, rotationPoint);
- drawable.position[0] -= state() == State::Run ? (fmaxf(headX * dir, 0.f) * 2.f) * dir : headX;
- drawable.position[1] -= fabsf(m_headRotation / ((float)Constants::pi * 4.f));
- }
+ applyHeadRotation(drawable);
drawables.append(std::move(drawable));
};
@@ -751,18 +771,32 @@ List<Drawable> Humanoid::render(bool withItems, bool withRotationAndScale) {
}
if (!m_bodyFrameset.empty() && !m_bodyHidden) {
- String image;
auto bodyDirectives = getBodyDirectives();
auto prefix = bodyDirectives.prefix();
+ String frameName;
if (dance.isValid() && danceStep->bodyFrame)
- image = strf("{}:{}{}", m_bodyFrameset, *danceStep->bodyFrame, prefix);
+ frameName = strf("{}{}", *danceStep->bodyFrame, prefix);
else if (m_state == Idle)
- image = strf("{}:{}{}", m_bodyFrameset, m_identity.personality.idle, prefix);
+ frameName = strf("{}{}", m_identity.personality.idle, prefix);
else
- image = strf("{}:{}.{}{}", m_bodyFrameset, frameBase(m_state), bodyStateSeq, prefix);
- auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, {});
+ frameName = strf("{}.{}{}", frameBase(m_state), bodyStateSeq, prefix);
+ String image = strf("{}:{}",m_bodyFrameset,frameName);
+ auto drawable = Drawable::makeImage(m_useBodyHeadMask ? image : std::move(image), 1.0f / TilePixels, true, {});
drawable.imagePart().addDirectives(bodyDirectives, true);
+ if (m_useBodyMask && !m_bodyMaskFrameset.empty()) {
+ String maskImage = strf("{}:{}",m_bodyMaskFrameset,frameName);
+ Directives maskDirectives = "?addmask="+maskImage+";0;0";
+ drawable.imagePart().addDirectives(maskDirectives, true);
+ }
addDrawable(std::move(drawable), m_bodyFullbright);
+ if (m_useBodyHeadMask && !m_bodyHeadMaskFrameset.empty()) {
+ String maskImage = strf("{}:{}",m_bodyHeadMaskFrameset,frameName);
+ Directives maskDirectives = "?addmask="+maskImage+";0;0";
+ auto drawable = Drawable::makeImage(std::move(image), 1.0f / TilePixels, true, {});
+ drawable.imagePart().addDirectives(bodyDirectives, true);
+ drawable.imagePart().addDirectives(maskDirectives, true);
+ addHeadDrawable(std::move(drawable), m_bodyFullbright);
+ }
}
if (!m_legsArmorFrameset.empty()) {
@@ -1275,6 +1309,18 @@ String Humanoid::getBodyFromIdentity() const {
GenderNames.getRight(m_identity.gender));
}
+String Humanoid::getBodyMaskFromIdentity() const {
+ return strf("/humanoid/{}/mask/{}body.png",
+ m_identity.imagePath ? *m_identity.imagePath : m_identity.species,
+ GenderNames.getRight(m_identity.gender));
+}
+
+String Humanoid::getBodyHeadMaskFromIdentity() const {
+ return strf("/humanoid/{}/headmask/{}body.png",
+ m_identity.imagePath ? *m_identity.imagePath : m_identity.species,
+ GenderNames.getRight(m_identity.gender));
+}
+
String Humanoid::getFacialEmotesFromIdentity() const {
return strf("/humanoid/{}/emote.png", m_identity.imagePath ? *m_identity.imagePath : m_identity.species);
}
diff --git a/source/game/StarHumanoid.hpp b/source/game/StarHumanoid.hpp
index d11de1d..a3e9d19 100644
--- a/source/game/StarHumanoid.hpp
+++ b/source/game/StarHumanoid.hpp
@@ -178,6 +178,7 @@ public:
void setFacingDirection(Direction facingDirection);
void setMovingBackwards(bool movingBackwards);
void setHeadRotation(float headRotation);
+ void setBackRotatesWithHead(bool backRotatesWithHead);
void setRotation(float rotation);
void setScale(Vec2F scale);
@@ -262,6 +263,8 @@ public:
String getHeadFromIdentity() const;
String getBodyFromIdentity() const;
+ String getBodyMaskFromIdentity() const;
+ String getBodyHeadMaskFromIdentity() const;
String getFacialEmotesFromIdentity() const;
String getHairFromIdentity() const;
String getFacialHairFromIdentity() const;
@@ -329,6 +332,9 @@ private:
Vec2F m_chestArmorOffset;
Vec2F m_legsArmorOffset;
Vec2F m_backArmorOffset;
+
+ bool m_useBodyMask;
+ bool m_useBodyHeadMask;
bool m_bodyHidden;
@@ -345,6 +351,8 @@ private:
String m_headFrameset;
String m_bodyFrameset;
+ String m_bodyMaskFrameset;
+ String m_bodyHeadMaskFrameset;
String m_backArmFrameset;
String m_frontArmFrameset;
String m_emoteFrameset;
@@ -375,6 +383,7 @@ private:
Maybe<String> m_dance;
Direction m_facingDirection;
bool m_movingBackwards;
+ bool m_backRotatesWithHead;
float m_headRotation;
float m_headRotationTarget;
float m_rotation;
diff --git a/source/game/StarPlayerStorage.cpp b/source/game/StarPlayerStorage.cpp
index bba080e..7687e97 100644
--- a/source/game/StarPlayerStorage.cpp
+++ b/source/game/StarPlayerStorage.cpp
@@ -41,9 +41,12 @@ PlayerStorage::PlayerStorage(String const& storageDir) {
try {
auto json = VersionedJson::readFile(filename);
Uuid uuid(json.content.getString("uuid"));
- auto& playerCacheData = m_savedPlayersCache[uuid];
- playerCacheData = entityFactory->loadVersionedJson(json, EntityType::Player);
- m_playerFileNames.insert(uuid, file.first.rsplit('.', 1).at(0));
+ if (m_playerFileNames.insert(uuid, file.first.rsplit('.', 1).at(0))) {
+ auto& playerCacheData = m_savedPlayersCache[uuid];
+ playerCacheData = entityFactory->loadVersionedJson(json, EntityType::Player);
+ } else {
+ Logger::warn("Duplicate player? Skipping player file {} because it has the same UUID as {}.player ({})", file.first, m_playerFileNames.getRight(uuid), uuid.hex());
+ }
} catch (std::exception const& e) {
Logger::error("Error loading player file, ignoring! {} : {}", filename, outputException(e, false));
}
@@ -168,7 +171,9 @@ Json PlayerStorage::savePlayer(PlayerPtr const& player) {
if (playerCacheData != newPlayerData) {
playerCacheData = newPlayerData;
VersionedJson versionedJson = entityFactory->storeVersionedJson(EntityType::Player, playerCacheData);
- VersionedJson::writeFile(versionedJson, File::relativeTo(m_storageDirectory, strf("{}.player", uuidFileName(uuid))));
+ auto fileName = strf("{}.player", uuidFileName(uuid));
+ VersionedJson::writeFile(versionedJson, File::relativeTo(m_storageDirectory, fileName));
+ Logger::info("Saved player {} to {}", Text::stripEscapeCodes(player->name()), fileName);
}
return newPlayerData;
}
diff --git a/source/game/scripting/StarRootLuaBindings.cpp b/source/game/scripting/StarRootLuaBindings.cpp
index b7c9a74..c45ef46 100644
--- a/source/game/scripting/StarRootLuaBindings.cpp
+++ b/source/game/scripting/StarRootLuaBindings.cpp
@@ -116,6 +116,11 @@ LuaCallbacks LuaBindings::makeRootCallbacks() {
return table;
});
+ callbacks.registerCallback("assetSourceMetadata", [root](LuaEngine& engine, String const& assetSourcePath) {
+ auto assets = root->assets();
+ return assets->assetSourceMetadata(assetSourcePath);
+ });
+
callbacks.registerCallback("itemFile", [root](LuaEngine& engine, String const& itemName) -> Maybe<String> {
return root->itemDatabase()->itemFile(itemName);
});