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; }
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; }
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); } }
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; } }
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); }
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(); }
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; }
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; }
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; }
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; }
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; }
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)); }
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 }
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; }
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; }