Commit e972afc3 authored by diafero's avatar diafero
Browse files

proper implementation of plNetMsgTestAndSet

with a lot of thanks to dirtsand;
this is based on <>
parent 6cf371c4
This describes parts of the protocol which were guessed, unknown bytes which always have the same value and similar problems. I don't list all the plMessages here as the server barely cares about them - it shouldn't be its business to parse them at all, and it only does so to work around some protocol flaws and Uru bugs.
NetMsgs which are more or less completely unknown:
- NetMsgTestAndSet: Alcugs can parse this, and if "lockReq" is set to 1, it replies with a plServerReplyMsg with the reply type set to "affirm". However, the actual purpose is unknown. I think the server is supposed to do more than just reply and forget about it, it sounds almost as if some kind of lock has to be acquired. I can't see any issue in-game which I connect to this, except for some weird problems with footstep sounds not always working if there is a big footstep region around the link-in point, but all of this is wild guessing.
- NetMsgPlayerPage: The format of this one is completely known, but why should anyone care about the avatar paging in or out? The server currently ignores it.
- NetMsgRelevanceRegions: It contains two bitfields (8 bytes each) saying what is relevant for the sender. The server currently ignores it, not knowing which events to filter according to these regions and which not (maybe all those where the plNetRelRegions flag is set?).
......@@ -362,6 +362,17 @@ namespace alc {
/* player is offline */0, onlineTime);
// release locks this player might have forgotten to release
tSpinLock lock(locksMutex);
for (auto it = locks.begin(); it != locks.end(); ) {
if (it->second == u->ki)
it = locks.erase(it);
// remove leftovers of this player from the age state
......@@ -958,8 +969,8 @@ namespace alc {
// Just ignore it, server-side Python is not supported
return 1;
//// unknown purpose messages
//// object management messages
case NetMsgTestAndSet:
if (!u->joined) {
......@@ -969,6 +980,29 @@ namespace alc {
// get the data out of the packet
tmTestAndSet testAndSet(u, msg);
// we need to update the lock map to match this request
bool affirm;
if (testAndSet.isLockReq) {
tSpinLock lock(locksMutex);
if (u->ki != 0 && locks.find(testAndSet.obj) == locks.end()) {
// Lock not currently held. Also require a valid KI so we can track this.
affirm = true;
locks[testAndSet.obj] = u->ki;
} else {
// Lock already held, tough luck.
affirm = false;
else {
tSpinLock lock(locksMutex);
// Release the lock, if it is held by this client. Otherwise ignore.
auto it = locks.find(testAndSet.obj);
if (it != locks.end() && it->second == u->ki)
// No reply needed.
return 1;
// if required, send a reply - this is simply copied from the old game server, don't ask me what it means
if (testAndSet.isLockReq) {
......@@ -976,7 +1010,7 @@ namespace alc {
tpServerReplyMsg serverReplyMsg = tpServerReplyMsg(tUruObjectRef()); // the parent is an empty object
serverReplyMsg.receivers.push_back(tUruObjectRef(testAndSet.obj)); // add the sent object as receiver
serverReplyMsg.flags = 0x00000800;
serverReplyMsg.replyType = 1; // this means "affirm"
serverReplyMsg.replyType = affirm; // 0 = deny, 1 = affirm
// send message
tmGameMessage msg(u, u->ki, &serverReplyMsg);
......@@ -984,6 +1018,8 @@ namespace alc {
return 1;
//// unknown purpose messages
case NetMsgPlayerPage:
if (!u->joined) {
......@@ -135,6 +135,10 @@ namespace alc {
bool noReltoShare, serverSideCommands, linkingOutIdle;
tString shardIdentifier;
typedef std::map<tUruObject, uint32_t> tLockList;
tLockList locks; //!< maps the locked object to the KI of the session that locked it; protected by below mutex
tSpinEx locksMutex;
} //End alc namespace
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment