EntityFind
» Siedler Map Source Forum » Siedler DEdK Script Forum » EntityFind
Seiten: 1
mcb
|
#1 01.10.2014 18:51 Beiträge: 1472 |
EntityFind
Da mir die Logic-Funktionen nicht reichen hab ich mal selber was gescriptet. Ich denke mal, das andere damit auch noch was anfangen können, daher stelle ich es mal hier rein. Fragen und Anregungen könnt ihr gerne hier Posten
--[[ EntityFind mcb 2.1 Schnelle Möglichkeit Entitys zu suchen & sortieren. Geht alle Entity-Ids durch, anstatt diese zu erfragen. (bobbys Methode) EntityFind.GetEntities(_amount, _acceptFunc, ...) _amount == nil => alle [ _acceptFunc: muss für jedes Entity true zurückgeben, das ausgegeben werden soll: id, unpack(arg) ] EntityFind.GetPlayerEntities(_player, _entityType, _amount, _acceptFunc, ...) _player: 1-8 => player oder 0 => neutral (player 0) oder nil => alle _entityType: EntityTypeId oder EntityTypeName oder table oder 0 oder nil => alle oder function => muss true zurückgeben, wenn nach EntityTyp gesucht werden soll: EntityTypeName, unpack(arg) _amount == nil => alle EntityFind.GetPlayerEntitiesInArea(_player, _entityType, _pos, _range, _amount, _acceptFunc, ...) _pos: Position oder existierendes Entity _range: Radius um _pos _amount: "dist" oder "distance" => alle suchen und nach Entfernung zu _pos sortieren (sort wird überschrieben) Rückgabe standardmäßig NICHT nach Entfernung zu _pos sortiert! Argumente können auch in einem table abgelegt sein: {player = , --in diesem Fall kann player auch ein table mit Playern sein entityType = , amount = , [acceptFunc = , arg = {}, -- Argumente für alle übergebenen Funktionen entities = {}, -- schon gefundene Entities sort = , -- um entities zu sortieren, muss jedem Entity einen Wert zuweisen (in entities vorhandene werden mit 0 bewertet): id, unpack(arg)] [pos = , -- bei Area range = ,] } EntityFind.Set enthält vorgefertigte Entity-tables: Leader (ohne Helden) Hero MilitaryBuilding (Türme) Military (Leader + Hero + MilitaryBuilding) Building (mit Wällen) PU (mit Kanonen) PB CU CB (mit Wällen) P (PU + PB) C (CU + CB) XD und Mengen-Operationen für tables: Add: Alle Elemente, die in einem der tables vorkommen, werden übernommen All: Alle Elemente, die in allen tables vorkommen, werden übernommen (Schnittmenge) Dif: Entfernt aus dem ersten table alle Elemente die in weiteren tables gegeben sind (übergebene tables werden nicht geändert) Benötigt: IstDrin ! vor EntityFind im Script ! GetDistance unpack-fix ]] ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ EntityFind = EntityFind or {oldId = {}, highest = 65537} function EntityFind_EntityCreated() local id = Event.GetEntityID() if id > 131072 then old = (id - math.floor(id/65536)*65536) + 65536 EntityFind.oldId[old] = id else EntityFind.highest = id end end Trigger.RequestTrigger(Events.LOGIC_EVENT_ENTITY_CREATED, nil, "EntityFind_EntityCreated", 1) Logic.DestroyEntity(Logic.CreateEntity(Entities.XD_ScriptEntity, 2, 2, 0, 0)) function EntityFind.GetEntities(_amount, _acceptFunc, ...) -- table für gefundene local entitySafe = {} local sort -- table-aufruf entpacken if type(_amount) == "table" then _acceptFunc = _amount.acceptFunc arg = _amount.arg or {} sort = _amount.sort entitySafe = _amount.entities or {} _amount = _amount.amount end assert(type(arg)=="table" and type(entitySafe)=="table") -- sort prüfen assert(type(sort)=="function" or not sort, "EntityFind: Keine Sortierfunktion: "..tostring(sort).." Funktion oder nil erlaubt") local value = {} if sort then for k,_ in pairs(entitySafe) do value[k] = 0 end _amount = nil end -- Menge prüfen assert(_amount==nil or type(_amount)=="number", "EntityFind: Keine Anzahl: "..tostring(_amount).." Zahl oder nil erlaubt!") -- acceptFunc prüfen _acceptFunc = _acceptFunc or function() return true end assert(type(_acceptFunc)=="function", "EntityFind: Keine Prüffunktion: "..tostring(_acceptFunc).." Funktion oder nil erlaubt!") -- suchen! for i = 65536, EntityFind.highest do -- gehe alle ids durch local id = i if EntityFind.oldId[id] then -- eventuell ersatzid id = EntityFind.oldId[id] end if IsValid(id) and _acceptFunc(id, unpack(arg)) then -- prüfen if sort then local v = sort(id, unpack(arg)) for i,val in ipairs(value) do if val > v then table.insert(entitySafe, i, id) table.insert(value, i, v) v = nil break end end if v then table.insert(entitySafe, id) table.insert(value, v) end else table.insert(entitySafe, id) end end if _amount and table.getn(entitySafe) >= _amount then -- genug gefunden: abbruch break end end return entitySafe end function EntityFind.GetPlayerEntities(_player, _entityType, _amount, _acceptFunc, ...) -- table für gefundene local entitySafe = {} local sort -- tableaufruf entpacken if type(_player) == "table" then _entityType = _player.entityType _amount = _player.amount _acceptFunc = _player.acceptFunc arg = _player.arg or {} entitySafe = _player.entities or {} sort = _player.sort _player = _player.player end -- sort prüfen assert(type(sort)=="function" or not sort, "EntityFind: Keine Sortierfunktion: "..tostring(sort).." Funktion oder nil erlaubt") local value = {} if sort then for k,_ in pairs(entitySafe) do value[k] = 0 end end -- acceptFunc prüfen _acceptFunc = _acceptFunc or function() return true end assert(type(_acceptFunc)=="function", "EntityFind: Keine Prüffunktion: "..tostring(_acceptFunc).." Funktion oder nil erlaubt!") -- player prüfen if _player == nil then _player = {0,1,2,3,4,5,6,7,8} elseif type(_player)~="table" then _player = {_player} end for _,pl in ipairs(_player) do assert(type(pl)=="number" and pl < 9 and pl >= 0, "EntityFind: Kein Spieler: "..tostring(pl)) end -- typ prüfen if type(_entityType)=="function" then -- type-accepter local entityTypeAccept = _entityType _entityType = {} for tEntityTypeName, tEntityType in pairs(Entities) do if entityTypeAccept(tEntityTypeName, unpack(arg)) then table.insert(_entityType, tEntityType) end end end if _entityType == 0 or _entityType == nil then --alle _entityType = Entities end if type(_entityType)~="table" then _entityType = {_entityType} end for k,ty in pairs(_entityType) do if type(ty)=="string" then _entityType[k] = Entities[ty] end assert(type(_entityType[k])=="number" and type(Logic.GetEntityTypeName(_entityType[k]))=="string", "EntityFind: Kein Entity-Typ: "..tostring(_entityType[k]) ) end -- key = true ist wesentlich schneller als IstDrin local ety = {} for _,et in pairs(_entityType) do ety[et] = true end _entityType = ety local pla = {} for _,pl in pairs(_player) do pla[pl] = true end _player = pla -- neue acceptFunc & sort local acc = function(id, player, entityType, acceptFunc, sortOld, ...) if player[GetPlayer(id)] and entityType[Logic.GetEntityType(id)] then return acceptFunc(id, unpack(arg)) end return false end local so = function(id, player, entityType, acceptFunc, sortOld, ...) return sortOld(id, unpack(arg)) end --Übergabe return EntityFind.GetEntities{amount = _amount, acceptFunc = acc, arg = {_player, _entityType, _acceptFunc, sort or false, unpack(arg)}, entities = entitySafe, sort = sort and so, } end function EntityFind.GetPlayerEntitiesInArea(_player, _entityType, _pos, _range, _amount, _acceptFunc, ...) -- table für gefundene local entitySafe = {} local sort -- tableaufruf entpacken if type(_player) == "table" then _entityType = _player.entityType _amount = _player.amount _acceptFunc = _player.acceptFunc arg = _player.arg or {} entitySafe = _player.entities or {} _pos = _player.pos _range = _player.range sort = _player.sort _player = _player.player end --Position prüfen if type(_pos) ~= "table" and IsValid(_pos) then _pos = GetPosition(_pos) end assert(type(_pos)=="table" and type(_pos.X)=="number" and type(_pos.Y)=="number", "EntityFind: keine Positionsangabe: "..tostring(_pos) ) --Reichweite prüfen assert(type(_range)=="number" and _range > 0, "EntityFind: Keine Reichweitenangabe "..tostring(_range)) -- acceptFunc prüfen _acceptFunc = _acceptFunc or function() return true end assert(type(_acceptFunc)=="function", "EntityFind: Keine Prüffunktion: "..tostring(_acceptFunc).." Funktion oder nil erlaubt!") --Funktion um Reichweite zu prüfen local func = function(id, pos, range, acceptFunc, sortOld, entityTypeOld, ...) return GetDistance(GetPosition(id), pos) <= range and acceptFunc(id, unpack(arg)) end -- Sortierung local sortOld if _amount == "distance" or _amount == "dist" then _amount = nil sort = function(id, pos) return GetDistance(id, pos) end elseif sort then sortOld = sort sort = function(id, pos, range, acceptFunc, sortOld, entityTypeOld, ...) return sortOld(id, unpack(arg)) end end entityTypeOld = nil -- entityType-accepter if type(_entityType) == "function" then entityTypeOld = _entityType _entityType = function(typeName, pos, range, acceptFunc, sortOld, entityTypeOld, ...) return entityTypeOld(typeName, unpack(arg)) end end --Übergabe return EntityFind.GetPlayerEntities{player = _player, entityType = _entityType, amount = _amount, acceptFunc = func, arg = {_pos, _range, _acceptFunc, sortOld or false, entityTypeOld or false, unpack(arg)}, entities = entitySafe, sort = sort, } end EntityFind.Set = { Leader = {Entities.CU_AggressiveWolf, Entities.PU_Thief, Entities.PU_Scout, Entities.PU_BattleSerf, Entities.CU_Barbarian_Hero_wolf, }, Hero = {Entities.CU_Barbarian_Hero, Entities.CU_BlackKnight, Entities.CU_Mary_de_Mortfichet, Entities.CU_Evil_Queen}, Building = {}, MilitaryBuilding = {Entities.PB_Tower2, Entities.PB_Tower3, Entities.PB_DarkTower2, Entities.PB_DarkTower3, Entities.CB_Evil_Tower1, }, C = {}, P = {}, XD = {}, } function EntityFind.Set.Add(...) local r = {} for _,t in ipairs(arg) do for _,ty in ipairs(t) do if not IstDrin(ty, r) then table.insert(r, ty) end end end return r end function EntityFind.Set.All(...) local r = {} local t1 = table.remove(arg) for _,ty in ipairs(t1) do local ok=true for _,t in ipairs(arg) do if not IstDrin(ty, t) then ok = false break end end if ok then table.insert(r, ty) end end return r end function EntityFind.Set.Dif(t1, ...) local r = {} for _,ty in ipairs(t1) do local ok = true for _,t in ipairs(arg) do if IstDrin(ty, t) then ok = false break end end if ok then table.insert(r, ty) end end return r end function EntityFind.LoadSet() local ig = {"PB_Tower2_Ballista", "PB_Tower3_Cannon", "PB_DarkTower2_Ballista", "PB_DarkTower3_Cannon", "CB_Evil_Tower1_ArrowLauncher", } for na, ty in pairs(Entities) do if not IstDrin(na, ig) then if string.find(na, "Leader") then table.insert(EntityFind.Set.Leader, ty) end if string.find(na, "Hero") then table.insert(EntityFind.Set.Hero, ty) end if string.find(na, "CU_") or string.find(na, "CB_") or string.find(na, "XD_Wall") or string.find(na, "XD_DarkWall") then table.insert(EntityFind.Set.C, ty) end if string.find(na, "PU_") or string.find(na, "PB_") or string.find(na, "PV_") then table.insert(EntityFind.Set.P, ty) end if string.find(na, "CB_") or string.find(na, "PB_") or string.find(na, "XD_Wall") or string.find(na, "XD_DarkWall") then table.insert(EntityFind.Set.Building, ty) end if string.find(na, "XD_") then table.insert(EntityFind.Set.XD, ty) end end end EntityFind.Set.Military = EntityFind.Set.Add(EntityFind.Set.Leader, EntityFind.Set.Hero, EntityFind.Set.MilitaryBuilding) EntityFind.Set.CU = EntityFind.Set.Dif(EntityFind.Set.C, EntityFind.Set.Building) EntityFind.Set.CB = EntityFind.Set.All(EntityFind.Set.C, EntityFind.Set.Building) EntityFind.Set.PU = EntityFind.Set.Dif(EntityFind.Set.P, EntityFind.Set.Building) EntityFind.Set.PB = EntityFind.Set.All(EntityFind.Set.P, EntityFind.Set.Building) end EntityFind.LoadSet()
Dieser Beitrag wurde von mcb am 01.11.2014 um 16:22 editiert.
mcb
|
#2 01.11.2014 16:25 Beiträge: 1472 |
Version 2.1:
Performance-Verbesserung durch bessere table-Verwaltung (entityType = true anstatt IstDrin)
Kalle
|
#3 08.11.2014 19:43 Beiträge: 1150 |
wie wird die Funktion angewendet? Ein Beispiel?
____________________
Lieber Siedeln statt (fern)sehen.....
mcb
|
#4 09.11.2014 00:12 Beiträge: 1472 |
Ich hab die Funktionen ähnlich aufgebaut wie die Logic-Funktionen, aber als Rückgabe gibt es "nur" ein table mit allen ids.
EntityFind.GetPlayerEntities:
local ids = EntityFind.GetPlayerEntities(1, Entities, nil, function(id) return GetHealth(id)<=50 end)
Gibt ein table mit allen Entities von Player 1 zurück, die weniger als 50% LP haben.
EntityFind.GetPlayerEntitiesInArea:
local ids = EntityFind.GetPlayerEntitiesInArea(1, Entities.PU_LeaderBow1, GetPosition("irgendwo"), 1500, 5, function(id) return GetHealth(id)<=50 end)
Daselbe mit 5 Kurzbogenschützen in der Nähe von "irgendwo".
totalwarANGEL
|
#5 11.11.2014 19:40 Beiträge: 2123 |
Darf man fragen, was der On-Created-Trigger dort zu suchen hat? Was steckt denn hinter der Formel da drin?
____________________
Die Welt ist arschlochförmig und wir leben in der Mitte.
mcb
|
#6 11.11.2014 22:05 Beiträge: 1472 |
Darfst du Das ist ein Teil der Ursprünglich von bobby stammt.
S5 hat nur eine begrenzte Anzahl an EntityIds. Damit die nicht so schnell aufgebraucht sind, werden die ids wiederverwendet (oder zumindest der Arbeitsspeicher davon). Damit mann nicht versehentlich ein "neues" entity mit einer "alten" id anspricht, wird da ein entsprechender Wert draufgerechnet, so dass jede id einzigartig ist. Die seltsame Formel rechnet das zurück und speichert das ganze in einem table, damit die richtigen entities in der Schleife verwendet werden können.
Außerdem speichert der Trigger die id des höchsten entitys, damit bei wenigen entitys nicht alle durchgegangen werden müssen.
Das ganze dient nur dazu, die laufzeit der Schleife zu verkürzen, indem einfach weniger nicht existente entitys geprüft werden.
totalwarANGEL
|
#7 12.11.2014 18:49 Beiträge: 2123 |
Also bei S6 ist die höchste EntityID 179583. Das müsste ich dann also nur anpassen. (Alles was ich nicht verstanden habe, habe ich bisher weggelassen...)
____________________
Die Welt ist arschlochförmig und wir leben in der Mitte.
mcb
|
#8 12.11.2014 19:09 Beiträge: 1472 |
Was ist mit der ersten entityId?
Für alles bis auf die Schleife und den EntityCreatedTrigger müsstest du eigentlich nur die Funktionen gegen die von S6 austauschen. (Also sowas wie GetDistance, IsAlive...) Der ganze Kram mit den Sets ist nicht so wichtig. Das sind nur tables mit vorsortierten entitytypen. Bei S6 werden die so nicht funktionieren.
totalwarANGEL
|
#9 12.11.2014 19:12 Beiträge: 2123 |
Die niedrigste ID ist deckungsgleich.
Zitat von mcb:
Der ganze Kram mit den Sets ist nicht so wichtig. Das sind nur tables mit vorsortierten entitytypen. Bei S6 werden die so nicht funktionieren.
Schon klar.
Danke für die Infos.
____________________
Die Welt ist arschlochförmig und wir leben in der Mitte.
mcb
|
#10 12.11.2014 19:16 Beiträge: 1472 |
Dann würd ichs einfach probieren. Viel mehr als das S6 abstürzt kann nicht passieren...
mundn
|
#11 24.06.2018 19:15 Beiträge: 83 |
Ich hätte da eine Frage:
Wo bekomme ich die benötigten Comforts "IstDrin", "GetDistance" und "unpack-fix" her? Wenn ich nämlich versuche meine Karte mit dem eingefügten Script zu starten gibt er mir nur Fehlermeldungen.
PS: gibt es elegantere Methoden alle Ballistatürme/Kanonentürme auf der Karte zu zählen als
local ids = EntityFind.GetPlayerEntities(1, Entities.PB_Tower3, nil)
____________________
Scripten bei Master pewe in DEdK Script-Wiki gelernt ich habe.
mcb
|
#12 24.06.2018 19:39 Beiträge: 1472 |
Hier im Forum oder im Wiki. unpack-fix ist beim trigger-fix dabei.
(Wenn du die nicht findest, kann ich sie aber auch hier reinkopieren)
EntityFind ist aber ehrlich gesagt veraltet. Ich würde S5Hook.EntityIterator verwenden.
Zählen: Logic.GetNumberOfEntitiesOfTypeOfPlayer(_player, _eTyp)
mundn
|
#13 24.06.2018 20:13 Beiträge: 83 |
Vielen Dank, hab alles gefunden und probier aus ob es funktioniert.
Logic.GetNumberOfEntitiesOfTypeOfPlayer(_player, _eTyp)
hätte ich echt früher finden müssen...
____________________
Scripten bei Master pewe in DEdK Script-Wiki gelernt ich habe.
Seiten: 1