X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=tools%2Fquake3%2Fcommon%2Finout.c;fp=tools%2Fquake3%2Fcommon%2Finout.c;h=ede88891b465a7a31dcff980ba93e940e5b79c2e;hp=0000000000000000000000000000000000000000;hb=80378101101ca1762bbf5638a9e3566893096d8a;hpb=aa81b47cb7fc6f6ecf9ee50d420c4040d3bb8b66 diff --git a/tools/quake3/common/inout.c b/tools/quake3/common/inout.c new file mode 100644 index 00000000..ede88891 --- /dev/null +++ b/tools/quake3/common/inout.c @@ -0,0 +1,367 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// deal with in/out tasks, for either stdin/stdout or network/XML stream +// + +#include "cmdlib.h" +#include "mathlib.h" +#include "polylib.h" +#include "inout.h" +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +// network broadcasting +#include "l_net/l_net.h" +#include "libxml/tree.h" + +#ifdef _WIN32 +HWND hwndOut = NULL; +qboolean lookedForServer = qfalse; +UINT wm_BroadcastCommand = -1; +#endif + +socket_t *brdcst_socket; +netmessage_t msg; + +qboolean verbose = qfalse; + +// our main document +// is streamed through the network to Radiant +// possibly written to disk at the end of the run +//++timo FIXME: need to be global, required when creating nodes? +xmlDocPtr doc; +xmlNodePtr tree; + +// some useful stuff +xmlNodePtr xml_NodeForVec( vec3_t v ) +{ + xmlNodePtr ret; + char buf[1024]; + + sprintf (buf, "%f %f %f", v[0], v[1], v[2]); + ret = xmlNewNode (NULL, "point"); + xmlNodeSetContent (ret, buf); + return ret; +} + +// send a node down the stream, add it to the document +void xml_SendNode (xmlNodePtr node) +{ + xmlBufferPtr xml_buf; + char xmlbuf[MAX_NETMESSAGE]; // we have to copy content from the xmlBufferPtr into an aux buffer .. that sucks .. + // this index loops through the node buffer + int pos = 0; + int size; + + xmlAddChild( doc->children, node ); + + if (brdcst_socket) + { + xml_buf = xmlBufferCreate(); + xmlNodeDump( xml_buf, doc, node, 0, 0 ); + + // the XML node might be too big to fit in a single network message + // l_net library defines an upper limit of MAX_NETMESSAGE + // there are some size check errors, so we use MAX_NETMESSAGE-10 to be safe + // if the size of the buffer exceeds MAX_NETMESSAGE-10 we'll send in several network messages + while (pos < xml_buf->use) + { + // what size are we gonna send now? + (xml_buf->use - pos < MAX_NETMESSAGE - 10) ? (size = xml_buf->use - pos) : (size = MAX_NETMESSAGE - 10); + //++timo just a debug thing + if (size == MAX_NETMESSAGE - 10) + Sys_FPrintf (SYS_NOXML, "Got to split the buffer\n"); + memcpy( xmlbuf, xml_buf->content+pos, size); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); + // now that the thing is sent prepare to loop again + pos += size; + } + +#if 0 + // NOTE: the NMSG_WriteString is limited to MAX_NETMESSAGE + // we will need to split into chunks + // (we could also go lower level, in the end it's using send and receiv which are not size limited) + //++timo FIXME: MAX_NETMESSAGE is not exactly the max size we can stick in the message + // there's some tweaking to do in l_net for that .. so let's give us a margin for now + + //++timo we need to handle the case of a buffer too big to fit in a single message + // try without checks for now + if (xml_buf->use > MAX_NETMESSAGE-10 ) + { + // if we send that we are probably gonna break the stream at the other end.. + // and Error will call right there + //Error( "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + Sys_FPrintf (SYS_NOXML, "MAX_NETMESSAGE exceeded for XML feedback stream in FPrintf (%d)\n", xml_buf->use); + xml_buf->content[xml_buf->use]='\0'; //++timo this corrupts the buffer but we don't care it's for printing + Sys_FPrintf (SYS_NOXML, xml_buf->content); + + } + + size = xml_buf->use; + memcpy( xmlbuf, xml_buf->content, size ); + xmlbuf[size] = '\0'; + NMSG_Clear( &msg ); + NMSG_WriteString (&msg, xmlbuf ); + Net_Send(brdcst_socket, &msg ); +#endif + + xmlBufferFree( xml_buf ); + } +} + +void xml_Select (char *msg, int entitynum, int brushnum, qboolean bError) +{ + xmlNodePtr node, select; + char buf[1024]; + char level[2]; + + // now build a proper "select" XML node + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + node = xmlNewNode (NULL, "select"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + (bError ? SYS_ERR : SYS_WRN) ; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'select' information + sprintf (buf, "%i %i", entitynum, brushnum); + select = xmlNewNode (NULL, "brush"); + xmlNodeSetContent (select, buf); + xmlAddChild (node, select); + xml_SendNode (node); + + sprintf (buf, "Entity %i, Brush %i: %s", entitynum, brushnum, msg); + if (bError) + Error(buf); + else + Sys_FPrintf (SYS_NOXML, "%s\n", buf); + +} + +void xml_Point (char *msg, vec3_t pt) +{ + xmlNodePtr node, point; + char buf[1024]; + char level[2]; + + node = xmlNewNode (NULL, "pointmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'point' node + sprintf (buf, "%g %g %g", pt[0], pt[1], pt[2]); + point = xmlNewNode (NULL, "point"); + xmlNodeSetContent (point, buf); + xmlAddChild (node, point); + xml_SendNode (node); + + sprintf (buf, "%s (%g %g %g)", msg, pt[0], pt[1], pt[2]); + Error (buf); +} + +#define WINDING_BUFSIZE 2048 +void xml_Winding (char *msg, vec3_t p[], int numpoints, qboolean die) +{ + xmlNodePtr node, winding; + char buf[WINDING_BUFSIZE]; + char smlbuf[128]; + char level[2]; + int i; + + node = xmlNewNode (NULL, "windingmsg"); + xmlNodeSetContent (node, msg); + level[0] = (int)'0' + SYS_ERR; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level); + // a 'winding' node + sprintf( buf, "%i ", numpoints); + for(i = 0; i < numpoints; i++) + { + sprintf (smlbuf, "(%g %g %g)", p[i][0], p[i][1], p[i][2]); + // don't overflow + if (strlen(buf)+strlen(smlbuf)>WINDING_BUFSIZE) + break; + strcat( buf, smlbuf); + } + + winding = xmlNewNode (NULL, "winding"); + xmlNodeSetContent (winding, buf); + xmlAddChild (node, winding); + xml_SendNode (node); + + if(die) + Error (msg); + else + { + Sys_Printf(msg); + Sys_Printf("\n"); + } +} + +// in include +#include "stream_version.h" + +void Broadcast_Setup( const char *dest ) +{ + address_t address; + char sMsg[1024]; + + Net_Setup(); + Net_StringToAddress((char *)dest, &address); + brdcst_socket = Net_Connect(&address, 0); + if (brdcst_socket) + { + // send in a header + sprintf (sMsg, ""); + NMSG_Clear( &msg ); + NMSG_WriteString(&msg, sMsg ); + Net_Send(brdcst_socket, &msg ); + } +} + +void Broadcast_Shutdown() +{ + if (brdcst_socket) + { + Sys_Printf("Disconnecting\n"); + Net_Disconnect(brdcst_socket); + brdcst_socket = NULL; + } +} + +// all output ends up through here +void FPrintf (int flag, char *buf) +{ + xmlNodePtr node; + static qboolean bGotXML = qfalse; + char level[2]; + + printf(buf); + + // the following part is XML stuff only.. but maybe we don't want that message to go down the XML pipe? + if (flag == SYS_NOXML) + return; + + // ouput an XML file of the run + // use the DOM interface to build a tree + /* + + message string + .. various nodes to describe corresponding geometry .. + + */ + if (!bGotXML) + { + // initialize + doc = xmlNewDoc("1.0"); + doc->children = xmlNewDocRawNode(doc, NULL, "q3map_feedback", NULL); + bGotXML = qtrue; + } + node = xmlNewNode (NULL, "message"); + xmlNodeSetContent (node, buf); + level[0] = (int)'0' + flag; + level[1] = 0; + xmlSetProp (node, "level", (char *)&level ); + + xml_SendNode (node); +} + +#ifdef DBG_XML +void DumpXML() +{ + xmlSaveFile( "XMLDump.xml", doc ); +} +#endif + +void Sys_FPrintf (int flag, const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + if ((flag == SYS_VRB) && (verbose == qfalse)) + return; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (flag, out_buffer); +} + +void Sys_Printf (const char *format, ...) +{ + char out_buffer[4096]; + va_list argptr; + + va_start (argptr, format); + vsprintf (out_buffer, format, argptr); + va_end (argptr); + + FPrintf (SYS_STD, out_buffer); +} + +/* +================= +Error + +For abnormal program terminations +================= +*/ +void Error( const char *error, ...) +{ + char out_buffer[4096]; + char tmp[4096]; + va_list argptr; + + va_start (argptr,error); + vsprintf (tmp, error, argptr); + va_end (argptr); + + sprintf( out_buffer, "************ ERROR ************\n%s\n", tmp ); + + FPrintf( SYS_ERR, out_buffer ); + +#ifdef DBG_XML + DumpXML(); +#endif + + //++timo HACK ALERT .. if we shut down too fast the xml stream won't reach the listener. + // a clean solution is to send a sync request node in the stream and wait for an answer before exiting + Sys_Sleep( 1000 ); + + Broadcast_Shutdown(); + + exit (1); +} +