madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) Ok thanks.More questions.Why does everything go through an interface. I mean, I like the idea, in OOPs there should be standard interfaces between classes. What I mean is what are they exactly in this case ? Are there different interfaces defined for different game entities. Is a entity the same as a component ?When you say :var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);You are querying the Engine's Player interface for a particular player component ? The cmp stands for component I guess ?Whats are the things like <AttackDetection/> or BattleDetection or FormationManager ? They are various parts of the system right ? So these are also components ? Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 (edited) Yes, an "interface" in this context is a simulation component interface. Engine.QueryInterface() acquires a reference to a particular interface of a particular entity. (Though, to be honest I know little of how it actually does that, I just use it ) Some assorted background info: http://svn.wildfiregames.com/docs/writing-components.htmlElements like <AttackDetection/> in templates are references to components, yes. Edited April 3, 2013 by zoot Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) Thanks, looking into it now, also ran into a particularly rich vein of documentation right here : http://trac.wildfire.../TDD_Simulation !! Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
leper Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) I believe it is DEBUG_PRINT() or DEBUG_WARN() or some such. For JS, it is warn() and error().LOGWARNING() and LOGERROR() is what you are looking for.EDIT: debug_warn() prints to stdout (or stderr (I'm not entirely sure without checking)) and breaks into the debugger, so it should be used if the code that triggers it indicates an engine bug. While LOGERROR() should be used for cases where modders can trigger it (eg: Wrong data files). Edited April 3, 2013 by leper some background info Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 Thanks Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 ok, so the minimap interface does not expose any functions to JS yet I see from the empty wrapper section in ICmpMinimap.cpp Guess this is where the new PingMap() would go. Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 Unknown territory to me, so your guess is as good as mine, but I don't believe you will want to add it to any file in the simulation2 subdirectory, since the simulation is a different scripting context from the GUI. The attack notification sound is played from the GUI context (messages.js), so the ping probably should too. Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 (edited) Once you've found the right place to add the function, you would likely want to add a reference to it here to expose it to the GUI JS context: https://github.com/0ad/0ad/blob/master/source/gui/scripting/ScriptFunctions.cpp#L612 (RegisterFunction() adds the function as a global Engine.* function in the given JS context.) Edited April 3, 2013 by zoot Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) Hmm, not sure what you mean. messages.js would call PingMiniMap(x, z) . This function will be implemented in C++. probably in CCmpMinimap.cpp. So to tie the Javascript call to the C++ function, I would need to probably add a line in ICmpMinimap as follows :BEGIN_INTERFACE_WRAPPER(Minimap)DEFINE_INTERFACE_METHOD_2("PingMiniMap", int, ICmpMinimap, PingMiniMap, int, int)END_INTERFACE_WRAPPER(Minimap)--------------Once you've found the right place to add the function, you would likely want to add a reference to it here to expose it to the GUI JS context: https://github.com/0...ctions.cpp#L612 (RegisterFunction() adds the function as a global Engine.* function in the given JS context.)Oh ok, I guess I can add it as a global function too so that the Minimap component does not have to be retrieved each time. I am not sure which approach is followed when. But I guess since there is just 1 minimap, therefore there is no minimap component as such. So it makes sense to register it as a global function. Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 (edited) Your approach could work too, I'm not sure how that minimap component is actually organized. It just seems odd to me that the ping would need to go through the simulation, since it is specific to a single player and shouldn't need to be network synchronized or anything. Edited April 3, 2013 by zoot Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 I think the CCmpMinimap.cpp component is what units use to make themselves show up on the minimap, while MiniMap.cpp is what actually renders the minimap. Quote Link to comment Share on other sites More sharing options...
leper Posted April 3, 2013 Report Share Posted April 3, 2013 The minimap code is actually in source/gui/. The minimap component is only used by the former to know which entities to render. Going from the gui code via the simulation just to update the minimap seems strange and is probably bogus. Either go from the simulation to the minimap (analogous to the way the entities are handled) or from the simulation to the gui code (which you already do) and then from the gui code to the minimap. The first way would probably lead to some problems that would need to be worked around, and the second does seem to be the better design choice. Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) r from the simulation to the gui code (which you already do) and then from the gui code to the minimapSo how exactly is zoot already going from the simulation to the gui code. Is messages.js part of gui code ? Not exactly sure what executes in what context here.------------oh ok, I guess it is since it is in gui/sessionSo he is going from the simulation/components/AttackDetection.js which is simulation code to the gui code in message.js Thats what you meant ? Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 The AttackDetection.js component is part of the simulation and this component invokes the PushNotification function which passes execution into messages.js which runs in the GUI. Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) ok so when execution reaches messages.js , into function handleNotifications() then what we want is to have this in there :else if (notification.type == "attack"){if (notification.player == Engine.GetPlayerID())Engine.GuiInterfaceCall("PlaySound", { "name":"attacked", "entity": notification.message.target });Engine.PingMinimap({ "entity": notification.message.target });}That means PingMinimap() should be declared as a global function in GuiScriptingInitAnd this function needs to get the position info from the passed entity and blink the correct position in the minimap. Or the position can be retrieved in JS itself and passed to PingMinimap().Please tell me if I am hopelessly wrong here Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 (edited) Exactly (or something very close to that, depending on what works out for you).It's a detail, but you'd need to enclose both lines in the 'if' context:else if (notification.type == "attack"){ if (notification.player == Engine.GetPlayerID()) { Engine.GuiInterfaceCall("PlaySound", { "name":"attacked", "entity": notification.message.target }); Engine.PingMinimap({ "entity": notification.message.target }); }} Edited April 3, 2013 by zoot 1 Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 (edited) yes right.ok, now for the rendering code in the minimap, Someone who has worked on it can please confirm my conjecture here :So the units are rendered in this part of the code in CMiniMap::Draw()PROFILE_START("minimap units");// Don't enable GL_POINT_SMOOTH because it's far too slow// (~70msec/frame on a GF4 rendering a thousand points)glPointSize(3.f);float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);std::vector<MinimapUnitVertex> vertexArray;vertexArray.reserve(ents.size());for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it){ MinimapUnitVertex v; ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); entity_pos_t posX, posZ; if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; vertexArray.push_back(v); } }}if (!vertexArray.empty()){ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); } else { glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); } glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);}PROFILE_END("minimap units");I guess something similar needs to be done for rendering blinking dots in the minimap for the attack positions. So I pack all the required pinging locations into a vertexarray inside a large for loop and then send it for rendering viashader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x);shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r);....glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size());in the shader render path ?From what I understand in the code is that the for-loop fetches the minimap component for each entity/thing visible in the 0ad world and then uses the minimap component to fetch the rendering data (colors, position) to be used to display that entity in the minimap. Edited April 3, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 I tried to print a large red blob on the minimap using this ://-----------------------------------------// Don't enable GL_POINT_SMOOTH because it's far too slow// (~70msec/frame on a GF4 rendering a thousand points)glPointSize(6.f);float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE);//CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap);std::vector<MinimapUnitVertex> vertexArray;vertexArray.reserve(1);MinimapUnitVertex v;v.a = 255;v.x = 10*sx;v.y = 10*sy;v.r = 255;v.g = 100;v.b = 100;vertexArray.push_back(v);std::cout << "Hallo\n";debug_printf(L"Hello");if (!vertexArray.empty()){ glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { shader->VertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); shader->ColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); } else { glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); } glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);}//-----------------------------------------It doesnt work. I am also having a hard time debugging as debug_warn() immediately breaks to the debugger. cout does not work but I would like to be able to print to the console every frame for now(for debugging only). Nor does debug_printf() . Do I need to run pyrogenesis_dbg.exe ?If I run pyrogenesis_dbg.exe it says MSVCRT90D.dll is missing or something. Quote Link to comment Share on other sites More sharing options...
zoot Posted April 3, 2013 Author Report Share Posted April 3, 2013 Did you try this:LOGWARNING() and LOGERROR() is what you are looking for. Quote Link to comment Share on other sites More sharing options...
madmax Posted April 3, 2013 Report Share Posted April 3, 2013 Ah thanks, that works. Prints inside the game. I guess stdout/stderr is suppressed somehow. Quote Link to comment Share on other sites More sharing options...
historic_bruno Posted April 3, 2013 Report Share Posted April 3, 2013 To see the output from e.g. debug_printf in Windows, you need to use DebugView or run the game in the debugger and use its console (the output window in Visual Studio). Quote Link to comment Share on other sites More sharing options...
madmax Posted April 4, 2013 Report Share Posted April 4, 2013 ok thanks.So on noticing carefully I see a little red line does show up on the bottom left corner of the minimap, Its not within the circle region of the minimap but I guess for that I just need get the proper co-ordinates. Quote Link to comment Share on other sites More sharing options...
zoot Posted April 4, 2013 Author Report Share Posted April 4, 2013 Note, if you aren't already aware, that maps internally are square, so positions in the corners of the internal map won't be visible on the circular minimap. Quote Link to comment Share on other sites More sharing options...
madmax Posted April 4, 2013 Report Share Posted April 4, 2013 (edited) OK, yeah I seem to be showing the dot on the minimap square outside the circle.There were some handy commands to start pyrogenesis in windowed mode with a particular map, skipping the starting screen. There was even one for starting 2 AIs against each other.Can anyone point me to that list of useful commands ?---------------Got one :pyrogenesis -quickstart -autostart="Isthmus" -autostart-ai=1:qbot-wc -autostart-ai=2:qbot-wcok, to gain control over 1 player, I just leave it out in the command line.pyrogenesis -quickstart -autostart="Isthmus" -autostart-ai=2:qbot-wcWhat other options are there ?Does -quickstart have sound suppressed ?Also I dont see a directory for aegis-bot in the ai folder. Where is it located. How is the engine finding the code for it ? Edited April 4, 2013 by madmax Quote Link to comment Share on other sites More sharing options...
Mythos_Ruler Posted April 4, 2013 Report Share Posted April 4, 2013 Does -quickstart have sound suppressed ?Yes it does.Also I dont see a directory for aegis-bot in the ai folder. Where is it located. How is the engine finding the code for it ?It's called qbot-wc internally. I spose we should rename the folder to Aegis? Would that break anything? Probably the maps which use Aegis bot, but those can be fixed easily enough with a script. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.