Skip to content

Commit

Permalink
AT: implement Archipelago data storage api
Browse files Browse the repository at this point in the history
  • Loading branch information
black-sliver committed Sep 27, 2022
1 parent f1691e4 commit 9312943
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 3 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# PopTracker Changelog

## next

* Pack Features
* Add support for Archipelago data storage api

## v0.21.0

* App Features
Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ SRC = $(wildcard $(SRC_DIR)/*.cpp) \
$(wildcard $(SRC_DIR)/usb2snes/*.cpp) \
$(wildcard $(SRC_DIR)/uat/*.cpp) \
$(wildcard $(SRC_DIR)/ap/*.cpp) \
$(wildcard $(LIB_DIR)/wswrap/src/*.cpp) \
$(wildcard $(SRC_DIR)/http/*.cpp) \
$(wildcard $(SRC_DIR)/packmanager/*.cpp)
#lib/gifdec/gifdec.c
Expand Down
6 changes: 6 additions & 0 deletions doc/AUTOTRACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ manifest.json and clicking on "AP" in the menu when the pack is loaded.
* when a location is checked, Location handlers are called
* when a location is scouted, Scout handlers are called
* when a bounce is received, Bounced handlers are called
* when a watched data storage value is changed, SetReply handlers are called
* when a data storage value is polled (Get), Retrieved handlers are called

### global Archipelago
* `.PlayerNumber` returns the slot number of the connected player or -1 if not connected
Expand All @@ -142,6 +144,10 @@ manifest.json and clicking on "AP" in the menu when the pack is loaded.
* `:AddLocationHandler(name, callback)` called when a location was checked; args: location_id, location_name
* `:AddScoutHandler(name, callback)` called when a location was scouted; args: location_id, location_name, item_id, item_name, item_player
* `:AddBouncedHandler(name, callback)` called when the server sends a bounce; args: json bounce message as table
* `:AddRetrievedHandler(name, callback)` called when the server replies to Get; args: key, value
* `:AddSetReplyHandler(name, callback)` called when a watched data storage value is changed; args: key, value, old_value
* `:Get(keys)` ask the server for values from data storage, run this from a ClearHandler, keys is an array of strings
* `:SetNotify(keys)` ask the server to notify when a data storage value is changed, run this from a ClearHandler, keys is an array of strings


## Other Stuff
Expand Down
2 changes: 1 addition & 1 deletion lib/apclientpp
Submodule apclientpp updated 4 files
+1 −1 LICENSE
+52 −6 README.md
+312 −43 apclient.hpp
+91 −0 apuuid.hpp
2 changes: 1 addition & 1 deletion lib/wswrap
22 changes: 22 additions & 0 deletions src/ap/aptracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ class APTracker final {
scout.item, _ap->get_item_name(scout.item), scout.player);
}
});
_ap->set_retrieved_handler([this](const std::map<std::string, json>& keys) {
auto lock = EventLock(_event);
for (const auto& pair: keys) {
onRetrieved.emit(this, pair.first, pair.second);
}
});
_ap->set_set_reply_handler([this](const std::string& key, const json& value, const json& old) {
auto lock = EventLock(_event);
onSetReply.emit(this, key, value, old);
});
return true;
}

Expand Down Expand Up @@ -190,13 +200,25 @@ class APTracker final {
return _ap ? _ap->get_player_number() : -1;
}

bool SetNotify(const std::list<std::string>& keys)
{
return _ap ? _ap->SetNotify(keys) : false;
}

bool Get(const std::list<std::string>& keys)
{
return _ap ? _ap->Get(keys) : false;
}

Signal<const std::string&> onError;
Signal<APClient::State> onStateChanged;
Signal<const json&> onClear; // called when state has to be cleared, gives new slot_data
Signal<int, int, const std::string&, int> onItem; // index, item, item_name, player
Signal<int64_t, const std::string&, int64_t, const std::string&, int> onScout; // location, location_name, item, item_name, target player
Signal<int64_t, const std::string&> onLocationChecked; // location, location_name
Signal<const json&> onBounced; // packet
Signal<const std::string&, const json&> onRetrieved;
Signal<const std::string&, const json&, const json&> onSetReply;

private:
APClient* _ap = nullptr;
Expand Down
78 changes: 78 additions & 0 deletions src/ap/archipelago.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const LuaInterface<Archipelago>::MethodMap Archipelago::Lua_Methods = {
LUA_METHOD(Archipelago, AddLocationHandler, const char*, LuaRef),
LUA_METHOD(Archipelago, AddScoutHandler, const char*, LuaRef),
LUA_METHOD(Archipelago, AddBouncedHandler, const char*, LuaRef),
LUA_METHOD(Archipelago, AddRetrievedHandler, const char*, LuaRef),
LUA_METHOD(Archipelago, AddSetReplyHandler, const char*, LuaRef),
LUA_METHOD(Archipelago, SetNotify, json),
LUA_METHOD(Archipelago, Get, json),
};

Archipelago::Archipelago(lua_State *L, APTracker *ap)
Expand Down Expand Up @@ -117,6 +121,80 @@ bool Archipelago::AddBouncedHandler(const std::string& name, LuaRef callback)
return true;
}


bool Archipelago::AddRetrievedHandler(const std::string& name, LuaRef callback)
{
if (!_ap || !callback.valid()) return false;
int ref = callback.ref;
_ap->onRetrieved += {this, [this, ref, name](void*, const std::string& key, const json& value) {
lua_rawgeti(_L, LUA_REGISTRYINDEX, ref);
Lua(_L).Push(key.c_str());
json_to_lua(_L, value);
if (lua_pcall(_L, 2, 0, 0)) {
const char* err = lua_tostring(_L, -1);
printf("Error calling Archipelago RetrievedHandler for %s: %s\n",
name.c_str(), err ? err : "Unknown");
lua_pop(_L, 1);
}
}};
return true;
}

bool Archipelago::AddSetReplyHandler(const std::string& name, LuaRef callback)
{
if (!_ap || !callback.valid()) return false;
int ref = callback.ref;
_ap->onSetReply += {this, [this, ref, name](void*, const std::string& key, const json& value, const json& old) {
lua_rawgeti(_L, LUA_REGISTRYINDEX, ref);
Lua(_L).Push(key.c_str());
json_to_lua(_L, value);
json_to_lua(_L, old);
if (lua_pcall(_L, 3, 0, 0)) {
const char* err = lua_tostring(_L, -1);
printf("Error calling Archipelago SetReplyHandler for %s: %s\n",
name.c_str(), err ? err : "Unknown");
lua_pop(_L, 1);
}
}};
return true;
}

bool Archipelago::SetNotify(const json& jKeys)
{
if (!_ap || (!jKeys.is_array() && !jKeys.is_object())) {
printf("Archipelago.SetNotify: keys must be array/table!\n");
return false;
}
std::list<std::string> keys;
for (auto& el: jKeys.items()) {
if (el.value().is_string()) {
keys.push_back(el.value());
} else {
printf("Archipelago.SetNotify: keys must be array/table of string!\n");
return false;
}
}
return _ap->SetNotify(keys);
}

bool Archipelago::Get(const json& jKeys)
{
if (!_ap || (!jKeys.is_array() && !jKeys.is_object())) {
printf("Archipelago.Get: keys must be array/table!\n");
return false;
}
std::list<std::string> keys;
for (auto& el: jKeys.items()) {
if (el.value().is_string()) {
keys.push_back(el.value());
} else {
printf("Archipelago.Get: keys must be array/table of string!\n");
return false;
}
}
return _ap->Get(keys);
}

int Archipelago::Lua_Index(lua_State *L, const char* key) {
if (strcmp(key, "PlayerNumber")==0) {
lua_pushinteger(L, _ap ? _ap->getPlayerNumber() : -1);
Expand Down
4 changes: 4 additions & 0 deletions src/ap/archipelago.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ class Archipelago : public LuaInterface<Archipelago> {
bool AddLocationHandler(const std::string& name, LuaRef callback);
bool AddScoutHandler(const std::string& name, LuaRef callback);
bool AddBouncedHandler(const std::string& name, LuaRef callback);
bool AddRetrievedHandler(const std::string& name, LuaRef callback);
bool AddSetReplyHandler(const std::string& name, LuaRef callback);
bool SetNotify(const json& keys);
bool Get(const json& keys);

protected:
lua_State *_L;
Expand Down

0 comments on commit 9312943

Please sign in to comment.