diff options
author | WasabiRaptor <ketchupraptor@gmail.com> | 2025-05-18 20:05:41 -0400 |
---|---|---|
committer | WasabiRaptor <ketchupraptor@gmail.com> | 2025-05-18 20:05:41 -0400 |
commit | 0bf17a8dc4a4e7c7c1b763a2e12ac0de27caff1a (patch) | |
tree | d29eb44ec5e7887fe1a2ab521254ff0230b5ba2f | |
parent | da281a0c5286014f952b5a8ce2f346f99c114089 (diff) |
big feature expansion
-rw-r--r-- | source/base/StarAnimatedPartSet.cpp | 138 | ||||
-rw-r--r-- | source/base/StarAnimatedPartSet.hpp | 28 | ||||
-rw-r--r-- | source/core/StarDataStream.cpp | 2 | ||||
-rw-r--r-- | source/core/StarNetCompatibility.cpp | 4 | ||||
-rw-r--r-- | source/game/StarNetworkedAnimator.cpp | 265 | ||||
-rw-r--r-- | source/game/StarNetworkedAnimator.hpp | 43 | ||||
-rw-r--r-- | source/game/scripting/StarNetworkedAnimatorLuaBindings.cpp | 39 | ||||
-rw-r--r-- | source/game/scripting/StarScriptedAnimatorLuaBindings.cpp | 58 | ||||
-rw-r--r-- | source/game/scripting/StarScriptedAnimatorLuaBindings.hpp | 2 |
9 files changed, 540 insertions, 39 deletions
diff --git a/source/base/StarAnimatedPartSet.cpp b/source/base/StarAnimatedPartSet.cpp index 5ffc68f..9e5f816 100644 --- a/source/base/StarAnimatedPartSet.cpp +++ b/source/base/StarAnimatedPartSet.cpp @@ -1,11 +1,12 @@ #include "StarAnimatedPartSet.hpp" #include "StarMathCommon.hpp" +#include "StarJsonExtra.hpp" namespace Star { AnimatedPartSet::AnimatedPartSet() {} -AnimatedPartSet::AnimatedPartSet(Json config) { +AnimatedPartSet::AnimatedPartSet(Json config, uint8_t animatorVersion) { for (auto const& stateTypePair : config.get("stateTypes", JsonObject()).iterateObject()) { auto const& stateTypeName = stateTypePair.first; auto const& stateTypeConfig = stateTypePair.second; @@ -33,6 +34,7 @@ AnimatedPartSet::AnimatedPartSet(Json config) { newStateType.states.sortByKey(); newStateType.activeState.stateTypeName = stateTypeName; + newStateType.activeState.reverse = false; newStateType.activeStateDirty = true; if (newStateType.defaultState.empty() && !newStateType.states.empty()) @@ -65,6 +67,7 @@ AnimatedPartSet::AnimatedPartSet(Json config) { } } newPart.activePart.partName = partPair.first; + newPart.activePart.setAnimationAffineTransform(Mat3F::identity()); newPart.activePartDirty = true; m_parts[partName] = std::move(newPart); @@ -110,11 +113,12 @@ StringList AnimatedPartSet::partNames() const { return m_parts.keys(); } -bool AnimatedPartSet::setActiveState(String const& stateTypeName, String const& stateName, bool alwaysStart) { +bool AnimatedPartSet::setActiveState(String const& stateTypeName, String const& stateName, bool alwaysStart, bool reverse) { auto& stateType = m_stateTypes.get(stateTypeName); - if (stateType.activeState.stateName != stateName || alwaysStart) { + if (stateType.activeState.stateName != stateName || alwaysStart || stateType.activeState.reverse != reverse) { stateType.activeState.stateName = stateName; stateType.activeState.timer = 0.0f; + stateType.activeState.frameProgress = 0.0f; stateType.activeStatePointer = stateType.states.get(stateName).get(); stateType.activeStateDirty = true; @@ -174,11 +178,15 @@ size_t AnimatedPartSet::activeStateIndex(String const& stateTypeName) const { auto const& stateType = m_stateTypes.get(stateTypeName); return *stateType.states.indexOf(stateType.activeState.stateName); } +bool AnimatedPartSet::activeStateReverse(String const& stateTypeName) const { + auto const& stateType = m_stateTypes.get(stateTypeName); + return stateType.activeState.reverse; +} -bool AnimatedPartSet::setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart) { +bool AnimatedPartSet::setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart, bool reverse) { auto const& stateType = m_stateTypes.get(stateTypeName); String const& stateName = stateType.states.keyAt(stateIndex); - return setActiveState(stateTypeName, stateName, alwaysStart); + return setActiveState(stateTypeName, stateName, alwaysStart, reverse); } void AnimatedPartSet::update(float dt) { @@ -247,15 +255,40 @@ void AnimatedPartSet::freshenActiveState(StateType& stateType) { if (stateType.activeStateDirty) { auto const& state = *stateType.activeStatePointer; auto& activeState = stateType.activeState; - activeState.frame = clamp<int>(activeState.timer / state.cycle * state.frames, 0, state.frames - 1); + + double progress = (activeState.timer / state.cycle * state.frames); + activeState.frameProgress = std::fmod(progress, 1); + activeState.frame = clamp<int>(progress, 0, state.frames - 1); + if (activeState.reverse) { + activeState.frame = (state.frames - 1) - activeState.frame; + if (state.animationMode == Loop) + if (activeState.frame <= 0 ) { + activeState.nextFrame = state.frames - 1; + } else { + activeState.nextFrame = clamp<int>(activeState.frame - 1, 0, state.frames - 1); + } + } else { + if (state.animationMode == Loop) + if (activeState.frame >= (state.frames-1) ) { + activeState.nextFrame = 0; + } else { + activeState.nextFrame = clamp<int>(activeState.frame + 1, 0, state.frames - 1); + } + } activeState.properties = stateType.stateTypeProperties; activeState.properties.merge(state.stateProperties, true); + activeState.nextProperties = activeState.properties; + for (auto const& pair : state.stateFrameProperties) { if (activeState.frame < pair.second.size()) activeState.properties[pair.first] = pair.second.get(activeState.frame); } + for (auto const& pair : state.stateFrameProperties) { + if (activeState.nextFrame < pair.second.size()) + activeState.nextProperties[pair.first] = pair.second.get(activeState.nextFrame); + } stateType.activeStateDirty = false; } @@ -292,16 +325,73 @@ void AnimatedPartSet::freshenActivePart(Part& part) { freshenActiveState(stateType); activePart.activeState = stateType.activeState; unsigned frame = stateType.activeState.frame; + unsigned nextFrame = stateType.activeState.nextFrame; // Then set the part state data, as well as any part state frame data if // the current frame is within the list size. activePart.properties.merge(partState->partStateProperties, true); + activePart.nextProperties = activePart.properties; for (auto const& pair : partState->partStateFrameProperties) { if (frame < pair.second.size()) activePart.properties[pair.first] = pair.second.get(frame); } + for (auto const& pair : partState->partStateFrameProperties) { + if (nextFrame< pair.second.size()) + activePart.nextProperties[pair.first] = pair.second.get(nextFrame); + } + if (version() > 0) { + auto processTransforms = [](Mat3F mat, JsonArray transforms, JsonObject properties) -> Mat3F { + for (auto const& v : transforms) { + auto actionData = v.toArray(); + auto action = actionData[0].toString(); + if (action == "reset") { + mat = Mat3F::identity(); + } else if (action == "translate") { + mat.translate(jsonToVec2F(actionData[1])); + } else if (action == "rotate") { + if (auto center = actionData[2]) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("rotationCenter")) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("center")) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else { + mat.rotate(actionData[1].toFloat()); + } + } else if (action == "scale") { + if (auto center = actionData[2]) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("scaleCenter")) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("center")) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else { + mat.scale(actionData[1].toFloat()); + } + } else if (action == "transform") { + mat = Mat3F(actionData[1].toFloat(), actionData[2].toFloat(), actionData[3].toFloat(), actionData[4].toFloat(), actionData[5].toFloat(), actionData[6].toFloat(), 0, 0, 1) * mat; + } + } + return mat; + }; + + + if (auto transforms = activePart.properties.ptr("transforms")) { + auto mat = processTransforms(activePart.animationAffineTransform(), transforms->toArray(), activePart.properties); + if (activePart.properties.value("interpolated").optBool().value(false)) { + if (auto nextTransforms = activePart.nextProperties.ptr("transforms")) { + auto nextMat = processTransforms(activePart.animationAffineTransform(), nextTransforms->toArray(), activePart.nextProperties); + activePart.setAnimationAffineTransform(mat, nextMat, stateType.activeState.frameProgress); + } else { + activePart.setAnimationAffineTransform(mat); + } + } else { + activePart.setAnimationAffineTransform(mat); + } + } + } // Each part can only have one state type x state match, so we are done. break; } @@ -310,4 +400,40 @@ void AnimatedPartSet::freshenActivePart(Part& part) { } } +void AnimatedPartSet::ActivePartInformation::setAnimationAffineTransform(Mat3F const& matrix) { + xTranslationAnimation = matrix[0][2]; + yTranslationAnimation = matrix[1][2]; + xScaleAnimation = sqrt(square(matrix[0][0]) + square(matrix[0][1])); + yScaleAnimation = sqrt(square(matrix[1][0]) + square(matrix[1][1])); + xShearAnimation = atan2(matrix[0][1], matrix[0][0]); + yShearAnimation = atan2(matrix[1][0], matrix[1][1]); +} +void AnimatedPartSet::ActivePartInformation::setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress) { + xTranslationAnimation = mat1[0][2]; + yTranslationAnimation = mat1[1][2]; + xScaleAnimation = sqrt(square(mat1[0][0]) + square(mat1[0][1])); + yScaleAnimation = sqrt(square(mat1[1][0]) + square(mat1[1][1])); + xShearAnimation = atan2(mat1[0][1], mat1[0][0]); + yShearAnimation = atan2(mat1[1][0], mat1[1][1]); + + xTranslationAnimation += (mat2[0][2] - xTranslationAnimation) * progress; + yTranslationAnimation += (mat2[1][2] - yTranslationAnimation) * progress; + xScaleAnimation += (sqrt(square(mat2[0][0]) + square(mat2[0][1])) - xScaleAnimation) * progress; + yScaleAnimation += (sqrt(square(mat2[1][0]) + square(mat2[1][1])) - yScaleAnimation) * progress; + xShearAnimation += (atan2(mat2[0][1], mat2[0][0]) - xShearAnimation) * progress; + yShearAnimation += (atan2(mat2[1][0], mat2[1][1]) - yShearAnimation) * progress; +} + +Mat3F AnimatedPartSet::ActivePartInformation::animationAffineTransform() const { + return Mat3F( + xScaleAnimation * cos(xShearAnimation), xScaleAnimation * sin(xShearAnimation), xTranslationAnimation, + yScaleAnimation * sin(yShearAnimation), yScaleAnimation * cos(yShearAnimation), yTranslationAnimation, + 0, 0, 1 + ); +} + +uint8_t AnimatedPartSet::version() const { + return m_animatorVersion; +} + } diff --git a/source/base/StarAnimatedPartSet.hpp b/source/base/StarAnimatedPartSet.hpp index a608924..43755be 100644 --- a/source/base/StarAnimatedPartSet.hpp +++ b/source/base/StarAnimatedPartSet.hpp @@ -2,6 +2,7 @@ #include "StarOrderedMap.hpp" #include "StarJson.hpp" +#include "StarMatrix3.hpp" namespace Star { @@ -46,7 +47,11 @@ public: String stateName; float timer; unsigned frame; + float frameProgress; JsonObject properties; + bool reverse; + unsigned nextFrame; + JsonObject nextProperties; }; struct ActivePartInformation { @@ -54,6 +59,18 @@ public: // If a state match is found, this will be set. Maybe<ActiveStateInformation> activeState; JsonObject properties; + JsonObject nextProperties; + + Mat3F animationAffineTransform() const; + void setAnimationAffineTransform(Mat3F const& matrix); + void setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress); + + float xTranslationAnimation; + float yTranslationAnimation; + float xScaleAnimation; + float yScaleAnimation; + float xShearAnimation; + float yShearAnimation; }; enum AnimationMode { @@ -97,7 +114,7 @@ public: }; AnimatedPartSet(); - AnimatedPartSet(Json config); + AnimatedPartSet(Json config, uint8_t animatiorVersion); // Returns the available state types. StringList stateTypes() const; @@ -118,7 +135,7 @@ public: // beginning. If alwaysStart is true, then starts the state animation off at // the beginning even if no state change has occurred. Returns true if a // state animation reset was done. - bool setActiveState(String const& stateTypeName, String const& stateName, bool alwaysStart = false); + bool setActiveState(String const& stateTypeName, String const& stateName, bool alwaysStart = false, bool reverse = false); // Restart this given state type's timer off at the beginning. void restartState(String const& stateTypeName); @@ -141,7 +158,8 @@ public: // state type is ordered, it is possible to simply serialize and deserialize // the state index for that state type. size_t activeStateIndex(String const& stateTypeName) const; - bool setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart = false); + bool activeStateReverse(String const& stateTypeName) const; + bool setActiveStateIndex(String const& stateTypeName, size_t stateIndex, bool alwaysStart = false, bool reverse = false); // Animate each state type forward 'dt' time, and either change state frames // or transition to new states, depending on the config. @@ -150,6 +168,8 @@ public: // Pushes all the animations into their final state void finishAnimations(); + uint8_t version() const; + private: static AnimationMode stringToAnimationMode(String const& string); @@ -158,6 +178,8 @@ private: OrderedHashMap<String, StateType> m_stateTypes; StringMap<Part> m_parts; + + uint8_t m_animatorVersion; }; } diff --git a/source/core/StarDataStream.cpp b/source/core/StarDataStream.cpp index 13bd2c0..1bc1071 100644 --- a/source/core/StarDataStream.cpp +++ b/source/core/StarDataStream.cpp @@ -6,7 +6,7 @@ namespace Star { -unsigned const CurrentStreamVersion = 7; // update OpenProtocolVersion too! +unsigned const CurrentStreamVersion = 8; // update OpenProtocolVersion too! DataStream::DataStream() : m_byteOrder(ByteOrder::BigEndian), diff --git a/source/core/StarNetCompatibility.cpp b/source/core/StarNetCompatibility.cpp index 37eef95..87e2e1c 100644 --- a/source/core/StarNetCompatibility.cpp +++ b/source/core/StarNetCompatibility.cpp @@ -2,6 +2,6 @@ namespace Star { -VersionNumber const OpenProtocolVersion = 7; // update StreamCompatibilityVersion too! +VersionNumber const OpenProtocolVersion = 8; // update StreamCompatibilityVersion too! -}
\ No newline at end of file +} diff --git a/source/game/StarNetworkedAnimator.cpp b/source/game/StarNetworkedAnimator.cpp index a974a3a..396738c 100644 --- a/source/game/StarNetworkedAnimator.cpp +++ b/source/game/StarNetworkedAnimator.cpp @@ -87,8 +87,14 @@ NetworkedAnimator::NetworkedAnimator(Json config, String relativePath) : Network if (relativePath.empty()) relativePath = "/"; } + m_animatorVersion = config.getUInt("version", 0); - m_animatedParts = AnimatedPartSet(config.get("animatedParts", JsonObject())); + if (version() > 0) { + if (auto v = config.get("includes")) + config = mergeIncludes(config, v, relativePath); + } + + m_animatedParts = AnimatedPartSet(config.get("animatedParts", JsonObject()), version()); m_relativePath = AssetPath::directory(relativePath); for (auto const& pair : config.get("globalTagDefaults", JsonObject()).iterateObject()) @@ -103,6 +109,8 @@ NetworkedAnimator::NetworkedAnimator(Json config, String relativePath) : Network auto& tg = m_transformationGroups[pair.first]; tg.interpolated = pair.second.getBool("interpolated", false); tg.setAffineTransform(Mat3F::identity()); + tg.setAnimationAffineTransform(Mat3F::identity()); + tg.setLocalAffineTransform(Mat3F::identity()); } for (auto const& pair : config.get("rotationGroups", JsonObject()).iterateObject()) { @@ -294,8 +302,9 @@ StringList NetworkedAnimator::states(String const& stateType) const { return m_animatedParts.states(stateType); } -bool NetworkedAnimator::setState(String const& stateType, String const& state, bool startNew) { - if (m_animatedParts.setActiveState(stateType, state, startNew)) { +bool NetworkedAnimator::setState(String const& stateType, String const& state, bool startNew, bool reverse) { + if (m_animatedParts.setActiveState(stateType, state, startNew, reverse)) { + m_stateInfo[stateType].wasUpdated = true; m_stateInfo[stateType].startedEvent.trigger(); return true; } else { @@ -303,9 +312,25 @@ bool NetworkedAnimator::setState(String const& stateType, String const& state, b } } +bool NetworkedAnimator::setLocalState(String const& stateType, String const& state, bool startNew, bool reverse) { + return m_animatedParts.setActiveState(stateType, state, startNew, reverse); +} + String NetworkedAnimator::state(String const& stateType) const { return m_animatedParts.activeState(stateType).stateName; } +int NetworkedAnimator::stateFrame(String const& stateType) const { + return m_animatedParts.activeState(stateType).frame; +} +float NetworkedAnimator::stateFrameProgress(String const& stateType) const { + return m_animatedParts.activeState(stateType).frameProgress; +} +float NetworkedAnimator::stateTimer(String const& stateType) const { + return m_animatedParts.activeState(stateType).timer; +} +bool NetworkedAnimator::stateReverse(String const& stateType) const { + return m_animatedParts.activeState(stateType).reverse; +} StringMap<AnimatedPartSet::Part> const& NetworkedAnimator::constParts() const { return m_animatedParts.constParts(); @@ -337,7 +362,7 @@ Mat3F NetworkedAnimator::globalTransformation() const { Mat3F NetworkedAnimator::groupTransformation(StringList const& transformationGroups) const { auto mat = Mat3F::identity(); for (auto const& tg : transformationGroups) - mat = m_transformationGroups.get(tg).affineTransform() * mat; + mat = m_transformationGroups.get(tg).affineTransform() * m_transformationGroups.get(tg).localAffineTransform() * mat; return mat; } @@ -404,6 +429,13 @@ void NetworkedAnimator::setPartTag(String const& partType, String tagName, Strin m_partTags[partType].set(std::move(tagName), std::move(tagValue)); } +void NetworkedAnimator::setPartDrawables(String const& partName, List<Drawable> drawables) { + m_partDrawables.set(partName, drawables); +} +void NetworkedAnimator::addPartDrawables(String const& partName, List<Drawable> drawables) { + m_partDrawables.ptr(partName)->appendAll(drawables); +} + void NetworkedAnimator::setProcessingDirectives(Directives const& directives) { m_processingDirectives.set(directives); } @@ -485,6 +517,40 @@ void NetworkedAnimator::resetTransformationGroup(String const& transformationGro m_transformationGroups.get(transformationGroup).setAffineTransform(Mat3F::identity()); } +void NetworkedAnimator::translateLocalTransformationGroup(String const& transformationGroup, Vec2F const& translation) { + auto& group = m_transformationGroups.get(transformationGroup); + group.setLocalAffineTransform(Mat3F::translation(translation) * group.localAffineTransform()); +} + +void NetworkedAnimator::rotateLocalTransformationGroup( + String const& transformationGroup, float rotation, Vec2F const& rotationCenter) { + auto& group = m_transformationGroups.get(transformationGroup); + group.setLocalAffineTransform(Mat3F::rotation(rotation, rotationCenter) * group.localAffineTransform()); +} + +void NetworkedAnimator::scaleLocalTransformationGroup( + String const& transformationGroup, float scale, Vec2F const& scaleCenter) { + auto& group = m_transformationGroups.get(transformationGroup); + group.setLocalAffineTransform(Mat3F::scaling(scale, scaleCenter) * group.localAffineTransform()); +} + +void NetworkedAnimator::scaleLocalTransformationGroup( + String const& transformationGroup, Vec2F const& scale, Vec2F const& scaleCenter) { + auto& group = m_transformationGroups.get(transformationGroup); + group.setLocalAffineTransform(Mat3F::scaling(scale, scaleCenter) * group.localAffineTransform()); +} + +void NetworkedAnimator::transformLocalTransformationGroup( + String const& transformationGroup, float a, float b, float c, float d, float tx, float ty) { + auto& group = m_transformationGroups.get(transformationGroup); + Mat3F transform = Mat3F(a, b, tx, c, d, ty, 0, 0, 1); + group.setLocalAffineTransform(transform * group.localAffineTransform()); +} + +void NetworkedAnimator::resetLocalTransformationGroup(String const& transformationGroup) { + m_transformationGroups.get(transformationGroup).setLocalAffineTransform(Mat3F::identity()); +} + bool NetworkedAnimator::hasParticleEmitter(String const& emitterName) const { return m_particleEmitters.contains(emitterName); } @@ -602,9 +668,27 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& } } } + HashMap<String, String> animationTags = {}; + if (version() > 0) + m_animatedParts.forEachActiveState([&](String const& stateTypeName, AnimatedPartSet::ActiveStateInformation const& activeState) { + unsigned stateFrame = activeState.frame; + Maybe<unsigned> frame; + String frameStr; + String frameIndexStr; + + frame = stateFrame; + frameStr = static_cast<String>(toString(stateFrame + 1)); + frameIndexStr = static_cast<String>(toString(stateFrame)); + if (frame) { + animationTags.set(stateTypeName + "_frame", frameStr); + animationTags.set(stateTypeName + "_frameIndex", frameIndexStr); + } + animationTags.set(stateTypeName + "_state", activeState.stateName); + }); List<tuple<AnimatedPartSet::ActivePartInformation const*, String const*, float>> parts; parts.reserve(partCount); + int drawableCount = 0; m_animatedParts.forEachActivePart([&](String const& partName, AnimatedPartSet::ActivePartInformation const& activePart) { Maybe<float> maybeZLevel; if (m_flipped.get()) { @@ -614,13 +698,15 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& if (!maybeZLevel) maybeZLevel = activePart.properties.value("zLevel").optFloat(); + if (auto drawables = m_partDrawables.contains(partName)) + drawableCount += m_partDrawables.get(partName).size(); parts.append(make_tuple(&activePart, &partName, maybeZLevel.value(0.0f))); }); sort(parts, [](auto const& a, auto const& b) { return get<2>(a) < get<2>(b); }); List<pair<Drawable, float>> drawables; - drawables.reserve(partCount); + drawables.reserve(partCount + drawableCount); for (auto& entry : parts) { auto& activePart = *get<0>(entry); auto& partName = *get<1>(entry); @@ -633,7 +719,22 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& bool fullbright = activePart.properties.value("fullbright").optBool().value(false); size_t originalDirectivesSize = baseProcessingDirectives.size(); + + auto const& partTags = m_partTags.get(partName); + if (auto directives = activePart.properties.value("processingDirectives").optString()) { + if (version() > 0){ + directives = directives->maybeLookupTagsView([&](StringView tag) -> StringView { + if (auto p = animationTags.ptr(tag)) { + return StringView(*p); + } else if (auto p = partTags.ptr(tag)) { + return StringView(*p); + } else if (auto p = m_globalTags.ptr(tag)) { + return StringView(*p); + } + return StringView("default"); + }); + } baseProcessingDirectives.append(*directives); } @@ -647,11 +748,22 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& frameIndexStr = static_cast<String>(toString(stateFrame)); if (auto directives = activePart.activeState->properties.value("processingDirectives").optString()) { + if (version() > 0){ + directives = directives->maybeLookupTagsView([&](StringView tag) -> StringView { + if (auto p = animationTags.ptr(tag)) { + return StringView(*p); + } else if (auto p = partTags.ptr(tag)) { + return StringView(*p); + } else if (auto p = m_globalTags.ptr(tag)) { + return StringView(*p); + } + return StringView("default"); + }); + } baseProcessingDirectives.append(*directives); } } - auto const& partTags = m_partTags.get(partName); Maybe<String> processedImage = image.maybeLookupTagsView([&](StringView tag) -> StringView { if (tag == "frame") { if (frame) @@ -659,6 +771,8 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& } else if (tag == "frameIndex") { if (frame) return frameIndexStr; + } else if (auto p = animationTags.ptr(tag)) { + return StringView(*p); } else if (auto p = partTags.ptr(tag)) { return StringView(*p); } else if (auto p = m_globalTags.ptr(tag)) { @@ -669,6 +783,9 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& }); String const& usedImage = processedImage ? processedImage.get() : image; + auto transformation = globalTransformation() * partTransformation(partName); + transformation.translate(position); + if (!usedImage.empty() && usedImage[0] != ':' && usedImage[0] != '?') { size_t hash = hashOf(usedImage); auto find = m_cachedPartDrawables.find(partName); @@ -690,14 +807,19 @@ List<pair<Drawable, float>> NetworkedAnimator::drawablesWithZLevel(Vec2F const& auto& imagePart = drawable.imagePart(); for (Directives const& directives : baseProcessingDirectives) imagePart.addDirectives(directives, centered); - drawable.transform(partTransformation(partName)); - drawable.transform(globalTransformation()); drawable.fullbright = fullbright; - drawable.translate(position); - + drawable.transform(transformation); drawables.append({std::move(drawable), get<2>(entry)}); } - + + if (m_partDrawables.contains(partName)) { + auto partDrawables = m_partDrawables.get(partName); + Drawable::transformAll(partDrawables, transformation); + for (auto drawable : partDrawables) { + drawables.append({drawable, get<2>(entry)}); + } + } + baseProcessingDirectives.resize(originalDirectivesSize); } @@ -830,6 +952,60 @@ void NetworkedAnimator::update(float dt, DynamicTarget* dynamicTarget) { for (auto const& name : particleEmittersOff->iterateArray()) m_particleEmitters.get(name.toString()).active.set(false); } + + if (version() > 0){ + auto processTransforms = [](Mat3F mat, JsonArray transforms, JsonObject properties) -> Mat3F { + for (auto const& v : transforms) { + auto actionData = v.toArray(); + auto action = actionData[0].toString(); + if (action == "reset") { + mat = Mat3F::identity(); + } else if (action == "translate") { + mat.translate(jsonToVec2F(actionData[1])); + } else if (action == "rotate") { + if (auto center = actionData[2]) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("rotationCenter")) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("center")) { + mat.rotate(actionData[1].toFloat(), jsonToVec2F(center)); + } else { + mat.rotate(actionData[1].toFloat()); + } + } else if (action == "scale") { + if (auto center = actionData[2]) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("scaleCenter")) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else if (auto center = properties.ptr("center")) { + mat.scale(actionData[1].toFloat(), jsonToVec2F(center)); + } else { + mat.scale(actionData[1].toFloat()); + } + } else if (action == "transform") { + mat = Mat3F(actionData[1].toFloat(), actionData[2].toFloat(), actionData[3].toFloat(), actionData[4].toFloat(), actionData[5].toFloat(), actionData[6].toFloat(), 0, 0, 1) * mat; + } + } + return mat; + }; + + + for (auto& pair : m_transformationGroups) { + if (auto transforms = activeState.properties.ptr(pair.first)) { + auto mat = processTransforms(pair.second.animationAffineTransform(), transforms->toArray(), activeState.properties); + if (pair.second.interpolated) { + if (auto nextTransforms = activeState.nextProperties.ptr("transforms")) { + auto nextMat = processTransforms(pair.second.animationAffineTransform(), nextTransforms->toArray(), activeState.nextProperties); + pair.second.setAnimationAffineTransform(mat, nextMat, activeState.frameProgress); + } else { + pair.second.setAnimationAffineTransform(mat); + } + } else { + pair.second.setAnimationAffineTransform(mat); + } + } + } + } }); for (auto& pair : m_rotationGroups) { @@ -990,6 +1166,47 @@ void NetworkedAnimator::TransformationGroup::setAffineTransform(Mat3F const& mat yShear.set(atan2(matrix[1][0], matrix[1][1])); } +void NetworkedAnimator::TransformationGroup::setLocalAffineTransform(Mat3F const& matrix) { + localTransform = matrix; +} + +Mat3F NetworkedAnimator::TransformationGroup::localAffineTransform() const { + return localTransform; +} + +void NetworkedAnimator::TransformationGroup::setAnimationAffineTransform(Mat3F const& matrix) { + xTranslationAnimation = matrix[0][2]; + yTranslationAnimation = matrix[1][2]; + xScaleAnimation = sqrt(square(matrix[0][0]) + square(matrix[0][1])); + yScaleAnimation = sqrt(square(matrix[1][0]) + square(matrix[1][1])); + xShearAnimation = atan2(matrix[0][1], matrix[0][0]); + yShearAnimation = atan2(matrix[1][0], matrix[1][1]); +} +void NetworkedAnimator::TransformationGroup::setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress) { + xTranslationAnimation = mat1[0][2]; + yTranslationAnimation = mat1[1][2]; + xScaleAnimation = sqrt(square(mat1[0][0]) + square(mat1[0][1])); + yScaleAnimation = sqrt(square(mat1[1][0]) + square(mat1[1][1])); + xShearAnimation = atan2(mat1[0][1], mat1[0][0]); + yShearAnimation = atan2(mat1[1][0], mat1[1][1]); + + xTranslationAnimation += (mat2[0][2] - xTranslationAnimation) * progress; + yTranslationAnimation += (mat2[1][2] - yTranslationAnimation) * progress; + xScaleAnimation += (sqrt(square(mat2[0][0]) + square(mat2[0][1])) - xScaleAnimation) * progress; + yScaleAnimation += (sqrt(square(mat2[1][0]) + square(mat2[1][1])) - yScaleAnimation) * progress; + xShearAnimation += (atan2(mat2[0][1], mat2[0][0]) - xShearAnimation) * progress; + yShearAnimation += (atan2(mat2[1][0], mat2[1][1]) - yShearAnimation) * progress; + +} + +Mat3F NetworkedAnimator::TransformationGroup::animationAffineTransform() const { + return Mat3F( + xScaleAnimation * cos(xShearAnimation), xScaleAnimation * sin(xShearAnimation), xTranslationAnimation, + yScaleAnimation * sin(yShearAnimation), yScaleAnimation * cos(yShearAnimation), yTranslationAnimation, + 0, 0, 1 + ); +} + void NetworkedAnimator::setupNetStates() { clearNetElements(); @@ -1007,6 +1224,8 @@ void NetworkedAnimator::setupNetStates() { addNetElement(&m_partTags[part]); for (auto& pair : m_stateInfo) { + pair.second.reverse.setCompatibilityVersion(8); + addNetElement(&pair.second.reverse); addNetElement(&pair.second.stateIndex); addNetElement(&pair.second.startedEvent); } @@ -1086,7 +1305,7 @@ void NetworkedAnimator::setupNetStates() { void NetworkedAnimator::netElementsNeedLoad(bool initial) { for (auto& pair : m_stateInfo) { if (pair.second.startedEvent.pullOccurred() || initial) - m_animatedParts.setActiveStateIndex(pair.first, pair.second.stateIndex.get(), true); + m_animatedParts.setActiveStateIndex(pair.first, pair.second.stateIndex.get(), true, pair.second.reverse.get()); } for (auto& pair : m_rotationGroups) { @@ -1096,8 +1315,26 @@ void NetworkedAnimator::netElementsNeedLoad(bool initial) { } void NetworkedAnimator::netElementsNeedStore() { - for (auto& pair : m_stateInfo) - pair.second.stateIndex.set(m_animatedParts.activeStateIndex(pair.first)); + for (auto& pair : m_stateInfo) { + if (pair.second.wasUpdated) { + pair.second.stateIndex.set(m_animatedParts.activeStateIndex(pair.first)); + pair.second.reverse.set(m_animatedParts.activeStateReverse(pair.first)); + } + } +} + +uint8_t NetworkedAnimator::version() const { + return m_animatorVersion; +} + +Json NetworkedAnimator::mergeIncludes(Json config, Json includes, String relativePath){ + for (Json const& path : includes.iterateArray()) { + auto includeConfig = Root::singleton().assets()->json(AssetPath::relativeTo(relativePath, path.toString())); + if (auto v = includeConfig.get("includes")) + includeConfig = mergeIncludes(includeConfig, v, relativePath); + config = jsonMerge(includeConfig, config); + } + return config; } } diff --git a/source/game/StarNetworkedAnimator.hpp b/source/game/StarNetworkedAnimator.hpp index 8265011..f91f526 100644 --- a/source/game/StarNetworkedAnimator.hpp +++ b/source/game/StarNetworkedAnimator.hpp @@ -79,8 +79,13 @@ public: // Returns whether a state change occurred. If startNew is true, always // forces a state change and starts the state off at the beginning even if // this state is already the current state. - bool setState(String const& stateType, String const& state, bool startNew = false); + bool setState(String const& stateType, String const& state, bool startNew = false, bool reverse = false); + bool setLocalState(String const& stateType, String const& state, bool startNew = false, bool reverse = false); String state(String const& stateType) const; + int stateFrame(String const& stateType) const; + float stateFrameProgress(String const& stateType) const; + float stateTimer(String const& stateType) const; + bool stateReverse(String const& stateType) const; StringMap<AnimatedPartSet::Part> const& constParts() const; StringMap<AnimatedPartSet::Part>& parts(); @@ -120,6 +125,9 @@ public: String const* globalTagPtr(String const& tagName) const; void setPartTag(String const& partType, String tagName, String tagValue); + void setPartDrawables(String const& partName, List<Drawable> drawables); + void addPartDrawables(String const& partName, List<Drawable> drawables); + void setProcessingDirectives(Directives const& directives); void setZoom(float zoom); bool flipped() const; @@ -147,6 +155,13 @@ public: void transformTransformationGroup(String const& transformationGroup, float a, float b, float c, float d, float tx, float ty); void resetTransformationGroup(String const& transformationGroup); + void translateLocalTransformationGroup(String const& transformationGroup, Vec2F const& translation); + void rotateLocalTransformationGroup(String const& transformationGroup, float rotation, Vec2F const& rotationCenter = Vec2F()); + void scaleLocalTransformationGroup(String const& transformationGroup, float scale, Vec2F const& scaleCenter = Vec2F()); + void scaleLocalTransformationGroup(String const& transformationGroup, Vec2F const& scale, Vec2F const& scaleCenter = Vec2F()); + void transformLocalTransformationGroup(String const& transformationGroup, float a, float b, float c, float d, float tx, float ty); + void resetLocalTransformationGroup(String const& transformationGroup); + bool hasParticleEmitter(String const& emitterName) const; // Active particle emitters emit over time based on emission rate/variance. void setParticleEmitterActive(String const& emitterName, bool active); @@ -200,6 +215,7 @@ public: // Run through the current animations until the final frame, including any // transition animations. void finishAnimations(); + uint8_t version() const; private: struct RotationGroup { @@ -216,14 +232,31 @@ private: Mat3F affineTransform() const; void setAffineTransform(Mat3F const& matrix); + Mat3F localAffineTransform() const; + void setLocalAffineTransform(Mat3F const& matrix); + + Mat3F animationAffineTransform() const; + void setAnimationAffineTransform(Mat3F const& matrix); + void setAnimationAffineTransform(Mat3F const& mat1, Mat3F const& mat2, float progress); + bool interpolated; + Mat3F localTransform; + NetElementFloat xTranslation; NetElementFloat yTranslation; NetElementFloat xScale; NetElementFloat yScale; NetElementFloat xShear; NetElementFloat yShear; + + float xTranslationAnimation; + float yTranslationAnimation; + float xScaleAnimation; + float yScaleAnimation; + float xShearAnimation; + float yShearAnimation; + }; struct ParticleEmitter { @@ -299,6 +332,8 @@ private: struct StateInfo { NetElementSize stateIndex; NetElementEvent startedEvent; + bool wasUpdated; + NetElementBool reverse; }; void setupNetStates(); @@ -306,7 +341,10 @@ private: void netElementsNeedLoad(bool full) override; void netElementsNeedStore() override; + Json mergeIncludes(Json config, Json includes, String relativePath); + String m_relativePath; + uint8_t m_animatorVersion; AnimatedPartSet m_animatedParts; OrderedHashMap<String, StateInfo> m_stateInfo; @@ -327,6 +365,9 @@ private: NetElementHashMap<String, String> m_globalTags; StableStringMap<NetElementHashMap<String, String>> m_partTags; + + HashMap<String,List<Drawable>> m_partDrawables; + mutable StringMap<std::pair<size_t, Drawable>> m_cachedPartDrawables; }; diff --git a/source/game/scripting/StarNetworkedAnimatorLuaBindings.cpp b/source/game/scripting/StarNetworkedAnimatorLuaBindings.cpp index dfafeb0..937e237 100644 --- a/source/game/scripting/StarNetworkedAnimatorLuaBindings.cpp +++ b/source/game/scripting/StarNetworkedAnimatorLuaBindings.cpp @@ -8,12 +8,21 @@ namespace Star { LuaCallbacks LuaBindings::makeNetworkedAnimatorCallbacks(NetworkedAnimator* networkedAnimator) { LuaCallbacks callbacks; - callbacks.registerCallbackWithSignature<bool, String, String, bool>( - "setAnimationState", bind(&NetworkedAnimator::setState, networkedAnimator, _1, _2, _3)); + callbacks.registerCallbackWithSignature<bool, String, String, bool, bool>( + "setAnimationState", bind(&NetworkedAnimator::setState, networkedAnimator, _1, _2, _3, _4)); callbacks.registerCallbackWithSignature<String, String>( "animationState", bind(&NetworkedAnimator::state, networkedAnimator, _1)); callbacks.registerCallbackWithSignature<Json, String, String>( "animationStateProperty", bind(&NetworkedAnimator::stateProperty, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<int, String>( + "animationStateFrame", bind(&NetworkedAnimator::stateFrame, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<float, String>( + "animationStateFrameProgress", bind(&NetworkedAnimator::stateFrameProgress, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<float, String>( + "animationStateTimer", bind(&NetworkedAnimator::stateTimer, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<bool, String>( + "animationStateReverse", bind(&NetworkedAnimator::stateReverse, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<void, String, String>( "setGlobalTag", bind(&NetworkedAnimator::setGlobalTag, networkedAnimator, _1, _2)); callbacks.registerCallbackWithSignature<void, String, String, String>( @@ -30,6 +39,7 @@ LuaCallbacks LuaBindings::makeNetworkedAnimatorCallbacks(NetworkedAnimator* netw "currentRotationAngle", bind(&NetworkedAnimator::currentRotationAngle, networkedAnimator, _1)); callbacks.registerCallbackWithSignature<bool, String>( "hasTransformationGroup", bind(&NetworkedAnimator::hasTransformationGroup, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<void, String, Vec2F>("translateTransformationGroup", bind(&NetworkedAnimator::translateTransformationGroup, networkedAnimator, _1, _2)); callbacks.registerCallback("rotateTransformationGroup", @@ -48,6 +58,27 @@ LuaCallbacks LuaBindings::makeNetworkedAnimatorCallbacks(NetworkedAnimator* netw bind(&NetworkedAnimator::transformTransformationGroup, networkedAnimator, _1, _2, _3, _4, _5, _6, _7)); callbacks.registerCallbackWithSignature<void, String>( "resetTransformationGroup", bind(&NetworkedAnimator::resetTransformationGroup, networkedAnimator, _1)); + + callbacks.registerCallbackWithSignature<void, String, Vec2F>("translateLocalTransformationGroup", + bind(&NetworkedAnimator::translateLocalTransformationGroup, networkedAnimator, _1, _2)); + callbacks.registerCallback("rotateLocalTransformationGroup", + [networkedAnimator](String const& transformationGroup, float rotation, Maybe<Vec2F> const& rotationCenter) { + networkedAnimator->rotateLocalTransformationGroup(transformationGroup, rotation, rotationCenter.value()); + }); + callbacks.registerCallback("scaleLocalTransformationGroup", + [networkedAnimator](LuaEngine& engine, String const& transformationGroup, LuaValue scale, Maybe<Vec2F> const& scaleCenter) { + if (auto cs = engine.luaMaybeTo<Vec2F>(scale)) + networkedAnimator->scaleLocalTransformationGroup(transformationGroup, *cs, scaleCenter.value()); + else + networkedAnimator->scaleLocalTransformationGroup(transformationGroup, engine.luaTo<float>(scale), scaleCenter.value()); + }); + callbacks.registerCallbackWithSignature<void, String, float, float, float, float, float, float>( + "transformLocalTransformationGroup", + bind(&NetworkedAnimator::transformLocalTransformationGroup, networkedAnimator, _1, _2, _3, _4, _5, _6, _7)); + callbacks.registerCallbackWithSignature<void, String>( + "resetLocalTransformationGroup", bind(&NetworkedAnimator::resetLocalTransformationGroup, networkedAnimator, _1)); + + callbacks.registerCallbackWithSignature<void, String, bool>( "setParticleEmitterActive", bind(&NetworkedAnimator::setParticleEmitterActive, networkedAnimator, _1, _2)); callbacks.registerCallbackWithSignature<void, String, float>("setParticleEmitterEmissionRate", @@ -105,6 +136,10 @@ LuaCallbacks LuaBindings::makeNetworkedAnimatorCallbacks(NetworkedAnimator* netw return poly; }); + callbacks.registerCallbackWithSignature<void, String, List<Drawable>>( + "addPartDrawables", bind(&NetworkedAnimator::addPartDrawables, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<void, String, List<Drawable>>( + "setPartDrawables", bind(&NetworkedAnimator::setPartDrawables, networkedAnimator, _1, _2)); return callbacks; } diff --git a/source/game/scripting/StarScriptedAnimatorLuaBindings.cpp b/source/game/scripting/StarScriptedAnimatorLuaBindings.cpp index 0b2dd7f..e093360 100644 --- a/source/game/scripting/StarScriptedAnimatorLuaBindings.cpp +++ b/source/game/scripting/StarScriptedAnimatorLuaBindings.cpp @@ -4,23 +4,63 @@ namespace Star { -LuaCallbacks LuaBindings::makeScriptedAnimatorCallbacks(const NetworkedAnimator* animator, function<Json(String const&, Json const&)> getParameter) { +LuaCallbacks LuaBindings::makeScriptedAnimatorCallbacks(NetworkedAnimator* networkedAnimator, function<Json(String const&, Json const&)> getParameter) { LuaCallbacks callbacks; callbacks.registerCallback("animationParameter", getParameter); - callbacks.registerCallback("partPoint", [animator](String const& partName, String const& propertyName) { - return animator->partPoint(partName, propertyName); - }); - callbacks.registerCallback("partPoly", [animator](String const& partName, String const& propertyName) { return animator->partPoly(partName, propertyName); }); + callbacks.registerCallbackWithSignature<Maybe<Vec2F>, String, String>("partPoint", bind(&NetworkedAnimator::partPoint, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<Maybe<PolyF>, String, String>("partPoly", bind(&NetworkedAnimator::partPoly, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<Json, String, String>("partProperty", bind(&NetworkedAnimator::partProperty, networkedAnimator, _1, _2)); - callbacks.registerCallback("transformPoint", [animator] (Vec2F point, String const& part) -> Vec2F { - return animator->partTransformation(part).transformVec2(point); + callbacks.registerCallback("transformPoint", [networkedAnimator] (Vec2F point, String const& part) -> Vec2F { + return networkedAnimator->partTransformation(part).transformVec2(point); }); - callbacks.registerCallback("transformPoly", [animator] (PolyF poly, String const& part) -> PolyF { - poly.transform(animator->partTransformation(part)); + callbacks.registerCallback("transformPoly", [networkedAnimator] (PolyF poly, String const& part) -> PolyF { + poly.transform(networkedAnimator->partTransformation(part)); return poly; }); + callbacks.registerCallbackWithSignature<Json, String, String>( + "animationStateProperty", bind(&NetworkedAnimator::stateProperty, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<int, String>( + "animationState", bind(&NetworkedAnimator::state, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<int, String>( + "animationStateFrame", bind(&NetworkedAnimator::stateFrame, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<float, String>( + "animationStateFrameProgress", bind(&NetworkedAnimator::stateFrameProgress, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<float, String>( + "animationStateTimer", bind(&NetworkedAnimator::stateTimer, networkedAnimator, _1)); + callbacks.registerCallbackWithSignature<bool, String>( + "animationStateReverse", bind(&NetworkedAnimator::stateReverse, networkedAnimator, _1)); + + callbacks.registerCallbackWithSignature<bool, String>( + "hasTransformationGroup", bind(&NetworkedAnimator::hasTransformationGroup, networkedAnimator, _1)); + + callbacks.registerCallbackWithSignature<void, String, Vec2F>("translateLocalTransformationGroup", + bind(&NetworkedAnimator::translateLocalTransformationGroup, networkedAnimator, _1, _2)); + callbacks.registerCallback("rotateLocalTransformationGroup", + [networkedAnimator](String const& transformationGroup, float rotation, Maybe<Vec2F> const& rotationCenter) { + networkedAnimator->rotateLocalTransformationGroup(transformationGroup, rotation, rotationCenter.value()); + }); + callbacks.registerCallback("scaleLocalTransformationGroup", + [networkedAnimator](LuaEngine& engine, String const& transformationGroup, LuaValue scale, Maybe<Vec2F> const& scaleCenter) { + if (auto cs = engine.luaMaybeTo<Vec2F>(scale)) + networkedAnimator->scaleLocalTransformationGroup(transformationGroup, *cs, scaleCenter.value()); + else + networkedAnimator->scaleLocalTransformationGroup(transformationGroup, engine.luaTo<float>(scale), scaleCenter.value()); + }); + callbacks.registerCallbackWithSignature<void, String, float, float, float, float, float, float>( + "transformLocalTransformationGroup", + bind(&NetworkedAnimator::transformLocalTransformationGroup, networkedAnimator, _1, _2, _3, _4, _5, _6, _7)); + callbacks.registerCallbackWithSignature<void, String>( + "resetLocalTransformationGroup", bind(&NetworkedAnimator::resetLocalTransformationGroup, networkedAnimator, _1)); + + callbacks.registerCallbackWithSignature<void, String, List<Drawable>>( + "addPartDrawables", bind(&NetworkedAnimator::addPartDrawables, networkedAnimator, _1, _2)); + callbacks.registerCallbackWithSignature<void, String, List<Drawable>>( + "setPartDrawables", bind(&NetworkedAnimator::setPartDrawables, networkedAnimator, _1, _2)); + + return callbacks; } diff --git a/source/game/scripting/StarScriptedAnimatorLuaBindings.hpp b/source/game/scripting/StarScriptedAnimatorLuaBindings.hpp index 27f8ed5..bf81936 100644 --- a/source/game/scripting/StarScriptedAnimatorLuaBindings.hpp +++ b/source/game/scripting/StarScriptedAnimatorLuaBindings.hpp @@ -6,6 +6,6 @@ namespace Star { namespace LuaBindings { - LuaCallbacks makeScriptedAnimatorCallbacks(const NetworkedAnimator* animator, function<Json(String const&, Json const&)> getParameter); + LuaCallbacks makeScriptedAnimatorCallbacks(NetworkedAnimator* networkedAnimator, function<Json(String const&, Json const&)> getParameter); } } |