Offline-TMs integrieren
Vaults koennen beim Kobold hinterlegt werden, d.h. Spieler koennen
die Funktionalitaet einschalten, bei Abwesenheit TMs zu empfangen.
Die Vaults werden beim Login abgerufen und in den 'online'-Kobold
und die TM-History uebertragen. Von dort werden sie letztendlich
wie alle anderen Nachrichten auch angezeigt.
Change-Id: Ib8e8b21304795dd9f0be057f9357c5f5239f260c
diff --git a/std/player/comm.c b/std/player/comm.c
index 2dc0601..2dbdc75 100644
--- a/std/player/comm.c
+++ b/std/player/comm.c
@@ -65,9 +65,13 @@
private nosave mixed *report_cache;
// Puffer fuer Kobold.
-private nosave struct msg_buffer_s kobold = (<msg_buffer_s>
+private nosave struct kobold_buffer_s kobold = (<kobold_buffer_s>
buf: allocate(32),
index: -1,);
+// Vault fuer Offline-TMs
+// Der KOBOLD (/secure/kobold) muss immer eine Referenz auf dieses Objekt
+// halten.
+private nosave lwobject "/std/player/comm_vault" commvault;
// Colourmap
// TODO: spaeter konfigurierbar machen
@@ -83,11 +87,15 @@
public varargs int ReceiveMsg(string msg, int msg_type, string msg_action,
string msg_prefix, object origin);
+private int check_ignores(string msg, int msg_type, string msg_action,
+ string msg_prefix, object|string origin);
+private varargs void add_struct_tell_history(struct kobold_msg_s msg,
+ int sent, int recv, int flags );
// erzeugt sortierte Liste an Kommunikationspartnern
private string *sorted_commpartners(int reversed);
-void create()
+protected void create()
{
::create();
Set(P_ALERT, SAVE, F_MODE_AS);
@@ -98,6 +106,7 @@
Set(P_IGNORE, ([]), F_VALUE);
Set(P_IGNORE, SAVE, F_MODE);
Set(P_BUFFER, SAVE, F_MODE);
+ SetProp(P_BUFFER, KOBOLD_OFFLINE);
Set(P_MESSAGE_PREPEND, SAVE, F_MODE_AS);
Set(P_MESSAGE_BEEP, SAVE, F_MODE_AS);
}
@@ -147,29 +156,19 @@
colourmap = build_colourmap(ttype);
}
-// called from base.c in Reconnect()
-protected void reconnect() {
- // Cache fuer den report zuruecksetzen, der koennte veraltet sein (insb.
- // falls in der letzten Session GMCP benutzt wurde und jetzt nicht).
- report_cache = 0;
-}
-
-protected void updates_after_restore(int newflag) {
- // Colourmap aktualisieren nach Restore
- colourmap = build_colourmap(QueryProp(P_TTY));
-
- // Altes Ignoriere loeschen...
- mixed ign = Query(P_IGNORE,F_VALUE);
- if (!mappingp(ign))
+private void setup_comm_vault()
+{
+ if (!commvault && (QueryProp(P_BUFFER) & KOBOLD_OFFLINE))
{
- if (pointerp(ign))
- ReceiveNotify(break_string(
- "Deine Ignoriere-Einstellungen wurden soeben geloescht, "
- "weil es eine Aktualisierung der Ignorierefunktion gab, "
- "bei der eine Konversion der Daten leider nicht "
- "moeglich war.",78), 0);
-
- Set(P_IGNORE, ([]), F_VALUE);
+ // Schauen, ob ein Vault im KOBOLD existiert.
+ commvault = KOBOLD->RetrieveVault();
+ // Wenn nicht, aber eins gewuenscht ist, wird eins erstellt und in KOBOLD
+ // hinterlegt.
+ if (!commvault)
+ {
+ commvault = new_lwobject("/std/player/comm_vault");
+ KOBOLD->DepositVault(commvault);
+ }
}
}
@@ -501,9 +500,45 @@
return MSG_BUFFERED;
}
+// speichert den Inhalt vom commvault im Kobold und der TM-History
+private void process_comm_vault(lwobject "/std/player/comm_vault" vault)
+{
+ struct kobold_msg_s *buffer = vault.Retrieve();
+ if (!sizeof(buffer))
+ return;
+ foreach(struct kobold_msg_s msg: buffer)
+ {
+ // Spieler-definiertes Ignoriere? (nur typen uebergeben, keine Flags)
+ int res = check_ignores(msg.msg, msg.type, msg.action, msg.prefix,
+ msg.sendername);
+ if (res) {
+ // Nachricht wegwerfen. Aber ggf. den Absender informieren, wenn der
+ // online ist und wir nicht Invis
+ object pl = find_player(msg.sendername);
+ if (pl &&
+ (!QueryProp(P_INVIS) || IS_LEARNER(pl)) )
+ pl->ReceiveNotify(sprintf("Deine Nachricht an %s wurde "
+ "ignoriert.",capitalize(getuid(this_object()))), MA_TELL);
+ continue;
+ }
+
+ // wenn der Puffer zu klein ist, Groesse verdoppeln.
+ // Keine Pruefung hier, weil das vault schon die Groesse beschraenkt und
+ // der Inhalt auf jeden Fall passen soll.
+ if (kobold->index >= sizeof(kobold->buf)-1)
+ kobold->buf += allocate(sizeof(kobold->buf));
+ kobold->index += 1;
+ kobold->buf[kobold->index] = msg;
+
+ // TM-History
+ add_struct_tell_history(msg, 0, 1, MSGFLAG_TELL);
+ }
+ vault.Empty();
+}
+
private void _flush_cache(int verbose) {
// nur mit genug Evalticks ausgeben.
- if (get_eval_cost() < 100000) return;
+ if (get_eval_cost() < 500000) return;
if (kobold->index >= 0)
{
ReceiveMsg("Ein kleiner Kobold teilt Dir folgendes mit:",
@@ -517,20 +552,34 @@
// in der Schleife unten gab: dann ist index nicht auf -1 gesetzt
// worden, aber einige Nachrichten sind schon geloescht.
if (!structp(msg)) continue;
+ // Im folgenden nicht den string in der struct aendern (die wird ggf.
+ // auch noch von der TM-History gebraucht).
+ string msgstr = msg.msg;
+ // Wenn Nachricht schon laenger her ist, Uhrzeit anhaengen, aber ggf.
+ // muss ein \n abgeschnitten werden.
+ if (msg.timestamp < time() - 3600)
+ {
+ if (msgstr[<1] == '\n')
+ msgstr = msgstr[0..<2]
+ + " [" + strftime("%d.%m.%y %T", msg.timestamp) + "]";
+ else
+ msgstr = msgstr
+ + " [" + strftime("%d.%m.%y %T", msg.timestamp) + "]";
+ }
// Ausgabe via efun::tell_object(), weil die Arbeit von ReceiveMsg()
// schon getan wurde. Allerdings muessen wir uns noch um den Umbruch
// und Farben kuemmern.
- msg->msg = terminal_colour(msg->msg, colourmap);
+ msgstr = terminal_colour(msgstr, colourmap);
if ((msg->type) & MSG_DONT_WRAP)
- msg->msg = (msg->prefix ? msg->prefix : "") + msg->msg;
+ msgstr = (msg->prefix ? msg->prefix : "") + msgstr;
else
{
int bsflags = msg->type & MSG_ALL_BS_FLAGS;
if (prepend)
bsflags |= BS_PREPEND_INDENT;
- msg->msg = break_string(msg->msg, 78, msg->prefix, bsflags);
+ msgstr = break_string(msgstr, 78, msg->prefix, bsflags);
}
- efun::tell_object(this_object(), msg->msg);
+ efun::tell_object(this_object(), msgstr);
kobold->buf[i]=0;
}
kobold->index=-1;
@@ -545,17 +594,48 @@
varargs int cmd_kobold(string arg)
{
+ if (!sizeof(arg))
+ {
+ _flush_cache(1);
+ return 1;
+ }
switch(arg)
{
case "ein":
- SetProp(P_BUFFER, 1);
- printf("Der Kobold merkt sich jetzt alles!\n"); break;
+ SetProp(P_BUFFER, KOBOLD_ONLINE|KOBOLD_OFFLINE);
+ ReceiveNotify("Der Kobold merkt sich jetzt alles!");
+ break;
+ case "online":
+ SetProp(P_BUFFER, KOBOLD_ONLINE);
+ ReceiveNotify("Der Kobold merkt sich jetzt alles, "
+ "wenn Du online bist!");
+ break;
+ case "offline":
+ SetProp(P_BUFFER, KOBOLD_OFFLINE);
+ ReceiveNotify("Der Kobold merkt sich jetzt alles, "
+ "wenn Du offline bist!");
+ break;
case "aus":
SetProp(P_BUFFER, 0);
- printf("Der Kobold wird Dich nicht stoeren!\n"); break;
- default: if(arg) printf("Der Kobold sagt: kobold ein oder kobold aus\n");
+ ReceiveNotify("Der Kobold wird Dich nicht stoeren!");
+ break;
+ default:
+ ReceiveNotify("Der Kobold sagt: Was soll ich mir denn merken? "
+ "('ein', 'aus', 'offline' oder 'online')");
+ return 1;
}
- _flush_cache(1);
+ if (QueryProp(P_BUFFER) & KOBOLD_OFFLINE)
+ setup_comm_vault();
+ else
+ {
+ // Comm-Vault entfernen. Aber zur Sicherheit nochmal abrufen und
+ // verarbeiten (sollte aber eigentlich ueberfluessig sein)
+ commvault = KOBOLD->ForgetVault();
+ if (commvault) {
+ process_comm_vault(commvault);
+ commvault = 0;
+ }
+ }
return 1;
}
@@ -629,12 +709,12 @@
}
}
-private varargs void add_to_tell_history( string uid, int sent, int recv,
- string message, string indent, int flags )
+private varargs void add_struct_tell_history(struct kobold_msg_s msg,
+ int sent, int recv, int flags )
{
/* tell_history ist ein Mapping mit UIDs der Gespraechspartner als Key.
Als Wert ist eine Strukur vom Typ chat_s eingetragen.
- Strukturen chat_s und stored_msg_s sind in /std/player/comm_structs.c
+ Strukturen chat_s und kobold_msg_s sind in /std/player/comm_structs.c
definiert.
TODO fuer spaeter, gerade keine Zeit fuer:
Als Wert ist ein Array von chat_s enthalten, wobei das 0. Element das
@@ -643,31 +723,22 @@
Element ist aeltestes Gespraech).
*/
- //TODO: Entfernen, wenn das nicht mehr passiert.
- if (!stringp(uid))
- {
- ReceiveMsg(sprintf(
- "\nadd_to_tell_history(): got bad uid argument %O."
- "sent: %d, recv: %d, flags: %d, msg: %s",
- uid, sent, recv, flags, message),MT_DEBUG|MSG_BS_LEAVE_LFS,0,0,ME);
- }
-
// Gespraechspartner fuer erwidere auch ohne tmhist speichern.
if (flags & (MSGFLAG_TELL|MSGFLAG_RTELL))
- last_comm_partner = uid;
+ last_comm_partner = msg.sendername;
// ist ein sortiertes Array von max. MAX_SAVED_CHATS Groesse, welches die
// Spieler enthaelt, denen man schon was mitgeteilt hat. Aktuellste am
// Anfang.
if (sent) {
if (!sizeof(commreceivers))
- commreceivers = ({uid});
- else if (commreceivers[0] != uid) {
+ commreceivers = ({msg.sendername});
+ else if (commreceivers[0] != msg.sendername) {
// nur wenn der aktuelle Partner nicht am Anfang steht, muss man hier was
// tun. Comm-Partner an den Anfang stellen und ggf. alten Eintrag
// entfernen.
// TODO: Effizienter gestalten.
- commreceivers = ({uid}) + (commreceivers-({uid}));
+ commreceivers = ({msg.sendername}) + (commreceivers-({msg.sendername}));
// ggf. kuerzen. (wenn !tell_history_enabled, wird es ggf. unten
// gemacht, denn die Hist muss min. alle UID enthalten, die auch in
// commreceivers drin sind.)
@@ -680,12 +751,12 @@
if (!tell_history_enabled)
return;
- if (!indent && message[<1] == 10)
- message = message[..<2];
+ if (msg.msg[<1] == '\n')
+ msg.msg = msg.msg[..<2];
struct chat_s chat;
// Gespraechspartner unbekannt?
- if (!member(tell_history, uid)) {
+ if (!member(tell_history, msg.sendername)) {
// zuviele Gespraeche in Hist? >= ist Absicht weil ja gleich noch eins
// dazu kommt.
if (sizeof(tell_history) >= MAX_SAVED_CHATS) {
@@ -704,16 +775,16 @@
commreceivers-=({deluid});
}
// neues Gespraech anlegen
- chat = (<chat_s> uid: uid, time_first_msg: time(),
- time_last_msg: time(),
+ chat = (<chat_s> uid: msg.sendername, time_first_msg: msg.timestamp,
+ time_last_msg: msg.timestamp,
sentcount: sent, recvcount: recv,
msgbuf: 0, ptr: 0 );
- tell_history[uid] = chat;
+ tell_history[msg.sendername] = chat;
}
else {
// Gespraechspartner bekannt, altes Gespraech weiterbenutzen
- chat = tell_history[uid];
- chat->time_last_msg = time();
+ chat = tell_history[msg.sendername];
+ chat->time_last_msg = msg.timestamp;
chat->sentcount += sent;
chat->recvcount += recv;
}
@@ -726,22 +797,27 @@
if (!pointerp(chat->msgbuf))
chat->msgbuf = allocate(MAX_SAVED_MESSAGES);
- // Message-Struktur ermitteln oder neu anlegen
- struct stored_msg_s msg;
- if (!structp(chat->msgbuf[chat->ptr])) {
- // neue Struct ins Array schreiben
- chat->msgbuf[chat->ptr] = msg = (<stored_msg_s>);
- }
- else {
- // alte Struct ueberschreiben
- msg = chat->msgbuf[chat->ptr];
- }
+ // neue Struct ins Array schreiben
+ chat->msgbuf[chat->ptr] = msg;
// Index auf naechste Messagestruktur ermitteln
chat->ptr = (chat->ptr + 1) % MAX_SAVED_MESSAGES;
- // Message speichern
- msg->msg = message;
- msg->prefix = indent;
- msg->timestamp = time();
+}
+
+private varargs void add_to_tell_history( string uid, int sent, int recv,
+ string message, string indent, int flags )
+{
+ //TODO: Entfernen, wenn das nicht mehr passiert.
+ if (!stringp(uid))
+ {
+ ReceiveMsg(sprintf(
+ "\nadd_to_tell_history(): got bad uid argument %O."
+ "sent: %d, recv: %d, flags: %d, msg: %s",
+ uid, sent, recv, flags, message),MT_DEBUG|MSG_BS_LEAVE_LFS,0,0,ME);
+ }
+ // Message-Struktur anlegen
+ struct kobold_msg_s msg = (<kobold_msg_s> msg: message, prefix: indent,
+ sendername: uid, timestamp: time());
+ add_struct_tell_history(msg, sent, recv, flags);
}
protected void clear_tell_history(int force)
@@ -989,7 +1065,7 @@
msg = break_string(msg, 78, indent,
(QueryProp(P_MESSAGE_PREPEND) ? BS_PREPEND_INDENT : 0) | BS_LEAVE_MY_LFS);
- if(QueryProp(P_BUFFER) &&
+ if((QueryProp(P_BUFFER) & KOBOLD_ONLINE) &&
(deaf ||
query_editing(this_object()) ||
query_input_pending(this_object())))
@@ -1369,7 +1445,7 @@
return 1;
case -2:
// check KOBOLD
- ob = find_object(KOBOLD);
+ ob = load_object(KOBOLD);
lname = ({string|int})ob->find_player(lower_case(who));
if (lname == -1) {
ReceiveNotify("Das war nicht eindeutig!",MA_TELL);
@@ -1831,11 +1907,11 @@
More(sprintf("%@s", map(data[ptr..MAX_SAVED_MESSAGES-1] +
data[0..ptr-1],
- function string (struct stored_msg_s msg) {
+ function string (struct kobold_msg_s msg) {
if (!structp(msg)) return "";
return break_string(terminal_colour(msg->msg, colourmap)
- + " <"
- + strftime("%H:%M:%S",msg->timestamp) + ">", 78,
+ + " ["
+ + strftime("%H:%M:%S",msg->timestamp) + "]", 78,
msg->prefix || "", msg->prefix ? BS_LEAVE_MY_LFS : 0);
} ) ) );
return 1;
@@ -1986,7 +2062,7 @@
// Typen.
// Rueckgabe: 0 oder MSG_IGNORED | MSG_VERB_IGN | MSG_MUD_IGN
private int check_ignores(string msg, int msg_type, string msg_action,
- string msg_prefix, object origin)
+ string msg_prefix, object|string origin)
{
// Einige Dinge lassen sich nicht ignorieren.
if (msg_type & (MT_NEWS|MT_NOTIFICATION))
@@ -1996,9 +2072,14 @@
// eine ignorierbare msg_action geben.
else if (stringp(msg_action) && origin && origin != ME)
{
- string srcname =
+ string srcname;
+ if (objectp(origin))
+ srcname =
(query_once_interactive(origin) ? origin->query_real_name()
: origin->name(WER) || "");
+ else
+ srcname = origin;
+
mapping ign = Query(P_IGNORE, F_VALUE);
if (member(ign, srcname))
@@ -2178,7 +2259,7 @@
|| QueryProp(P_EARMUFFS))
{
if (!(flags & MSG_DONT_BUFFER)
- && QueryProp(P_BUFFER))
+ && (QueryProp(P_BUFFER) & KOBOLD_ONLINE))
{
// Nachricht soll im Kobold gespeichert werden.
return add_to_kobold(msg, msg_type, msg_action, msg_prefix, origin);
@@ -2213,3 +2294,36 @@
return MSG_DELIVERED;
}
+
+// called from base.c in Reconnect()
+protected void reconnect() {
+ // Cache fuer den report zuruecksetzen, der koennte veraltet sein (insb.
+ // falls in der letzten Session GMCP benutzt wurde und jetzt nicht).
+ report_cache = 0;
+}
+
+protected void updates_after_restore(int newflag) {
+ // Colourmap aktualisieren nach Restore
+ colourmap = build_colourmap(QueryProp(P_TTY));
+
+ // Altes Ignoriere loeschen...
+ mixed ign = Query(P_IGNORE,F_VALUE);
+ if (!mappingp(ign))
+ {
+ if (pointerp(ign))
+ ReceiveNotify(break_string(
+ "Deine Ignoriere-Einstellungen wurden soeben geloescht, "
+ "weil es eine Aktualisierung der Ignorierefunktion gab, "
+ "bei der eine Konversion der Daten leider nicht "
+ "moeglich war.",78), 0);
+
+ Set(P_IGNORE, ([]), F_VALUE);
+ }
+ // ggf. Comm-Vault abrufen oder neu erstellen.
+ setup_comm_vault();
+ // Wenn es eins gibt, den Inhalt zu unserem internen Koboldpuffer
+ // hinzufuegen, von wo es spaeter angezeigt wird.
+ if (commvault)
+ process_comm_vault(commvault);
+}
+
diff --git a/std/player/comm_structs.c b/std/player/comm_structs.c
index 03c132a..c0b3322 100644
--- a/std/player/comm_structs.c
+++ b/std/player/comm_structs.c
@@ -11,32 +11,29 @@
inherit "/std/living/comm_structs";
+// Struct fuer im Kobold, im Comm-Vault und in der TM-History gespeicherte
+// Nachrichten.
// Basiert auf allgemeiner msg_s Struktur aus living/comm-structs.c
struct kobold_msg_s (msg_s) {
string action; // Messageaction fuer ReceiveMsg
string sendername;// Ursprung der Nachricht
-};
-
-// Fuer gespeicherte Nachrichten (in der comm-History von Spielern) wird die
-// kobold_msg verwendet, aber es ist noch ein zusaetzlicher Zeitstempel
-// noetig.
-struct stored_msg_s (kobold_msg_s) {
int timestamp; // Zeitstempel der Nachricht
};
-struct msg_buffer_s {
- //struct msg_s *buf;
- mixed *buf;
+// Buffer fuer den Kobold im Spielerobjekt
+struct kobold_buffer_s {
+ struct kobold_msg_s *buf;
int index;
};
+// Struktur fuer Gespraeche in der TM-History
struct chat_s {
string uid; // UID des Gespraechspartners
int time_first_msg; // Zeit der ersten Nachricht
int time_last_msg; // Zeit der letzen Nachricht
int sentcount; // Anzahl gesendeter Nachrichten
int recvcount; // Anzahl empfangener Nachrichten
- mixed msgbuf; // Array von msg_s (Art Ringpuffer)
+ struct kobold_msg_s *msgbuf; // Array von kobold_msg_s (Art Ringpuffer)
int ptr; // Pointer auf die naechste zu ueberschreibende msg_s
// in msgbuf
};
diff --git a/std/player/comm_vault.c b/std/player/comm_vault.c
index 81541d6..af983ec 100644
--- a/std/player/comm_vault.c
+++ b/std/player/comm_vault.c
@@ -5,10 +5,10 @@
inherit "/std/player/comm_structs";
-nosave string uuid;
+private nosave string uuid;
// nosave ist wichtig - niemand soll den buffer mit save_value() auslesen
// koennen!
-nosave struct stored_msg_s *buffer = ({});
+private nosave struct kobold_msg_s *buffer = ({});
protected void create_lw()
{
@@ -20,9 +20,9 @@
return uuid;
}
-public struct stored_msg_s *Retrieve()
+public struct kobold_msg_s *Retrieve()
{
-// if (getuid(this_object()) == getuid(previous_object()))
+ if (uuid == getuuid(previous_object()))
{
return buffer;
}
@@ -31,7 +31,7 @@
public void Empty()
{
-// if (getuid(this_object()) == getuid(previous_object()))
+ if (uuid == getuuid(previous_object()))
{
buffer = ({});
}
@@ -48,7 +48,7 @@
if (sizeof(buffer) >= MAX_KOBOLD_LIMIT)
return MSG_BUFFER_FULL;
- buffer += ({ (<stored_msg_s> msg:msg, type:msg_type,
+ buffer += ({ (<kobold_msg_s> msg:msg, type:msg_type,
prefix: msg_prefix, action: msg_action,
sendername: ({string})origin.query_real_name(),
timestamp: time())