Beispiel #1
0
int C4Shader::ParsePosition(const char *szWhat, const char **ppPos)
{
	const char *pPos = *ppPos;
	while (isspace(*pPos)) pPos++;

	// Expect a name
	const char *pStart = pPos;
	while (isalnum(*pPos)) pPos++;
	StdStrBuf Name; Name.Copy(pStart, pPos - pStart);

	// Lookup name
	int iPosition = -1;
	for (int i = 0; i < sizeof(C4SH_PosNames) / sizeof(*C4SH_PosNames); i++) {
		if (SEqual(Name.getData(), C4SH_PosNames[i].Name)) {
			iPosition = C4SH_PosNames[i].Position;
			break;
		}
	}
	if (iPosition == -1) {
		ShaderLogF("  gl: Unknown slice position in %s: %s", szWhat, Name.getData());
		return -1;
	}

	// Add modifier
	while (isspace(*pPos)) pPos++;
	if (*pPos == '+') {
		int iMod, iModLen;
		if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
			ShaderLogF("  gl: Invalid slice modifier in %s", szWhat);
			return -1;
		}
		iPosition += iMod;
		pPos += 1+iModLen;
	}
	if (*pPos == '-') {
		int iMod, iModLen;
		if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
			ShaderLogF("  gl: Invalid slice modifier in %s", szWhat);
			return -1;
		}
		iPosition -= iMod;
		pPos += 1+iModLen;
	}

	// Everything okay!
	*ppPos = pPos;
	return iPosition;
}
Beispiel #2
0
C4GUI::Edit::InputResult C4ChatInputDialog::OnChatInput(C4GUI::Edit *edt,
                                                        bool fPasting,
                                                        bool fPastingMore) {
  // no double processing
  if (fProcessed) return C4GUI::Edit::IR_CloseDlg;
  // get edit text
  C4GUI::Edit *pEdt = reinterpret_cast<C4GUI::Edit *>(edt);
  char *szInputText = const_cast<char *>(pEdt->GetText());
  // Store to back buffer
  Game.MessageInput.StoreBackBuffer(szInputText);
  // script queried input?
  if (fObjInput) {
    fProcessed = true;
    // check if the target input is still valid
    C4Player *pPlr = Game.Players.Get(iPlr);
    if (!pPlr) return C4GUI::Edit::IR_CloseDlg;
    if (!pPlr->MarkMessageBoardQueryAnswered(pTarget)) {
      // there was no associated query!
      return C4GUI::Edit::IR_CloseDlg;
    }
    // then do a script callback, incorporating the input into the answer
    if (fUppercase) SCapitalize(szInputText);
    StdStrBuf sInput;
    sInput.Copy(szInputText);
    sInput.EscapeString();
    Game.Control.DoInput(
        CID_Script,
        new C4ControlScript(
            FormatString("OnMessageBoardAnswer(Object(%d), %d, \"%s\")",
                         pTarget ? pTarget->Number : 0, iPlr,
                         sInput.getData()).getData()),
        CDT_Decide);
    return C4GUI::Edit::IR_CloseDlg;
  } else
    // reroute to message input class
    Game.MessageInput.ProcessInput(szInputText);
  // safety: message board commands may do strange things
  if (!C4GUI::IsGUIValid() || this != pInstance) return C4GUI::Edit::IR_Abort;
  // select all text to be removed with next keypress
  // just for pasting mode; usually the dlg will be closed now anyway
  pEdt->SelectAll();
  // avoid dlg close, if more content is to be pasted
  if (fPastingMore) return C4GUI::Edit::IR_None;
  fProcessed = true;
  return C4GUI::Edit::IR_CloseDlg;
}
Beispiel #3
0
void C4ChatControl::ChatSheet::AddTextLine(const char *szText, uint32_t dwClr) {
  // strip stuff that would confuse Clonk
  StdStrBuf sText;
  sText.Copy(szText);
  for (char c = '\x01'; c < ' '; ++c) sText.ReplaceChar(c, ' ');
  // convert incoming UTF-8
  convUTF8toWindows(sText);
  // add text line to chat box
  CStdFont *pUseFont = &C4GUI::GetRes()->TextFont;
  pChatBox->AddTextLine(sText.getData(), pUseFont, dwClr, true, false);
  pChatBox->ScrollToBottom();
  // sheet now has unread messages if not selected
  if (!fHasUnread && !IsActiveSheet()) {
    fHasUnread = true;
    SetCaptionColor(C4GUI_Caption2FontClr);
  }
}
Beispiel #4
0
C4PortraitSelDlg::ListItem::ListItem(const char *szFilename)
    : C4FileSelDlg::ListItem(szFilename), fError(false), fLoaded(false) {
  CStdFont *pUseFont = &(C4GUI::GetRes()->MiniFont);
  // determine label text
  StdStrBuf sDisplayLabel;
  if (szFilename) {
    sDisplayLabel.Copy(::GetFilename(szFilename));
    ::RemoveExtension(&sDisplayLabel);
  } else {
    sDisplayLabel.Ref(LoadResStr("IDS_MSG_NOPORTRAIT"));
  }
  // insert linebreaks into label text
  int32_t iLineHgt = Max<int32_t>(
      pUseFont->BreakMessage(sDisplayLabel.getData(), ImagePreviewSize - 6,
                             &sFilenameLabelText, false),
      1);
  // set size
  SetBounds(C4Rect(0, 0, ImagePreviewSize, ImagePreviewSize + iLineHgt));
}
void C4DefGraphicsPtrBackup::Add(C4DefGraphics* pGfx)
{
	for(C4DefGraphics* pCur = pGfx; pCur != NULL; pCur = pCur->pNext)
		Entries.push_back(new C4DefGraphicsPtrBackupEntry(pCur));

	// Remove all mesh materials that were loaded from this definition
	C4Def* pDef = pGfx->pDef;
	for(StdMeshMatManager::Iterator iter = ::MeshMaterialManager.Begin(); iter != MeshMaterialManager.End(); )
	{
		StdStrBuf Filename;
		Filename.Copy(pDef->Filename);
		Filename.Append("/"); Filename.Append(GetFilename(iter->FileName.getData()));

		if(Filename == iter->FileName)
			iter = ::MeshMaterialManager.Remove(iter, &MeshMaterialUpdate);
		else
			++iter;
	}
}
Beispiel #6
0
C4FileSelDlg::DefaultListItem::DefaultListItem(const char *szFilename,
                                               bool fTruncateExtension,
                                               bool fCheckbox, bool fGrayed,
                                               C4GUI::Icons eIcon)
    : C4FileSelDlg::ListItem(szFilename),
      pLbl(NULL),
      pCheck(NULL),
      pKeyCheck(NULL),
      fGrayed(fGrayed) {
  StdStrBuf sLabel;
  if (szFilename)
    sLabel.Ref(::GetFilename(szFilename));
  else
    sLabel.Ref(LoadResStr("IDS_CTL_NONE"));
  if (szFilename && fTruncateExtension) {
    sLabel.Copy();
    char *szFilename = sLabel.GrabPointer();
    RemoveExtension(szFilename);
    sLabel.Take(szFilename);
  }
  rcBounds.Hgt = C4GUI::GetRes()->TextFont.GetLineHeight();
  UpdateSize();
  C4GUI::ComponentAligner caMain(GetContainedClientRect(), 0, 0);
  int32_t iHeight = caMain.GetInnerHeight();
  if (fCheckbox) {
    pCheck = new C4GUI::CheckBox(caMain.GetFromLeft(iHeight), NULL, false);
    if (fGrayed) pCheck->SetEnabled(false);
    AddElement(pCheck);
    pKeyCheck = new C4KeyBinding(
        C4KeyCodeEx(K_SPACE), "FileSelToggleFileActive", KEYSCOPE_Gui,
        new C4GUI::ControlKeyCB<ListItem>(*this, &ListItem::UserToggleCheck),
        C4CustomKey::PRIO_Ctrl);
  }
  C4GUI::Icon *pIco = new C4GUI::Icon(caMain.GetFromLeft(iHeight), eIcon);
  AddElement(pIco);
  pLbl = new C4GUI::Label(
      sLabel.getData(), caMain.GetAll(), ALeft,
      fGrayed ? C4GUI_CheckboxDisabledFontClr : C4GUI_CheckboxFontClr);
  AddElement(pLbl);
}
Beispiel #7
0
bool GetLogSection(size_t iStart, size_t iLength, StdStrBuf &rsOut)
	{
	if (!iLength) { rsOut.Clear(); return true; }
	// read section from log file
	CStdFile LogFileRead;
	char *szBuf, *szBufOrig; size_t iSize; // size exclusing terminator
	if (!LogFileRead.Load(sLogFileName.getData(), (BYTE **)&szBuf, (int *) &iSize, 1)) return false;
	szBufOrig = szBuf;
	// reduce to desired buffer section
	if (iStart > iSize) iStart = iSize;
	if (iStart + iLength > iSize) iLength = iSize - iStart;
	szBuf += iStart; szBuf[iLength] = '\0';
	// strip timestamps; convert linebreaks to Clonk-linebreaks '|'
	char *szPosWrite=szBuf; const char *szPosRead=szBuf;
	while (*szPosRead)
		{
		// skip timestamp
		if (*szPosRead == '[')
			while (*szPosRead && *szPosRead != ']') { --iSize; ++szPosRead; }
		// skip whitespace behind timestamp
		if (!*szPosRead) break;
		szPosRead++;
		// copy data until linebreak
		size_t iLen=0;
		while (*szPosRead && *szPosRead != 0x0d && *szPosRead != 0x0a)
			{ ++szPosRead; ++iLen; }
		if (iLen && szPosRead-iLen != szPosWrite) memmove(szPosWrite, szPosRead-iLen, iLen);
		szPosWrite += iLen;
		// skip additional linebreaks
		while (*szPosRead == 0x0d || *szPosRead == 0x0a) ++szPosRead;
		// write a Clonk-linebreak
		if (*szPosRead) *szPosWrite++ = '|';
		}
	// done; create string buffer from data
	rsOut.Copy(szBuf, szPosWrite - szBuf);
	// old buf no longer used
	delete [] szBufOrig;
	// done, success
	return true;
	}
void C4PlayerInfoListAttributeConflictResolver::ResolveInPacket()
{
	// check all player infos
	fAnyChange = false;
	int32_t iCheck = 0;
	while ((pResolveInfo = pResolvePacket->GetPlayerInfo(iCheck++)))
	{
		// not already joined? Joined player must not change their attributes!
		if (pResolveInfo->HasJoined()) continue;
		DWORD dwPrevColor = pResolveInfo->GetColor();
		StdStrBuf sPrevForcedName; sPrevForcedName.Copy(pResolveInfo->GetForcedName());
		// check attributes: Name and color
		for (eAttr = C4PlayerInfo::PLRATT_Color; eAttr != C4PlayerInfo::PLRATT_Last; eAttr = (C4PlayerInfo::Attribute) (eAttr+1))
		{
			if (eAttr == C4PlayerInfo::PLRATT_Color)
			{
				// no color change in savegame associations
				if (pResolveInfo->GetAssociatedSavegamePlayerID()) continue;
				// or forced team colors
				if (Game.Teams.IsTeamColors() && Game.Teams.GetTeamByID(pResolveInfo->GetTeam())) continue;
			}
			else if (eAttr == C4PlayerInfo::PLRATT_Name)
			{
				// no name change if a league name is used
				if (pResolveInfo->getLeagueAccount() && *pResolveInfo->getLeagueAccount()) continue;
			}
			// not if attributes are otherwise fixed (e.g., for script players)
			if (pResolveInfo->IsAttributesFixed()) continue;
			// resolve in this info
			ResolveInInfo();
		}
		// mark change for return value if anything was changed
		if (pResolveInfo->GetColor() != dwPrevColor || (pResolveInfo->GetForcedName() != sPrevForcedName))
			fAnyChange = true;
		// next player info check
	}
	// mark update if anything was changed
	if (fAnyChange) pResolvePacket->SetUpdated();
}
Beispiel #9
0
void C4GameSave::WriteDescDefinitions(StdStrBuf &sBuf)
{
	// Definition specs
	if (Game.DefinitionFilenames[0])
	{
		char szDef[_MAX_PATH+1];
		// Desc
		sBuf.Append(LoadResStr("IDS_DESC_DEFSPECS"));
		// Get definition modules
		for (int cnt=0; SGetModule(Game.DefinitionFilenames,cnt,szDef); cnt++)
		{
			// Get exe relative path
			StdStrBuf sDefFilename;
			sDefFilename.Copy(Config.AtRelativePath(szDef));
			// Append comma
			if (cnt>0) sBuf.Append(", ");
			// Apend to desc
			sBuf.Append(sDefFilename);
		}
		// End of line
		WriteDescLineFeed(sBuf);
	}
}
bool C4ScriptHost::LoadData(const char *szFilename, const char *szData, class C4LangStringTable *pLocalTable)
{
	// String Table
	if (stringTable != pLocalTable)
	{
		if (stringTable) stringTable->DelRef();
		stringTable = pLocalTable;
		if (stringTable) stringTable->AddRef();
	}
	ScriptName.Copy(szFilename);

	StdStrBuf tempScript;
	tempScript.Copy(szData);

	Script.Clear();
	if(stringTable)
		stringTable->ReplaceStrings(tempScript, Script);
	else
		Script.Take(tempScript);

	Preparse();
	return true;
}
Beispiel #11
0
bool C4ComponentHost::GetLanguageString(const char *szLanguage,
                                        StdStrBuf &rTarget) {
  const char *cptr;
  // No good parameters
  if (!szLanguage || !Data) return false;
  // Search for two-letter language identifier in text body, i.e. "DE:"
  char langindex[4] = "";
  for (int clseg = 0;
       SCopySegment(szLanguage ? szLanguage : "", clseg, langindex, ',', 2);
       clseg++) {
    SAppend(":", langindex);
    if (cptr = SSearch(Data.getData(), langindex)) {
      // Return the according string
      int iEndPos = SCharPos('\r', cptr);
      if (iEndPos < 0) iEndPos = SCharPos('\n', cptr);
      if (iEndPos < 0) iEndPos = strlen(cptr);
      rTarget.Copy(cptr, iEndPos);
      return true;
    }
  }
  // Language string not found
  return false;
}
Beispiel #12
0
StdStrBuf C4Team::GetNameWithParticipants() const
{
	// compose team name like "Team 1 (boni, GhostBear, Clonko)"
	// or just "Team 1" for empty team
	StdStrBuf sTeamName;
	sTeamName.Copy(GetName());
	if (GetPlayerCount())
	{
		sTeamName.Append(" (");
		int32_t iTeamPlrCount=0;
		for (int32_t j=0; j<GetPlayerCount(); ++j)
		{
			int32_t iPlr = GetIndexedPlayer(j);
			C4PlayerInfo *pPlrInfo;
			if (iPlr) if  ((pPlrInfo = Game.PlayerInfos.GetPlayerInfoByID(iPlr)))
				{
					if (iTeamPlrCount++) sTeamName.Append(", ");
					sTeamName.Append(pPlrInfo->GetName());
				}
		}
		sTeamName.AppendChar(')');
	}
	return sTeamName;
}
Beispiel #13
0
void C4Shader::AddSlices(ShaderSliceList& slices, const char *szWhat, const char *szText, const char *szSource, int iSourceTime)
{
	const char *pStart = szText, *pPos = szText;
	int iDepth = -1;
	int iPosition = -1;
	bool fGotContent = false; // Anything in the slice apart from comments and white-space?

	// Find slices
	while(*pPos) {

		// Comment? Might seem silly, but we don't want to get confused by braces in comments...
		if (*pPos == '/' && *(pPos + 1) == '/') {
			pPos += 2;
			while (*pPos && *pPos != '\n') pPos++;
			continue;
		}
		if (*pPos == '/' && *(pPos + 1) == '*') {
			pPos += 2;
			while (*pPos && (*pPos != '*' || *(pPos+1) != '/')) pPos++;
			if (*pPos) pPos += 2;
			continue;
		}

		// Opening brace?
		if (*pPos == '{') {
			iDepth++; pPos++;
			continue;
		}
		if (*pPos == '}') {
			// End of slice?
			if (iPosition != -1 && !iDepth) {

				// Have a new slice!
				if (fGotContent)
				{
					StdStrBuf Str; Str.Copy(pStart, pPos - pStart);
					AddSlice(slices, iPosition, Str.getData(), szSource, iSourceTime);
				}

				iPosition = -1;
				pStart = pPos+1;
				fGotContent = false;
			}
			if (iDepth >= 0)
				iDepth--;
			pPos++;
			continue;
		}

		// New slice? We need a newline followed by "slice". Don't do
		// the depth check, so that we also recognize slices inside
		// an ifdefed-out "void main() {" block.
		if (*pPos == '\n') {
			if (SEqual2(pPos+1, "slice") && !isalnum(*(pPos+6))) {
				const char *pSliceEnd = pPos; pPos += 6;
				while(isspace(*pPos)) pPos++;
				if(*pPos != '(') { pPos++; continue; }
				pPos++;

				// Now let's parse the position
				iPosition = ParsePosition(szWhat, &pPos);
				if (iPosition != -1) {
					// Make sure a closing parenthesis
					while(isspace(*pPos)) pPos++;
					if(*pPos != ')') { pPos++; continue; }
					pPos++;

					// Make sure an opening brace follows
					while(isspace(*pPos)) pPos++;
					if (*pPos == '{') {

						// Add code before "slice" as new slice
						if (fGotContent)
						{
							StdStrBuf Str; Str.Copy(pStart, pSliceEnd - pStart);
							AddSlice(slices, -1, Str.getData(), szSource, iSourceTime);
						}

						iDepth = 0;
						pStart = pPos+1;
						fGotContent = false;
					} else {
						ShaderLogF("  gl: Missing opening brace in %s!", szWhat);
					}
					pPos++;
					continue;
				}
			}
		}

		// Otherwise: Continue
		if (!isspace(*pPos)) fGotContent = true;
		pPos++;
	}

	// Add final slice
	if (fGotContent)
	{
		StdStrBuf Str; Str.Copy(pStart, pPos - pStart);
		AddSlice(slices, iPosition, Str.getData(), szSource, iSourceTime);
	}

}
bool C4Application::DoInit(int argc, char * argv[])
{
	assert(AppState == C4AS_None);
	// Config overwrite by parameter
	StdStrBuf sConfigFilename;
	for (int32_t iPar=0; iPar < argc; iPar++)
		if (SEqual2NoCase(argv[iPar], "--config="))
			sConfigFilename.Copy(argv[iPar] + 9);
	// Config check
	Config.Init();
	Config.Load(sConfigFilename.getData());
	Config.Save();
	// sometimes, the configuration can become corrupted due to loading errors or w/e
	// check this and reset defaults if necessary
	if (Config.IsCorrupted())
	{
		if (sConfigFilename)
		{
			// custom config corrupted: Fail
			Log("ERROR: Custom configuration corrupted - program abort!\n");
			return false;
		}
		else
		{
			// default config corrupted: Restore default
			Log("Warning: Configuration corrupted - restoring default!\n");
			Config.Default();
			Config.Save();
			Config.Load();
		}
	}
	// Open log
	OpenLog();

	Revision.Ref(C4REVISION);

	// Engine header message
	Log(C4ENGINECAPTION);
	LogF("Version: %s %s (%s)", C4VERSION, C4_OS, Revision.getData());
	LogF("ExePath: \"%s\"", Config.General.ExePath.getData());
	LogF("SystemDataPath: \"%s\"", Config.General.SystemDataPath);
	LogF("UserDataPath: \"%s\"", Config.General.UserDataPath);

	// Init C4Group
	C4Group_SetProcessCallback(&ProcessCallback);
	C4Group_SetTempPath(Config.General.TempPath.getData());
	C4Group_SetSortList(C4CFN_FLS);

	// Cleanup temp folders left behind
	Config.CleanupTempUpdateFolder();

	// Initialize game data paths
	Reloc.Init();

	// init system group
	if (!Reloc.Open(SystemGroup, C4CFN_System))
	{
		// Error opening system group - no LogFatal, because it needs language table.
		// This will *not* use the FatalErrors stack, but this will cause the game
		// to instantly halt, anyway.
		const char *szMessage = "Error opening system group file (System.ocg)!";
		Log(szMessage);
		// Fatal error, game cannot start - have player notice
		MessageDialog(szMessage);
		return false;
	}
	// Parse command line
	ParseCommandLine(argc, argv);

	// Open additional logs that depend on command line
	OpenExtraLogs();

	// Init external language packs
	Languages.Init();
	// Load language string table
	if (!Languages.LoadLanguage(Config.General.LanguageEx))
		// No language table was loaded - bad luck...
		if (!Languages.HasStringTable())
			Log("WARNING: No language string table loaded!");

#if defined(WIN32) && defined(WITH_AUTOMATIC_UPDATE)
	// Windows: handle incoming updates directly, even before starting up the gui
	//          because updates will be applied in the console anyway.
	if (Application.IncomingUpdate)
		if (C4UpdateDlg::ApplyUpdate(Application.IncomingUpdate.getData(), false, NULL))
			return true;
#endif

	// Fixup resolution
	if (!Config.Graphics.Windowed)
		ApplyResolutionConstraints();

	// activate
	Active=true;

	// Init carrier window
	if (!isEditor)
	{
		if (!(pWindow = FullScreen.Init(this)))
			{ Clear(); ShowGfxErrorDialog(); return false; }
	}
	else
	{
		if (!(pWindow = Console.Init(this)))
			{ Clear(); return false; }
	}

	// init timers (needs window)
	Add(pGameTimer = new C4ApplicationGameTimer());

	// Initialize OpenGL
	bool success = DDrawInit(this, GetConfigWidth(), GetConfigHeight(), Config.Graphics.BitDepth, Config.Graphics.Monitor);
	if (!success) { LogFatal(LoadResStr("IDS_ERR_DDRAW")); Clear(); ShowGfxErrorDialog(); return false; }

	if (!isEditor)
	{
		if (!SetVideoMode(Application.GetConfigWidth(), Application.GetConfigHeight(), Config.Graphics.BitDepth, Config.Graphics.RefreshRate, Config.Graphics.Monitor, !Config.Graphics.Windowed))
			pWindow->SetSize(Config.Graphics.WindowX, Config.Graphics.WindowY);
	}

	// Initialize gamepad
	if (!pGamePadControl && Config.General.GamepadEnabled)
		pGamePadControl = new C4GamePadControl();

	AppState = C4AS_PreInit;

	return true;
}
Beispiel #15
0
bool C4MessageInput::ProcessCommand(const char *szCommand) {
  C4GameLobby::MainDlg *pLobby = Game.Network.GetLobby();
  // command
  char szCmdName[C4MaxName + 1];
  SCopyUntil(szCommand + 1, szCmdName, ' ', C4MaxName);
  // parameter
  const char *pCmdPar = SSearch(szCommand, " ");
  if (!pCmdPar) pCmdPar = "";

  // dev-scripts
  if (SEqual(szCmdName, "help")) {
    LogF(LoadResStr("IDS_TEXT_COMMANDSAVAILABLEDURINGGA"));
    LogF("/private [player] [message] - %s",
         LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOTHES"));
    LogF("/team [message] - %s",
         LoadResStr("IDS_MSG_SENDAPRIVATEMESSAGETOYOUR"));
    LogF("/me [action] - %s", LoadResStr("IDS_TEXT_PERFORMANACTIONINYOURNAME"));
    LogF("/sound [sound] - %s",
         LoadResStr("IDS_TEXT_PLAYASOUNDFROMTHEGLOBALSO"));
    LogF("/kick [client] - %s", LoadResStr("IDS_TEXT_KICKTHESPECIFIEDCLIENT"));
    LogF("/observer [client] - %s",
         LoadResStr("IDS_TEXT_SETTHESPECIFIEDCLIENTTOOB"));
    LogF("/fast [x] - %s", LoadResStr("IDS_TEXT_SETTOFASTMODESKIPPINGXFRA"));
    LogF("/slow - %s", LoadResStr("IDS_TEXT_SETTONORMALSPEEDMODE"));
    LogF("/chart - %s", LoadResStr("IDS_TEXT_DISPLAYNETWORKSTATISTICS"));
    LogF("/nodebug - %s", LoadResStr("IDS_TEXT_PREVENTDEBUGMODEINTHISROU"));
    LogF("/set comment [comment] - %s",
         LoadResStr("IDS_TEXT_SETANEWNETWORKCOMMENT"));
    LogF("/set password [password] - %s",
         LoadResStr("IDS_TEXT_SETANEWNETWORKPASSWORD"));
    LogF("/set faircrew [on/off] - %s",
         LoadResStr("IDS_TEXT_ENABLEORDISABLEFAIRCREW"));
    LogF("/set maxplayer [4] - %s",
         LoadResStr("IDS_TEXT_SETANEWMAXIMUMNUMBEROFPLA"));
    LogF("/script [script] - %s", LoadResStr("IDS_TEXT_EXECUTEASCRIPTCOMMAND"));
    LogF("/clear - %s", LoadResStr("IDS_MSG_CLEARTHEMESSAGEBOARD"));
    return TRUE;
  }
  // dev-scripts
  if (SEqual(szCmdName, "script")) {
    if (!Game.IsRunning) return FALSE;
    if (!Game.DebugMode) return FALSE;
    if (!Game.Network.isEnabled() &&
        !SEqual(Game.ScenarioFile.GetMaker(), Config.General.Name) &&
        Game.ScenarioFile.GetStatus() != GRPF_Folder)
      return FALSE;
    if (Game.Network.isEnabled() && !Game.Network.isHost()) return FALSE;

    Game.Control.DoInput(
        CID_Script,
        new C4ControlScript(pCmdPar, C4ControlScript::SCOPE_Console, false),
        CDT_Decide);
    return TRUE;
  }
  // set runtimte properties
  if (SEqual(szCmdName, "set")) {
    if (SEqual2(pCmdPar, "maxplayer ")) {
      if (Game.Control.isCtrlHost()) {
        if (atoi(pCmdPar + 10) == 0 && !SEqual(pCmdPar + 10, "0")) {
          Log("Syntax: /set maxplayer count");
          return FALSE;
        }
        Game.Control.DoInput(
            CID_Set, new C4ControlSet(C4CVT_MaxPlayer, atoi(pCmdPar + 10)),
            CDT_Decide);
        return TRUE;
      }
    }
    if (SEqual2(pCmdPar, "comment ") || SEqual(pCmdPar, "comment")) {
      if (!Game.Network.isEnabled() || !Game.Network.isHost()) return FALSE;
      // Set in configuration, update reference
      Config.Network.Comment.CopyValidated(pCmdPar[7] ? (pCmdPar + 8) : "");
      Game.Network.InvalidateReference();
      Log(LoadResStr("IDS_NET_COMMENTCHANGED"));
      return TRUE;
    }
    if (SEqual2(pCmdPar, "password ") || SEqual(pCmdPar, "password")) {
      if (!Game.Network.isEnabled() || !Game.Network.isHost()) return FALSE;
      Game.Network.SetPassword(pCmdPar[8] ? (pCmdPar + 9) : NULL);
      if (pLobby) pLobby->UpdatePassword();
      return TRUE;
    }
    if (SEqual2(pCmdPar, "faircrew ")) {
      if (!Game.Control.isCtrlHost() || Game.Parameters.isLeague())
        return FALSE;
      C4ControlSet *pSet = NULL;
      if (SEqual(pCmdPar + 9, "on"))
        pSet =
            new C4ControlSet(C4CVT_FairCrew, Config.General.FairCrewStrength);
      else if (SEqual(pCmdPar + 9, "off"))
        pSet = new C4ControlSet(C4CVT_FairCrew, -1);
      else if (isdigit((unsigned char)pCmdPar[9]))
        pSet = new C4ControlSet(C4CVT_FairCrew, atoi(pCmdPar + 9));
      else
        return FALSE;
      Game.Control.DoInput(CID_Set, pSet, CDT_Decide);
      return TRUE;
    }
    // unknown property
    return FALSE;
  }
  // get szen from network folder - not in lobby; use res tab there
  if (SEqual(szCmdName, "netgetscen")) {
    if (Game.Network.isEnabled() && !Game.Network.isHost() && !pLobby) {
      const C4Network2ResCore *pResCoreScen =
          Game.Parameters.Scenario.getResCore();
      if (pResCoreScen) {
        C4Network2Res::Ref pScenario =
            Game.Network.ResList.getRefRes(pResCoreScen->getID());
        if (pScenario)
          if (C4Group_CopyItem(
                  pScenario->getFile(),
                  Config.AtExePath(GetFilename(Game.ScenarioFilename)))) {
            LogF(LoadResStr("IDS_MSG_CMD_NETGETSCEN_SAVED"),
                 Config.AtExePath(GetFilename(Game.ScenarioFilename)));
            return TRUE;
          }
      }
    }
    return FALSE;
  }
  // clear message board
  if (SEqual(szCmdName, "clear")) {
    // lobby
    if (pLobby) {
      pLobby->ClearLog();
    }
    // fullscreen
    else if (Game.GraphicsSystem.MessageBoard.Active)
      Game.GraphicsSystem.MessageBoard.ClearLog();
    else {
      // EM mode
      Console.ClearLog();
    }
    return TRUE;
  }
  // kick client
  if (SEqual(szCmdName, "kick")) {
    if (Game.Network.isEnabled() && Game.Network.isHost()) {
      // find client
      C4Client *pClient = Game.Clients.getClientByName(pCmdPar);
      if (!pClient) {
        LogF(LoadResStr("IDS_MSG_CMD_NOCLIENT"), pCmdPar);
        return FALSE;
      }
      // league: Kick needs voting
      if (Game.Parameters.isLeague() &&
          Game.Players.GetAtClient(pClient->getID()))
        Game.Network.Vote(VT_Kick, true, pClient->getID());
      else
        // add control
        Game.Clients.CtrlRemove(pClient,
                                LoadResStr("IDS_MSG_KICKFROMMSGBOARD"));
    }
    return TRUE;
  }
  // set fast mode
  if (SEqual(szCmdName, "fast")) {
    if (!Game.IsRunning) return FALSE;
    if (Game.Parameters.isLeague()) {
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
      return FALSE;
    }
    int32_t iFS;
    if ((iFS = atoi(pCmdPar)) == 0) return FALSE;
    // set frameskip and fullspeed flag
    Game.FrameSkip = BoundBy<int32_t>(iFS, 1, 500);
    Game.FullSpeed = TRUE;
    // start calculation immediatly
    Application.NextTick(false);
    return TRUE;
  }
  // reset fast mode
  if (SEqual(szCmdName, "slow")) {
    if (!Game.IsRunning) return FALSE;
    Game.FullSpeed = FALSE;
    Game.FrameSkip = 1;
    return TRUE;
  }

  if (SEqual(szCmdName, "nodebug")) {
    if (!Game.IsRunning) return FALSE;
    Game.Control.DoInput(CID_Set, new C4ControlSet(C4CVT_AllowDebug, false),
                         CDT_Decide);
    return TRUE;
  }

  if (SEqual(szCmdName, "msgboard")) {
    if (!Game.IsRunning) return FALSE;
    // get line cnt
    int32_t iLineCnt = BoundBy(atoi(pCmdPar), 0, 20);
    if (iLineCnt == 0)
      Game.GraphicsSystem.MessageBoard.ChangeMode(2);
    else if (iLineCnt == 1)
      Game.GraphicsSystem.MessageBoard.ChangeMode(0);
    else {
      Game.GraphicsSystem.MessageBoard.iLines = iLineCnt;
      Game.GraphicsSystem.MessageBoard.ChangeMode(1);
    }
    return TRUE;
  }

  // kick/activate/deactivate/observer
  if (SEqual(szCmdName, "activate") || SEqual(szCmdName, "deactivate") ||
      SEqual(szCmdName, "observer")) {
    if (!Game.Network.isEnabled() || !Game.Network.isHost()) {
      Log(LoadResStr("IDS_MSG_CMD_HOSTONLY"));
      return FALSE;
    }
    // search for client
    C4Client *pClient = Game.Clients.getClientByName(pCmdPar);
    if (!pClient) {
      LogF(LoadResStr("IDS_MSG_CMD_NOCLIENT"), pCmdPar);
      return FALSE;
    }
    // what to do?
    C4ControlClientUpdate *pCtrl = NULL;
    if (szCmdName[0] == 'a')  // activate
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_Activate, true);
    else if (szCmdName[0] == 'd' && !Game.Parameters.isLeague())  // deactivate
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_Activate, false);
    else if (szCmdName[0] == 'o' && !Game.Parameters.isLeague())  // observer
      pCtrl = new C4ControlClientUpdate(pClient->getID(), CUT_SetObserver);
    // perform it
    if (pCtrl)
      Game.Control.DoInput(CID_ClientUpdate, pCtrl, CDT_Sync);
    else
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
    return TRUE;
  }

  // control mode
  if (SEqual(szCmdName, "centralctrl") || SEqual(szCmdName, "decentralctrl") ||
      SEqual(szCmdName, "asyncctrl")) {
    if (!Game.Network.isEnabled() || !Game.Network.isHost()) {
      Log(LoadResStr("IDS_MSG_CMD_HOSTONLY"));
      return FALSE;
    }
    if (Game.Parameters.isLeague() && *szCmdName == 'a') {
      Log(LoadResStr("IDS_LOG_COMMANDNOTALLOWEDINLEAGUE"));
      return FALSE;
    }
    Game.Network.SetCtrlMode(
        *szCmdName == 'c' ? CNM_Central : *szCmdName == 'd' ? CNM_Decentral
                                                            : CNM_Async);
    return TRUE;
  }

  // show chart
  if (Game.IsRunning)
    if (SEqual(szCmdName, "chart")) return Game.ToggleChart();

  // custom command
  C4MessageBoardCommand *pCmd;
  if (Game.IsRunning)
    if (pCmd = GetCommand(szCmdName)) {
      StdStrBuf Script, CmdScript;
      // replace %player% by calling player number
      if (SSearch(pCmd->Script, "%player%")) {
        int32_t iLocalPlr = NO_OWNER;
        C4Player *pLocalPlr = Game.Players.GetLocalByIndex(0);
        if (pLocalPlr) iLocalPlr = pLocalPlr->Number;
        StdStrBuf sLocalPlr;
        sLocalPlr.Format("%d", iLocalPlr);
        CmdScript.Copy(pCmd->Script);
        CmdScript.Replace("%player%", sLocalPlr.getData());
      } else {
        CmdScript.Ref(pCmd->Script);
      }
      // insert parameters
      if (SSearch(CmdScript.getData(), "%d")) {
        // make sure it's a number by converting
        Script.Format(CmdScript.getData(), (int)atoi(pCmdPar));
      } else if (SSearch(CmdScript.getData(), "%s")) {
        // Unrestricted parameters?
        // That's kind of a security risk as it will allow anyone to execute
        // code
        switch (pCmd->eRestriction) {
          case C4MessageBoardCommand::C4MSGCMDR_Escaped: {
            // escape strings
            StdStrBuf Par;
            Par.Copy(pCmdPar);
            Par.EscapeString();
            // compose script
            Script.Format(CmdScript.getData(), Par.getData());
          } break;

          case C4MessageBoardCommand::C4MSGCMDR_Plain:
            // unescaped
            Script.Format(CmdScript.getData(), pCmdPar);
            break;

          case C4MessageBoardCommand::C4MSGCMDR_Identifier: {
            // only allow identifier-characters
            StdStrBuf Par;
            while (IsIdentifier(*pCmdPar) || isspace((unsigned char)*pCmdPar))
              Par.AppendChar(*pCmdPar++);
            // compose script
            Script.Format(CmdScript.getData(), Par.getData());
          } break;
        }
      } else
        Script = CmdScript.getData();
      // add script
      Game.Control.DoInput(CID_Script, new C4ControlScript(Script.getData()),
                           CDT_Decide);
      // ok
      return TRUE;
    }

  // unknown command
  StdStrBuf sErr;
  sErr.Format(LoadResStr("IDS_ERR_UNKNOWNCMD"), szCmdName);
  if (pLobby)
    pLobby->OnError(sErr.getData());
  else
    Log(sErr.getData());
  return FALSE;
}
bool C4UpdateDlg::ApplyUpdate(const char *strUpdateFile, bool fDeleteUpdate, C4GUI::Screen *pScreen)
{
	// Apply update: If the update file is a .ocu, it will extract c4group and apply the update.
	// If the update file is an installer, it will just launch that installer.
	StdStrBuf strUpdateProgEx, strUpdateArgs;
	bool fIsGroupUpdate = SEqualNoCase(GetExtension(strUpdateFile), C4CFN_UpdateGroupExtension+1);
	// Is this an update executable or an update group?
	if (fIsGroupUpdate)
	{
		// This is an update group (.ocu). Extract c4group and run it.
		// Find a place to extract the update
		Config.MakeTempUpdateFolder();
		// Determine name of update program
		StdStrBuf strUpdateProg;
		strUpdateProg.Copy(C4CFN_UpdateProgram);
		// Windows: manually append extension because ExtractEntry() cannot properly glob and Extract() doesn't return failure values
#ifdef _WIN32
		strUpdateProg += ".exe";
#endif
		// Determine name of local extract of update program
		strUpdateProgEx.Copy(Config.AtTempUpdatePath(strUpdateProg.getData()));

		// Extract update program (the update should be applied using the new version)
		C4Group UpdateGroup;
		if (!UpdateGroup.Open(strUpdateFile))
		{
			LogF("Error opening \"%s\": %s", strUpdateFile, UpdateGroup.GetError());
			return false;
		}
		// Look for update program at top level
		if (!UpdateGroup.ExtractEntry(strUpdateProg.getData(), strUpdateProgEx.getData()))
		{
			LogF("Error extracting \"%s\": %s", strUpdateProg.getData(), UpdateGroup.GetError());
			return false;
		}
		// Extract any needed library files
		UpdateGroup.Extract(C4CFN_UpdateProgramLibs, Config.AtTempUpdatePath(""), C4CFN_UpdateProgram);
		UpdateGroup.Close();
#ifdef _WIN32
		// Notice: even if the update program and update group are in the temp path, they must be executed in our working directory
		DWORD ProcessID = GetCurrentProcessId();
		//strUpdateArgs.Format("\"%s\" \"%s\" %s %lu", strUpdateProgEx.getData(), strUpdateFile, fDeleteUpdate ? "-yd" : "-y", (unsigned long)ProcessID);
		strUpdateArgs.Format("\"%s\" %s %lu", strUpdateFile, fDeleteUpdate ? "-yd" : "-y", (unsigned long)ProcessID);

#if 0 // debug code to reroute updating via batch file
		CStdFile f; - reroute via vi
		f.Create(Config.AtTempUpdatePath("update.bat"));
		f.WriteString(FormatString("%s %s\npause\n", strUpdateProgEx.getData(), strUpdateArgs.getData()).getData());
		f.Close();
		strUpdateProgEx.Copy(Config.AtTempUpdatePath("update.bat"));
		strUpdateArgs.Copy(strUpdateProgEx);
#endif
#endif
	}
	else
	{
		// This "update" is actually an installer. Just run it.
		strUpdateProgEx = strUpdateFile;
		strUpdateArgs = "";
		// if group was downloaded to temp path, delete it from there
		if (fDeleteUpdate) SCopy(strUpdateProgEx.getData(), Config.General.TempUpdatePath, CFG_MaxString);
	}

	// Execute update program
	Log(LoadResStr("IDS_PRC_LAUNCHINGUPDATE"));
	succeeded = true;

#ifdef _WIN32
	// Notice: even if the update program and update group are in the temp path, they must be executed in our working directory
	// the magic verb "runas" opens the update program in a shell requesting elevation
	int iError = (intptr_t)ShellExecute(NULL, L"runas", strUpdateProgEx.GetWideChar(), strUpdateArgs.GetWideChar(), Config.General.ExePath.GetWideChar(), SW_SHOW);
	if (iError <= 32) return false;

	// must quit ourselves for update program to work
	if (succeeded) Application.Quit();
#else
	if (pipe(c4group_output) == -1)
	{
		Log("Error creating pipe");
		return false;
	}
	switch (pid = fork())
	{
		// Error
	case -1:
		Log("Error creating update child process.");
		return false;
		// Child process
	case 0:
		// Close unused read end
		close(c4group_output[0]);
		// redirect stdout and stderr to the parent
		dup2(c4group_output[1], STDOUT_FILENO);
		dup2(c4group_output[1], STDERR_FILENO);
		if (c4group_output[1] != STDOUT_FILENO && c4group_output[1] != STDERR_FILENO)
			close(c4group_output[1]);
		if (fIsGroupUpdate)
			execl(C4CFN_UpdateProgram, C4CFN_UpdateProgram, "-v", strUpdateFile, (fDeleteUpdate ? "-yd" : "-y"), static_cast<char *>(0));
		else
			execl(strUpdateFile, strUpdateFile, static_cast<char *>(0));
		printf("execl failed: %s\n", strerror(errno));
		exit(1);
		// Parent process
	default:
		// Close unused write end
		close(c4group_output[1]);
		// disable blocking
		fcntl(c4group_output[0], F_SETFL, O_NONBLOCK);
		// Open the update log dialog (this will update itself automatically from c4group_output)
		pScreen->ShowRemoveDlg(new C4UpdateDlg());
		break;
	}
#endif
	// done
	return succeeded;
}
bool C4UpdateDlg::CheckForUpdates(C4GUI::Screen *pScreen, bool fAutomatic)
{
	// Automatic update only once a day
	if (fAutomatic)
		if (time(NULL) - Config.Network.LastUpdateTime < 60 * 60 * 24)
			return false;
	// Store the time of this update check (whether it's automatic or not or successful or not)
	Config.Network.LastUpdateTime = time(NULL);
	// Get current update url and version info from server
	StdStrBuf UpdateURL;
	StdStrBuf VersionInfo;
	C4GUI::Dialog *pWaitDlg = NULL;
	pWaitDlg = new C4GUI::MessageDialog(LoadResStr("IDS_MSG_LOOKINGFORUPDATES"), LoadResStr("IDS_TYPE_UPDATE"), C4GUI::MessageDialog::btnAbort, C4GUI::Ico_Ex_Update, C4GUI::MessageDialog::dsRegular);
	pWaitDlg->SetDelOnClose(false);
	pScreen->ShowDialog(pWaitDlg, false);

	C4Network2UpdateClient UpdateClient;
	bool fSuccess = false, fAborted = false;
	StdStrBuf strVersion; strVersion.Format("%d.%d", C4XVER1, C4XVER2);
	StdStrBuf strQuery; strQuery.Format("%s?version=%s&platform=%s&action=version", Config.Network.UpdateServerAddress, strVersion.getData(), C4_OS);
	if (UpdateClient.Init() && UpdateClient.SetServer(strQuery.getData()) && UpdateClient.QueryUpdateURL())
	{
		UpdateClient.SetNotify(&Application.InteractiveThread);
		Application.InteractiveThread.AddProc(&UpdateClient);
		// wait for version check to terminate
		while (UpdateClient.isBusy())
		{
			// wait, check for program abort
			if (!Application.ScheduleProcs()) { fAborted = true; break; }
			// check for dialog close
			if (pWaitDlg) if (!pWaitDlg->IsShown())  { fAborted = true; break; }
		}
		if (!fAborted) 
		{
			fSuccess = UpdateClient.GetVersion(&VersionInfo);
			UpdateClient.GetUpdateURL(&UpdateURL);
		}
		Application.InteractiveThread.RemoveProc(&UpdateClient);
		UpdateClient.SetNotify(NULL);
	}
	delete pWaitDlg;
	// User abort
	if (fAborted)
	{
		return false;
	}
	// Error during update check
	if (!fSuccess)
	{
		StdStrBuf sError; sError.Copy(LoadResStr("IDS_MSG_UPDATEFAILED"));
		const char *szErrMsg = UpdateClient.GetError();
		if (szErrMsg)
		{
			sError.Append(": ");
			sError.Append(szErrMsg);
		}
		pScreen->ShowMessage(sError.getData(), LoadResStr("IDS_TYPE_UPDATE"), C4GUI::Ico_Ex_Update);
		return false;
	}
	// Applicable update available
	if (C4UpdateDlg::IsValidUpdate(VersionInfo.getData()))
	{
		// Prompt user, then apply update
		if (pScreen->ShowMessageModal(LoadResStr("IDS_MSG_ANUPDATETOVERSIONISAVAILA"), LoadResStr("IDS_TYPE_UPDATE"), C4GUI::MessageDialog::btnYesNo, C4GUI::Ico_Ex_Update))
		{
			if (!DoUpdate(UpdateURL.getData(), pScreen))
				pScreen->ShowMessage(LoadResStr("IDS_MSG_UPDATEFAILED"), LoadResStr("IDS_TYPE_UPDATE"), C4GUI::Ico_Ex_Update);
			else
				return true;
		}
	}
	// No applicable update available
	else
	{
		// Message (if not automatic)
		if (!fAutomatic)
			pScreen->ShowMessage(LoadResStr("IDS_MSG_NOUPDATEAVAILABLEFORTHISV"), LoadResStr("IDS_TYPE_UPDATE"), C4GUI::Ico_Ex_Update);
	}
	// Done (and no update has been done)
	return false;
}
Beispiel #18
0
	bool ValidateString(StdStrBuf &rsString, ValidationOption eOption)
		{
		bool fValid = true;
		// validation depending on option
		// check min length
		if (!rsString.getLength())
			{
			// empty if not allowed?
			if (eOption != VAL_NameAllowEmpty && eOption != VAL_NameExAllowEmpty && eOption != VAL_Comment)
				{
				rsString.Copy("empty");
				fValid = false;
				}
			}
		switch (eOption)
			{
			case VAL_Filename: // regular filenames only
				// absolutely no directory traversal
				if (rsString.ReplaceChar('/', '_')) fValid = false;
				if (rsString.ReplaceChar('\\', '_')) fValid = false;

				// fallthrough to general file name validation
			case VAL_SubPathFilename: // filenames and optional subpath
				// do not traverse upwards in file hierarchy
				if (rsString.Replace("..", "__")) fValid = false;
				if (*rsString.getData() == '/' || *rsString.getData() == '\\') { *rsString.getMData() = '_'; fValid = false; }

				// fallthrough to general file name validation
			case VAL_FullPath:        // full filename paths
				// some characters are prohibited in filenames in general
				if (rsString.ReplaceChar('*', '_')) fValid = false;
				if (rsString.ReplaceChar('?', '_')) fValid = false;
				if (rsString.ReplaceChar('<', '_')) fValid = false;
				if (rsString.ReplaceChar('>', '_')) fValid = false;
				// ';' and '|' is never allowed in filenames, because it would cause problems in many engine internal file lists
				if (rsString.ReplaceChar(';', '_')) fValid = false;
				if (rsString.ReplaceChar('|', '_')) fValid = false;
				// the colon is generally prohibited except at pos 2 (C:\...), because it could lead to creation of (invisible) streams on NTFS
				if (rsString.ReplaceChar(':', '_', 2)) fValid = false;
				if (*rsString.getData() == ':') { *rsString.getMData() = '_'; fValid = false; }
				// validate drive letter
				if (rsString.getLength()>=2 && *rsString.getPtr(1) == ':')
					{
					if (eOption != VAL_FullPath)
						{
						*rsString.getMPtr(1)='_'; fValid = false;
						}
					else if (!isalpha((unsigned char)*rsString.getData()) || (*rsString.getPtr(2)!='\\' && *rsString.getPtr(2)!='/'))
						{
						*rsString.getMData()=*rsString.getMPtr(1)='_'; fValid = false;
						}
					}
				break;

			case VAL_NameNoEmpty:
			case VAL_NameAllowEmpty:
				// no markup
				if (CMarkup::StripMarkup(&rsString)) { fValid = false; }
				// trim spaces
				if (rsString.TrimSpaces()) fValid = false;
				// min length
				if (eOption == VAL_NameNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); }
				// max length
				if (rsString.getLength() > C4MaxName) { fValid = false; rsString.SetLength(C4MaxName); }
				break;

			case VAL_NameExNoEmpty:
			case VAL_NameExAllowEmpty:
				// trim spaces
				if (rsString.TrimSpaces()) fValid = false;
				// min length
				if (eOption == VAL_NameExNoEmpty) if (!rsString.getLength()) { fValid = false; rsString.Copy("Unknown"); }
				// max length
				if (rsString.getLength() > C4MaxLongName) { fValid = false; rsString.SetLength(C4MaxLongName); }
				break;

			case VAL_IRCName: // nickname for IRC. a-z, A-Z, _^{[]} only; 0-9|- inbetween; max 30 characters
				if (rsString.getLength() > 30) fValid = false;
				if (rsString.getLength() < 2) fValid = false;
				if (!rsString.ValidateChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_^{[]}0123456789|-")) { fValid = false; rsString.Copy("Guest"); }
				if (SEqualNoCase(rsString.getData(), "NickServ")
				 || SEqualNoCase(rsString.getData(), "ChanServ")
				 || SEqualNoCase(rsString.getData(), "MemoServ")
				 || SEqualNoCase(rsString.getData(), "OperServ")
				 || SEqualNoCase(rsString.getData(), "HelpServ")) fValid = false;
				if (!fValid) rsString.Copy("Guest");
				break;

			case VAL_IRCPass: // password for IRC; max 31 characters
				// max length; no spaces
				if (rsString.getLength() > 31) { fValid = false; rsString.SetLength(31); }
				if (rsString.getLength() < 2) { fValid = false; rsString.Copy("secret"); }
				if (rsString.ReplaceChar(' ', '_')) fValid = false;
				break;

			case VAL_IRCChannel: // IRC channel name
				if (rsString.getLength() > 32) { fValid = false; rsString.SetLength(32); }
				else if (rsString.getLength() < 2) { fValid = false; rsString.Copy("#clonken"); }
				else if (*rsString.getData() != '#' && *rsString.getData() != '+') { fValid = false; *rsString.getMData() = '#'; }
				if (rsString.ReplaceChar(' ', '_')) fValid = false;
				break;

			case VAL_Comment: // comment - just limit length
				if (rsString.getLength() > C4MaxComment) { fValid = false; rsString.SetLength(C4MaxComment); }
				break;

			default:
				assert(!"not yet implemented");
			}
		// issue warning for invalid adjustments
		if (!fValid)
			{
			const char *szOption = "unknown";
			switch (eOption)
				{
				case VAL_Filename:         szOption = "filename";         break;
				case VAL_SubPathFilename:  szOption = "(sub-)filename";   break;
				case VAL_FullPath:         szOption = "free filename";    break;
				case VAL_NameNoEmpty:      szOption = "strict name";      break;
				case VAL_NameExNoEmpty:    szOption = "name";             break;
				case VAL_NameAllowEmpty:   szOption = "strict name*";     break;
				case VAL_NameExAllowEmpty: szOption = "name*";            break;
				case VAL_IRCName:          szOption = "IRC nick";         break;
				case VAL_IRCPass:          szOption = "IRC password";     break;
				case VAL_IRCChannel:       szOption = "IRC channel";      break;
				case VAL_Comment:          szOption = "Comment";          break;
				}
			//LogF("WARNING: Adjusted invalid user input for \"%s\" to \"%s\"", szOption, rsString.getData());
			}
		return !fValid;
		}
StdStrBuf C4KeyCodeEx::KeyCode2String(C4KeyCode wCode, bool fHumanReadable, bool fShort)
{
    // Gamepad keys
    if (Key_IsGamepad(wCode))
    {
        int iGamepad = Key_GetGamepad(wCode);
        int gamepad_event = Key_GetGamepadEvent(wCode);
        switch (gamepad_event)
        {
        case KEY_JOY_Left:
            return FormatString("Joy%dLeft", iGamepad+1);
        case KEY_JOY_Up:
            return FormatString("Joy%dUp", iGamepad+1);
        case KEY_JOY_Down:
            return FormatString("Joy%dDown", iGamepad+1);
        case KEY_JOY_Right:
            return FormatString("Joy%dRight", iGamepad+1);
        default:
            if (Key_IsGamepadAxis(wCode))
            {
                if (fHumanReadable)
                    // This is still not great, but it is not really possible to assign unknown axes to "left/right" "up/down"...
                    return FormatString("[%d] %s", int(1 + Key_GetGamepadAxisIndex(wCode)), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min");
                else
                    return FormatString("Joy%dAxis%d%s", iGamepad+1, static_cast<int>(Key_GetGamepadAxisIndex(wCode)+1), Key_IsGamepadAxisHigh(wCode) ? "Max" : "Min");
            }
            else
            {
                // button
                if (fHumanReadable)
                    // If there should be gamepads around with A B C D... on the buttons, we might create a display option to show letters instead...
                    return FormatString("< %d >", int(1 + Key_GetGamepadButtonIndex(wCode)));
                else
                    return FormatString("Joy%d%c", iGamepad+1, static_cast<char>(Key_GetGamepadButtonIndex(wCode) + 'A'));
            }
        }
    }
    // Mouse keys
    if (Key_IsMouse(wCode))
    {
        int mouse_id = Key_GetMouse(wCode);
        int mouse_event = Key_GetMouseEvent(wCode);
        const char *mouse_str = "Mouse";
        switch (mouse_event)
        {
        case KEY_MOUSE_Move:
            return FormatString("%s%dMove", mouse_str, mouse_id);
        case KEY_MOUSE_Wheel1Up:
            return FormatString("%s%dWheel1Up", mouse_str, mouse_id);
        case KEY_MOUSE_Wheel1Down:
            return FormatString("%s%dWheel1Down", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonLeft:
            return FormatString("%s%dLeft", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonRight:
            return FormatString("%s%dRight", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonMiddle:
            return FormatString("%s%dMiddle", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonLeftDouble:
            return FormatString("%s%dLeftDouble", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonRightDouble:
            return FormatString("%s%dRightDouble", mouse_str, mouse_id);
        case KEY_MOUSE_ButtonMiddleDouble:
            return FormatString("%s%dMiddleDouble", mouse_str, mouse_id);
        default:
            // extended mouse button
        {
            uint8_t btn = Key_GetMouseEvent(wCode);
            if (btn >= KEY_MOUSE_Button1Double)
                return FormatString("%s%dButton%dDouble", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1Double));
            else
                return FormatString("%s%dButton%d", mouse_str, mouse_id, int(btn-KEY_MOUSE_Button1));
        }
        }
    }

    // it's a keyboard key
    if (!fHumanReadable) {
        // for config files and such: dump scancode
        return FormatString("$%x", static_cast<unsigned int>(wCode));
    }
#if defined(USE_WIN32_WINDOWS) || (defined(_WIN32) && defined(USE_GTK))

    // Query map
    const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
    while (pCheck->szName)
        if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName);
        else ++pCheck;

//  TODO: Works?
//  StdStrBuf Name; Name.SetLength(1000);
//  int res = GetKeyNameText(wCode, Name.getMData(), Name.getSize());
//  if(!res)
//    // not found: Compose as direct code
//    return FormatString("\\x%x", (DWORD) wCode);
//  // Set size
//  Name.SetLength(res);
//  return Name;

    wchar_t buf[100];
    int len = GetKeyNameText(wCode<<16, buf, 100);
    if (len > 0) {
        // buf is nullterminated name
        return StdStrBuf(buf);
    }
#elif defined (USE_COCOA)
    // query map
    const C4KeyCodeMapEntry *pCheck = KeyCodeMap;
    while (pCheck->szName)
        if (wCode == pCheck->wCode) return StdStrBuf((pCheck->szShortName && fShort) ? pCheck->szShortName : pCheck->szName);
        else ++pCheck;
    // not found: Compose as direct code
    return FormatString("\\x%x", static_cast<unsigned int>(wCode));
#elif defined(USE_GTK)
    Display * const dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
    KeySym keysym = (KeySym)XkbKeycodeToKeysym(dpy,wCode+8,0,0);
    char* name = NULL;
    if (keysym != NoSymbol) { // is the keycode without shift modifiers mapped to a symbol?
        name = gtk_accelerator_get_label_with_keycode(gdk_display_get_default(), keysym, wCode+8, (GdkModifierType)0);
    }
    if (name) { // is there a string representation of the keysym?
        // prevent memleak
        StdStrBuf buf;
        buf.Copy(name);
        g_free(name);
        return buf;
    }
#elif defined(USE_SDL_MAINLOOP)
    StdStrBuf buf;
    buf.Copy(SDL_GetScancodeName(static_cast<SDL_Scancode>(wCode)));
    if (!buf.getLength()) buf.Format("\\x%x", wCode);
    return buf;
#endif
    return FormatString("$%x", static_cast<unsigned int>(wCode));
}
Beispiel #20
0
CStdWindow *CStdWindow::Init(CStdApp *pApp, const char *Title,
                             CStdWindow *pParent, bool HideCursor) {
#ifndef USE_X11
  return this;
#else
  Active = true;
  dpy = pApp->dpy;

  if (!FindInfo()) return 0;

  // Various properties
  XSetWindowAttributes attr;
  attr.border_pixel = 0;
  attr.background_pixel = 0;
  // Which events we want to receive
  attr.event_mask =
      // EnterWindowMask |
      // LeaveWindowMask |
      StructureNotifyMask | FocusChangeMask | KeyPressMask | KeyReleaseMask |
      PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
  attr.colormap = XCreateColormap(dpy, DefaultRootWindow(dpy),
                                  ((XVisualInfo *)Info)->visual, AllocNone);
  unsigned long attrmask =
      CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
  Pixmap bitmap;
  if (HideCursor) {
    // Hide the mouse cursor
    XColor cursor_color;
    // We do not care what color the invisible cursor has
    memset(&cursor_color, 0, sizeof(cursor_color));
    bitmap = XCreateBitmapFromData(dpy, DefaultRootWindow(dpy), "\000", 1, 1);
    attr.cursor = XCreatePixmapCursor(dpy, bitmap, bitmap, &cursor_color,
                                      &cursor_color, 0, 0);
    attrmask |= CWCursor;
  }

  wnd = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 640, 480, 0,
                      ((XVisualInfo *)Info)->depth, InputOutput,
                      ((XVisualInfo *)Info)->visual, attrmask, &attr);
  if (HideCursor) {
    XFreeCursor(dpy, attr.cursor);
    XFreePixmap(dpy, bitmap);
  }
  if (!wnd) {
    Log("Error creating window.");
    return 0;
  }
  // Update the XWindow->CStdWindow-Map
  CStdAppPrivate::SetWindow(wnd, this);
  if (!pApp->Priv->xic && pApp->Priv->xim) {
    pApp->Priv->xic = XCreateIC(
        pApp->Priv->xim, XNClientWindow, wnd, XNFocusWindow, wnd, XNInputStyle,
        XIMPreeditNothing | XIMStatusNothing, XNResourceName, STD_PRODUCT,
        XNResourceClass, STD_PRODUCT, NULL);
    if (!pApp->Priv->xic) {
      Log("Failed to create input context.");
      XCloseIM(pApp->Priv->xim);
      pApp->Priv->xim = 0;
    } else {
      long ic_event_mask;
      if (XGetICValues(pApp->Priv->xic, XNFilterEvents, &ic_event_mask, NULL) ==
          NULL)
        attr.event_mask |= ic_event_mask;
      XSelectInput(dpy, wnd, attr.event_mask);
      XSetICFocus(pApp->Priv->xic);
    }
  }
  // We want notification of closerequests and be killed if we hang
  Atom WMProtocols[2];
  char *WMProtocolnames[] = {"WM_DELETE_WINDOW", "_NET_WM_PING"};
  XInternAtoms(dpy, WMProtocolnames, 2, false, WMProtocols);
  XSetWMProtocols(dpy, wnd, WMProtocols, 2);
  // Let the window manager know our pid so it can kill us
  Atom PID = XInternAtom(pApp->dpy, "_NET_WM_PID", false);
  int32_t pid = getpid();
  if (PID != None)
    XChangeProperty(pApp->dpy, wnd, PID, XA_CARDINAL, 32, PropModeReplace,
                    reinterpret_cast<const unsigned char *>(&pid), 1);
  // Title and stuff
  XTextProperty title_property;
  StdStrBuf tbuf;
  tbuf.Copy(Title ? Title : "");
  char *tbufstr = tbuf.getMData();
  // char * title = "Clonk Endeavour";
  XStringListToTextProperty(&tbufstr, 1, &title_property);
  // State and Icon
  XWMHints *wm_hint = XAllocWMHints();
  wm_hint->flags = StateHint | InputHint | IconPixmapHint | IconMaskHint;
  wm_hint->initial_state = NormalState;
  wm_hint->input = True;
  // Trust XpmCreatePixmapFromData to not modify the xpm...
  XpmCreatePixmapFromData(dpy, wnd, const_cast<char **>(c4x_xpm),
                          &wm_hint->icon_pixmap, &wm_hint->icon_mask, 0);
  // Window class
  XClassHint *class_hint = XAllocClassHint();
  class_hint->res_name = STD_PRODUCT;
  class_hint->res_class = STD_PRODUCT;
  XSetWMProperties(dpy, wnd, &title_property, &title_property, pApp->Priv->argv,
                   pApp->Priv->argc, 0, wm_hint, class_hint);
  // Set "parent". Clonk does not use "real" parent windows, but multiple
  // toplevel windows.
  if (pParent) XSetTransientForHint(dpy, wnd, pParent->wnd);
  // Show window
  XMapWindow(dpy, wnd);
  // Clean up
  // The pixmap has to stay as long as the window exists, so it does not hurt to
  // never free it.
  // XFreePixmap(dpy,xwmh->icon_pixmap);
  // XFreePixmap(dpy,xwmh->icon_mask);
  XFree(title_property.value);
  Hints = wm_hint;
  XFree(class_hint);

  // Render into whole window
  renderwnd = wnd;

  return this;
#endif  // USE_X11
}
Beispiel #21
0
bool C4Application::DoInit() {
  assert(AppState == C4AS_None);
  // Config overwrite by parameter
  StdStrBuf sConfigFilename;
  char szParameter[_MAX_PATH + 1];
  for (int32_t iPar = 0;
       SGetParameter(GetCommandLine(), iPar, szParameter, _MAX_PATH); iPar++)
    if (SEqual2NoCase(szParameter, "/config:"))
      sConfigFilename.Copy(szParameter + 8);
  // Config check
  Config.Init();
  Config.Load(true, sConfigFilename.getData());
  Config.Save();
  // sometimes, the configuration can become corrupted due to loading errors or
  // w/e
  // check this and reset defaults if necessary
  if (Config.IsCorrupted()) {
    if (sConfigFilename) {
      // custom config corrupted: Fail
      Log("Warning: Custom configuration corrupted - program abort!\n");
      return false;
    } else {
      // default config corrupted: Restore default
      Log("Warning: Configuration corrupted - restoring default!\n");
      Config.Default();
      Config.Save();
      Config.Load();
    }
  }
  MMTimer = Config.General.MMTimer != 0;
  // Init C4Group
  C4Group_SetMaker(Config.General.Name);
  C4Group_SetProcessCallback(&ProcessCallback);
  C4Group_SetTempPath(Config.General.TempPath);
  C4Group_SetSortList(C4CFN_FLS);

  // Open log
  if (!OpenLog()) return false;

  // init system group
  if (!SystemGroup.Open(C4CFN_System)) {
    // Error opening system group - no LogFatal, because it needs language
    // table.
    // This will *not* use the FatalErrors stack, but this will cause the game
    // to instantly halt, anyway.
    Log("Error opening system group file (System.c4g)!");
    return false;
  }

  // Language override by parameter
  const char *pLanguage;
  if (pLanguage = SSearchNoCase(GetCommandLine(), "/Language:"))
    SCopyUntil(pLanguage, Config.General.LanguageEx, ' ', CFG_MaxString);

  // Init external language packs
  Languages.Init();
  // Load language string table
  if (!Languages.LoadLanguage(Config.General.LanguageEx))
    // No language table was loaded - bad luck...
    if (!IsResStrTableLoaded())
      Log("WARNING: No language string table loaded!");

  // Set unregistered user name
  C4Group_SetMaker(LoadResStr("IDS_PRC_UNREGUSER"));

  // Parse command line
  Game.ParseCommandLine(GetCommandLine());

#ifdef WIN32
  // Windows: handle incoming updates directly, even before starting up the gui
  //          because updates will be applied in the console anyway.
  if (Application.IncomingUpdate)
    if (C4UpdateDlg::ApplyUpdate(Application.IncomingUpdate.getData(), false,
                                 NULL))
      return true;
#endif

  // activate
  Active = TRUE;

  // Init carrier window
  if (isFullScreen) {
    if (!(pWindow = FullScreen.Init(this))) {
      Clear();
      return false;
    }
  } else {
    if (!(pWindow = Console.Init(this))) {
      Clear();
      return false;
    }
  }

  // init timers (needs window)
  if (!InitTimer()) {
    LogFatal(LoadResStr("IDS_ERR_TIMER"));
    Clear();
    return false;
  }

  // Engine header message
  Log(C4ENGINEINFOLONG);
  LogF("Version: %s %s", C4VERSION, C4_OS);

#if defined(USE_DIRECTX) && defined(_WIN32)
  // DDraw emulation warning
  DWORD DDrawEmulationState;
  if (GetRegistryDWord(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw",
                       "EmulationOnly", &DDrawEmulationState))
    if (DDrawEmulationState)
      Log("WARNING: DDraw Software emulation is activated!");
#endif
  // Initialize D3D/OpenGL
  DDraw = DDrawInit(this, isFullScreen, FALSE, Config.Graphics.BitDepth,
                    Config.Graphics.Engine, Config.Graphics.Monitor);
  if (!DDraw) {
    LogFatal(LoadResStr("IDS_ERR_DDRAW"));
    Clear();
    return false;
  }

#if defined(_WIN32) && !defined(USE_CONSOLE)
  // Register clonk file classes - notice: under Vista this will only work if we
  // have administrator rights
  char szModule[_MAX_PATH + 1];
  GetModuleFileName(NULL, szModule, _MAX_PATH);
  SetC4FileClasses(szModule);
#endif

  // Initialize gamepad
  if (!pGamePadControl && Config.General.GamepadEnabled)
    pGamePadControl = new C4GamePadControl();

  AppState = C4AS_PreInit;

  return true;
}
Beispiel #22
0
bool C4Playback::StreamToRecord(const char *szStream, StdStrBuf *pRecordFile) {
  // Load data
  StdBuf CompressedData;
  Log("Reading stream...");
  if (!CompressedData.LoadFromFile(szStream)) return false;

  // Decompress
  unsigned long iStreamSize = CompressedData.getSize() * 5;
  StdBuf StreamData;
  StreamData.New(iStreamSize);
  while (true) {
    // Initialize stream
    z_stream strm;
    ZeroMem(&strm, sizeof strm);
    strm.next_in = getMBufPtr<BYTE>(CompressedData);
    strm.avail_in = CompressedData.getSize();
    strm.next_out = getMBufPtr<BYTE>(StreamData);
    strm.avail_out = StreamData.getSize();

    // Decompress
    if (inflateInit(&strm) != Z_OK) return false;
    int ret = inflate(&strm, Z_FINISH);
    if (ret == Z_STREAM_END) {
      inflateEnd(&strm);
      break;
    }
    if (ret != Z_BUF_ERROR) return false;

    // All input consumed?
    iStreamSize = strm.total_out;
    if (strm.avail_in == 0) {
      Log("Stream data incomplete, using as much data as possible");
      break;
    }

    // Larger buffer needed
    StreamData.Grow(CompressedData.getSize());
    iStreamSize = StreamData.getSize();
  }
  StreamData.SetSize(iStreamSize);

  // Parse
  C4Playback Playback;
  Playback.ReadBinary(StreamData);
  LogF("Got %d chunks from stream", Playback.chunks.size());

  // Get first chunk, which must contain the initial
  chunks_t::iterator chunkIter = Playback.chunks.begin();
  if (chunkIter == Playback.chunks.end() || chunkIter->Type != RCT_File)
    return false;

  // Get initial chunk, go over file name
  StdBuf InitialData = *chunkIter->pFileData;
  const char *szInitialFilename = chunkIter->Filename.getData();

  // Put to temporary file and unpack
  char szInitial[_MAX_PATH + 1] = "~initial.tmp";
  MakeTempFilename(szInitial);
  if (!InitialData.SaveToFile(szInitial) || !C4Group_UnpackDirectory(szInitial))
    return false;

  // Load Scenario.txt from Initial
  C4Group Grp;
  C4Scenario Initial;
  if (!Grp.Open(szInitial) || !Initial.Load(Grp) || !Grp.Close()) return false;

  // Copy original scenario
  const char *szOrigin = Initial.Head.Origin.getData();
  char szRecord[_MAX_PATH + 1];
  SCopy(szStream, szRecord, _MAX_PATH);
  if (GetExtension(szRecord)) *(GetExtension(szRecord) - 1) = 0;
  SAppend(".c4s", szRecord, _MAX_PATH);
  LogF("Original scenario is %s, creating %s.", szOrigin, szRecord);
  if (!C4Group_CopyItem(szOrigin, szRecord, false, false)) return false;

  // Merge initial
  if (!Grp.Open(szRecord) || !Grp.Merge(szInitial)) return false;

  // Process other files in stream
  chunkIter->Delete();
  chunkIter = Playback.chunks.erase(chunkIter);
  while (chunkIter != Playback.chunks.end())
    if (chunkIter->Type == RCT_File) {
      LogF("Inserting %s...", chunkIter->Filename.getData());
      StdStrBuf Temp;
      Temp.Copy(chunkIter->Filename);
      MakeTempFilename(&Temp);
      if (!chunkIter->pFileData->SaveToFile(Temp.getData())) return false;
      if (!Grp.Move(Temp.getData(), chunkIter->Filename.getData()))
        return false;
      chunkIter = Playback.chunks.erase(chunkIter);
    } else
      chunkIter++;

  // Write record data
  StdBuf RecordData = Playback.ReWriteBinary();
  if (!Grp.Add(C4CFN_CtrlRec, RecordData, false, true)) return false;

  // Done
  Log("Writing record file...");
  Grp.Close();
  pRecordFile->Copy(szRecord);
  return true;
}