Add support for animate replace=true
This commit is contained in:
@@ -21,7 +21,7 @@ static const char *vtname(AnimValueType vt) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t hash_encstep(uint64_t prev, std::string_view s) {
|
||||
static uint64_t hash_encstep(uint64_t prev, std::string_view s) {
|
||||
return util::hash_string(util::HashValue(123, prev), s).first;
|
||||
}
|
||||
|
||||
@@ -420,102 +420,114 @@ void AnimCoreState::decode(std::string_view s) {
|
||||
}
|
||||
|
||||
int AnimQueue::get_size_limit() const {
|
||||
if (encqueue_ == nullptr) return 0;
|
||||
StreamBuffer sb(*encqueue_);
|
||||
return sb.read_uint8();
|
||||
}
|
||||
|
||||
int AnimQueue::get_actual_size() const {
|
||||
if (encqueue_ == nullptr) return 0;
|
||||
StreamBuffer sb(*encqueue_);
|
||||
sb.read_bytes(1);
|
||||
return sb.read_uint8();
|
||||
}
|
||||
|
||||
uint64_t AnimQueue::get_final_hash() const {
|
||||
if (encqueue_ == nullptr) return 0;
|
||||
StreamBuffer sb(*encqueue_);
|
||||
sb.read_bytes(2);
|
||||
return sb.read_uint64();
|
||||
}
|
||||
|
||||
std::string_view AnimQueue::get_final_encstep() const {
|
||||
if (encqueue_ == nullptr) return std::string_view();
|
||||
StreamBuffer sb(*encqueue_);
|
||||
sb.read_bytes(10);
|
||||
return sb.read_string_view();
|
||||
}
|
||||
|
||||
void AnimQueue::update_encqueue(int limit, bool add, std::string_view add_enc, bool keepold) {
|
||||
// Make sure the size limit is reasonable.
|
||||
assert((limit >= 2) && (limit <= 250));
|
||||
AnimQueue::QueueRange AnimQueue::get_range(int lo, int hi) {
|
||||
// Clamp lo and hi to the valid range (0 to actual_size).
|
||||
//
|
||||
int actual_size = get_actual_size();
|
||||
if (lo < 0) lo = 0;
|
||||
if (hi > actual_size) hi = actual_size;
|
||||
|
||||
// You must either add a new step or retain an old step. The queue can't be empty.
|
||||
assert(keepold || add);
|
||||
// Abort early if the range is empty. This avoids several edge cases.
|
||||
//
|
||||
if (lo >= hi) return QueueRange(0, std::string_view());
|
||||
|
||||
// Find out how many old steps we'll be retaining, ignoring the size limit.
|
||||
int nretain = 0;
|
||||
if (keepold) nretain = get_actual_size();
|
||||
|
||||
// If retaining all steps would overflow the size limit, retain fewer.
|
||||
int retain_limit = limit;
|
||||
if (add) retain_limit -= 1;
|
||||
if (nretain > retain_limit) nretain = retain_limit;
|
||||
|
||||
// Calculate the new size of the queue.
|
||||
int new_size = add ? (nretain + 1) : nretain;
|
||||
|
||||
// If we're retaining steps, extract them from the old queue.
|
||||
std::string_view retain;
|
||||
if (nretain > 0) {
|
||||
std::string_view oldqueue(*encqueue_);
|
||||
StreamBuffer sb(oldqueue);
|
||||
sb.read_bytes(2); // Skip over the header.
|
||||
int pos1 = sb.total_reads();
|
||||
for (int i = 0; i < nretain; i++) {
|
||||
sb.read_uint64();
|
||||
sb.read_string_view();
|
||||
}
|
||||
int pos2 = sb.total_reads();
|
||||
retain = oldqueue.substr(pos1, pos2 - pos1);
|
||||
// Get the entries.
|
||||
//
|
||||
std::string_view queueview(*encqueue_);
|
||||
StreamBuffer sb(queueview);
|
||||
sb.read_bytes(2); // Skip over the header.
|
||||
for (int i = 0; i < lo; i++) {
|
||||
sb.read_uint64();
|
||||
sb.read_string_view();
|
||||
}
|
||||
|
||||
// If we're adding a step, calculate its hash.
|
||||
uint64_t add_hash = 0;
|
||||
if (add) {
|
||||
uint64_t prev_hash = 0;
|
||||
if (nretain > 0) prev_hash = get_final_hash();
|
||||
add_hash = hash_encstep(prev_hash, add_enc);
|
||||
int pos1 = sb.total_reads();
|
||||
for (int i = lo; i < hi; i++) {
|
||||
sb.read_uint64();
|
||||
sb.read_string_view();
|
||||
}
|
||||
int pos2 = sb.total_reads();
|
||||
return QueueRange(hi-lo, queueview.substr(pos1, pos2 - pos1));
|
||||
}
|
||||
|
||||
// Finally, encode everything into a binary blob.
|
||||
uint64_t AnimQueue::hash_encstep(const QueueRange &prev, std::string_view s) {
|
||||
uint64_t prev_hash = 0;
|
||||
if (prev.size > 0) {
|
||||
StreamBuffer retsb(prev.entries);
|
||||
prev_hash = retsb.read_uint64();
|
||||
}
|
||||
return ::hash_encstep(prev_hash, s);
|
||||
}
|
||||
|
||||
void AnimQueue::update_encqueue(int limit, bool add, std::string_view add_enc, int keeplo, int keephi) {
|
||||
// Get the retained entries.
|
||||
QueueRange keeprange = get_range(keeplo, keephi);
|
||||
|
||||
// Encode everything into a binary blob.
|
||||
StreamBuffer result;
|
||||
result.write_uint8(limit);
|
||||
result.write_uint8(new_size);
|
||||
result.write_uint8(keeprange.size + (add ? 1:0));
|
||||
if (add) {
|
||||
uint64_t add_hash = hash_encstep(keeprange, add_enc);
|
||||
result.write_uint64(add_hash);
|
||||
result.write_string(add_enc);
|
||||
}
|
||||
result.write_bytes(retain);
|
||||
result.write_bytes(keeprange.entries);
|
||||
|
||||
// Replace the shared string.
|
||||
encqueue_ = std::make_shared<std::string>(result.view());
|
||||
}
|
||||
|
||||
AnimQueue::AnimQueue() {
|
||||
update_encqueue(10, true, AnimState().encode(), false);
|
||||
update_encqueue(10, true, AnimState().encode(), 0, 0);
|
||||
}
|
||||
|
||||
void AnimQueue::clear(const AnimState &state) {
|
||||
update_encqueue(get_size_limit(), true, state.encode(), false);
|
||||
update_encqueue(get_size_limit(), true, state.encode(), 0, 0);
|
||||
}
|
||||
|
||||
void AnimQueue::clear() {
|
||||
update_encqueue(get_size_limit(), true, AnimState().encode(), false);
|
||||
update_encqueue(get_size_limit(), true, AnimState().encode(), 0, 0);
|
||||
}
|
||||
|
||||
void AnimQueue::set_limit(int limit) {
|
||||
update_encqueue(limit, false, "", true);
|
||||
assert((limit >= 2) && (limit <= 250));
|
||||
update_encqueue(limit, false, std::string_view(), 0, limit);
|
||||
}
|
||||
|
||||
void AnimQueue::add(const AnimState &state) {
|
||||
update_encqueue(get_size_limit(), true, state.encode(), true);
|
||||
int limit = get_size_limit();
|
||||
update_encqueue(limit, true, state.encode(), 0, limit - 1);
|
||||
}
|
||||
|
||||
void AnimQueue::replace(const AnimState &state) {
|
||||
int limit = get_size_limit();
|
||||
update_encqueue(limit, true, state.encode(), 1, limit);
|
||||
}
|
||||
|
||||
void AnimQueue::serialize(StreamBuffer *sb) const {
|
||||
|
||||
Reference in New Issue
Block a user