| 11-29-2007, 03:36 AM | #1 |
TGS (Techno's horrible/unfinished Gunattach System) is also attached. Updated Nov 30 '07: Many pointless, inlinable functions removed Fiddled with particle engine a little Commented the hell out of everything. Concept: To be able to add units to a timer easily and effeciently so that a single timer can trigger more than one event. This is particularly useful to smooth motion systems that rely on having a short timer but do not want to allocate a ton of processor time to multiple short timers (basically anything more than 3 short timers gets pretty ridiculous). Realization: This system does not realize the concept of "easily" or "effeciently", is horribly and possibly incorrectly commented, and is being posted for review. This is my first submission, I'm relatively new to the world editor but I have read alot of Cohadar's angry posts so those are the things I'm working on at the moment. Pros: It works fine as far as I can tell, and is pretty much bug-free. Uses ABC which is nice an easy to understand. Cons: The code is awful At present it requires the use of the inherent badly coded structures I use sentences for variable names except for some instances where I get retarded with it and do whatever. Probably leaky as hell. Demo map and code coming shortly, edits ftw. JASS:// ------------------ VERSIONS AND CHANGELOG ---------------------------------- // Version: .03 BETA // Changelog: // .03 beta - fully commented with test map // .02 beta - many errors fixed, some comments added, unreleased // .01 beta - initial public release, poorly coded and commented, some errors // // ------------------- IMPROVEMENTS FORTHCOMING ------------------------------- // Need to figure out exactly how to null some vars and clean up some leaks // Need to figure out how to null function interface pointers. // Optimization!! // More optimizations! // Reducing Cohadar Attack Index below 30% // // ------------------- GET ON WITH IT ALREADY --------------------------------- // These functions and structs are the core of the Techno Timer System Library // // DOCUMENTATION // I'm generally bad at documentation so please, if you would like anything explained, // please, PM me @Technomancer on [url]www.thehelper.net[/url], and I'll add it to the documentation // // *************************************************************************************** // The general idea is to run your map according to a global timer, instead of creating // and destroying any number of individual timers, because as a rule we try to cut down // on trigger events and function calls during the execution of a map, and CreateTimer(), // DestroyTimer(), and espeically TimerStart(...) and the associated triggers will lag your // shit up, that's a gaurentee. Several maps already incorporate global event timers into // themselves, this is just a premade package that will allow you to easily do so in your // map. // // *************************************************************************************** // This trigger set uses vJass. The only other effective system for doing this sort of // would be to use gamecache based handle var systems, which in rare cases are buggy, // but can also slow the game excessively after a large amount of data is transferred. // // *************************************************************************************** // // This is how this pacakage will work with new timer operated units: // Step 1) Create a Unit, and a non-private, non-method Function that follows the syntax // of function YOUR_NAME HERE takes unit interface_unit returns nothing // Keep it exactly the same, except for the name. // Step 2) Create a timer structure (Techno_TimerStruct) // Step 3) Assign a struct of type Techno_GunUnitAttach to the unit's custom value. // *No custom libraries are required for this, just use // call SetUnitUserData( UNIT , STRUCT_NAME ) // Step 4) Assign the unit and an associated function to the timer // the timer can now automatically pick out the unit's necessary // custom values from the struct attached to the unit, and // will automatically send the unit with those values to the // function which you selected for it, at the interval you select // // ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' // EXAMPLE // call YOUR_TIMER_STRUCT_NAME.Timer_Add_Unit( YOUR_UNIT_NAME, UNIT'S_FUNCTION_NAME ) // Obviously, replace the stuff in all caps with your names // ''''''''''''''''''''''''''''''''''''''''''''''''''''''''' // Step 5) Activate the timer if necessary. The timer will automatically pass the unit // to the required function. // Step 6) Any additional data you wish to pass can be passed in the structure you // assigned in the Unit's custom value. This allows total modularity, because // any function that can access the unit can access all of the values that are // involved in the function // // I would love some help textmacroing this up to be more modular, so that the unit // can take differently named structs, and the function interface can take different // arguements if the user so desires. //TTS: Techno Timer System library TTS uses ABC //Declare globals and stuff globals constant integer MAX_UNITS = 64 // max array size constant integer TESTER_U_ID = 'h000' //ID of tester unit // necessary? endglobals // ** ALL function interface OBJECTS OF TYPE "INTERFACE" MUST USE THIS SYNTAX ** // ** COPY AND PASTE: DO NOT CHANGE THE WORDS, OR ADD ANYTHING ** // ** you are welcome to edit it should you see fit. ** // ** You can pass whatever you need through the unit using the struct ** // ** attached to it ** function interface INTERFACE takes unit interface_unit returns nothing // ** This is NOT A FUNCTION // ** This is NOT A FUNCTION // ** This is NOT A FUNCTION , It is a function interface // ** This is NOT A FUNCTION used for getting pointers to functions // ** This is NOT A FUNCTION //This function is called whenever the timer hits 0. //It is generic and (UNTESTED) should work with any number of created timers. //This function does not do anything but loop, get the required functions and //their associated units, and then pass the units to the functions, while the //functions execute. function Timer_Action_Functions takes nothing returns nothing local integer i = 0 local unit u local Techno_GunUnitAttach gAttach = Techno_GunUnitAttach.create() local Techno_TimerStruct thisTimer local INTERFACE f set thisTimer = GetTimerStructC(GetExpiredTimer()) loop exitwhen i >= thisTimer.Num_Units //Get Function Attached GunStruct set u = thisTimer.Unit_Array[i] set gAttach = GetUnitUserData(u) set gAttach.timercounter = gAttach.timercounter + 1 //call BJDebugMsg("timercounter is set to: " + I2S(gAttach.timercounter)) if (gAttach.timercounter >= gAttach.max_iterations) then call BJDebugMsg(" gAttach.timercounter = " + I2S(gAttach.timercounter) + " | gAttach.max_iterations = " + I2S(gAttach.max_iterations) ) call SetUnitUserData(u, 0) //Removes the custom value from the unit call RemoveUnit(u) // Kill the unit when the timer expires call thisTimer.Timer_Remove_Unit_Enum(i) //gattach is reused so do not destroy it!!! // *** There is a leak here, but I'm unsure how to fix it. *** // *** NEED TO ADD CODE FOR PERMENANT PERIODIC TIMERS *** // // *** Probably will just add an if check to see if //Notice that in thise side of the if statement the counter is not increased! //This is to prevent units being skipped when they replace a removed unit //in the Timer_Remove_Unit_Enum function //Unfortunately the faster version of that function is not presently //Being implemented. else // Specific unit timer is not expired //Get associated function of gunstruct set f = thisTimer.Unit_Funcs_Array[i] call f.execute(u) set i = i + 1 endif endloop set u = null endfunction struct Techno_TimerStruct timer T_Timer = CreateTimer() //In future versions, both arrays may be changed to linked lists of units. unit array Unit_Array[MAX_UNITS] INTERFACE array Unit_Funcs_Array[MAX_UNITS] real cooldown = .01 integer Num_Units = 0 boolean TimerActive = false method TimerAddUnit takes unit u, INTERFACE f returns nothing //First we check to make sure we have enough space if this.Num_Units < MAX_UNITS then //Then we set the unit equal to the appropriate array, //add the appropriate function to the corresponding array //and increase the counter for the number of units by 1 set this.Unit_Array[this.Num_Units] = u set this.Unit_Funcs_Array[this.Num_Units] = f set this.Num_Units = this.Num_Units + 1 else //if too many units: call BJDebugMsg("Error: Unit Cap Reached on Timer | From TTS") endif set u = null endmethod //method TimerAddUnitLinkedList coming soon! //EASILY INLINABLE: DO NOT CALL THIS FUNCTION method Timer_Get_Last_Unit takes nothing returns unit local unit u = this.Unit_Array[this.Num_Units] return u endmethod //Removes the last unit from the list. Inlinable but prettier // if not inlined. method Timer_Remove_Last_Unit takes nothing returns nothing set this.Unit_Array[this.Num_Units] = null set this.Num_Units = this.Num_Units - 1 if this.Num_Units < 0 then set this.Num_Units = 0 endif endmethod // This function needs to be more thoroughly tested for buggers and leaks method Timer_Remove_Unit_Enum takes integer unum returns nothing //This one could use rescripting... linked lists mmmm //Replace each unit with the one in front of it, starting with the unum unit //Do the same for the unit functions if this.Num_Units == unum + 1 then //CODE HERE IS INLINED FROM Timer_Remove_Last_Unit //Just removes the last unit from the array call BJDebugMsg("First Remove method | num_units = " + I2S(this.Num_Units) + " | enum = " + I2S(unum) ) set this.Unit_Array[this.Num_Units] = null set this.Num_Units = this.Num_Units - 1 else // Credit to Cohadar of WC3Campaigns.net, I stole this idea from ABC: set this.Unit_Array[unum] = this.Unit_Array[this.Num_Units - 1] set this.Unit_Array[this.Num_Units - 1] = null set this.Unit_Funcs_Array[unum] = this.Unit_Funcs_Array[this.Num_Units - 1] //set this.Unit_Array[this.Num_Units] = null //Not implemented due to problem interfacing with Timer_Action_Functions //OLDWAY: if during testing there are no unfixable problems, this code // will be removed. //loop // exitwhen unum > this.Num_Units // set this.Unit_Array[unum] = this.Unit_Array[unum + 1] // set this.Unit_Funcs_Array[unum] = this.Unit_Funcs_Array[unum + 1] // set unum = unum + 1 //endloop //set this.Unit_Array[this.Num_Units] = null //ENDOLDWAY // set this.Unit_Funcs_Array[this.Num_Units] = null // *** FOR THIS LINE, I NEED TO LOOK UP THE SYNTAX TO REMOVE A FUNCTION // POINTER... null apparently is incorrect? *** // For right now, it will be re-initialized later (should be) // So this isn't much of a problem and should only cause serious issues // in systems that initialize many, many timers and don't add alot of // units to each one. set this.Num_Units = this.Num_Units - 1 endif endmethod //Timer Start Function: method Timer_TimerStart takes nothing returns nothing set this.TimerActive = true //to prevent duplicate activation which causes errors call SetTimerStructC(this.T_Timer, this) //so the timer can access it's own info //start the timer call TimerStart(this.T_Timer, this.cooldown, true, function Timer_Action_Functions) endmethod endstruct endlibrary The techno_gununitthinger that is referenced a couple of times above: (incomplete but posted for references) JASS:// ------------------ VERSIONS AND CHANGELOG ---------------------------------- // Version: .03 BETA // Changelog: // .03 beta - fully commented with test map // .02 beta - many errors fixed, some comments added, unreleased // .01 beta - initial public release, poorly coded and commented, some errors // // ------------------- IMPROVEMENTS FORTHCOMING ------------------------------- // Need to figure out exactly how to null some vars and clean up some leaks // Need to figure out how to null function interface pointers. // Optimization!! // More optimizations! // Reducing Cohadar Attack Index below 30% // // ------------------- GET ON WITH IT ALREADY --------------------------------- // *********************************************************************** // // This is the techno gun system library. I made it so I could | // shoot shit across the map using my global timer, mostly frogs. | // This library uses ABC Struct Attachment System, available at | // [url]www.WC3Campaigns.net[/url], and the World Editor Section of | // [url]www.thehelper.net[/url], and invented by Cohadar of [url]www.wc3campagins.net[/url] | // | // Both sites are great mapping resources. Anyway, on with the FAQ: | // | // KNOWN ISSUES: | // IF YOU ATTACH THE SAME STRUCT TO MULTIPLE UNITS, THEN ALL UNITS | // WILL USE THE EXACT SAME DATA TO MOVE, AND IF YOU CHANGE THE DATA IT WILL | // CHANGE FOR ALL UNITS. This is not a bug, this is just you being lazy. | // If you want multiple units w/ different values then use different | // structs. If you want multiple units on the same struct, then just use | // one, which is actually a cool, but unintentional feature. | // | // *********************************************************************** // // ************************* LIBRARY CONTAINS WHAT? ********************** // // This library contains a struct to attach to your units, and a bunch of ->| (incomplete lol) // physics based functions which you absolutely don't have to use. | // You don't have to actually use either of them to use the timer system, | // Just change the name of the struct used from Techno_GunUnitAttach to | // Your_Struct_Name. Only struct attachments are supported, get your | // handle vars out of here! | // | // If you do change that sort of thing, you can just disable this library | // and use it for reference. | // | // Eventually the timer system will use TextMacros to allow you to | // determine what kind of struct you want to use, and in fact, I could | // probably do it right now if I really wanted to, but that's on the to-do | // list. | // ************************************************************************// // Please note: If you copy this library into your system from another map, // please take the time to download the newest version from [url]www.wc3campaigns.net[/url] // or [url]www.thehelper.net[/url]. It will run faster and be less buggy, and it will // save me, Cohadar, and everyone else at those forums a whole lot of trouble // with noobs reposting old issues. library TGS requires ABC struct Techno_GunUnitAttach integer timercounter //counts timer iterations integer max_iterations integer projectile_unit real jump_dist //targetting declares unit targettingunit real fixedx real fixedy real angle method SetProjectileType takes integer UnitType returns nothing set this.projectile_unit = UnitType endmethod method GetProjectileType takes nothing returns integer return this.projectile_unit endmethod method GetTimerCounter takes nothing returns integer return this.timercounter endmethod method CalcTargAngle_UnitBased takes real sourceX, real sourceY returns real return (bj_RADTODEG * Atan2( (GetUnitY(this.targettingunit) - sourceY ), (GetUnitX(this.targettingunit) - sourceX) )) endmethod method CalcTargAngle_targ2 takes real sourceX, real sourceY returns real return (bj_RADTODEG * Atan2( (this.fixedy - sourceY ) , ( this.fixedx - sourceX ) ) ) endmethod method Init takes integer iterations, real jumpdist, real angle returns nothing set this.timercounter = 0 set this.projectile_unit = 'nfro' //make sure to change this if your shit is coming out in frogs, dumbass. set this.fixedx = 0. set this.fixedy = 0. set this.angle = angle set this.jump_dist = jumpdist set this.max_iterations = iterations endmethod method onDestroy takes nothing returns nothing set this.targettingunit = null endmethod endstruct // FOR QUiCK REFERENCE // Techno_GunAttachUnit MEMBERS // // integer timercounter //counts timer iterations // integer max_iterations // integer projectile_unit //targetting declares // integer targetting_function_type = 2 // unit targettingunit // real fixedx // real fixedy // real angle // // // // FOR TGSLinearMove // Variables necessary from tgs // fixedx // fixedy function TGSLinearMove takes unit interface_unit returns nothing //Move unit in a straight TOWARDS A POINT line according to distance every tick //In general, it is better to set the angle rather than recalculate the angle every time //See function TGSMoveByAngle local Techno_GunUnitAttach tgs = GetUnitUserData(interface_unit) local real x = GetUnitX(interface_unit) local real y = GetUnitY(interface_unit) local real angle = bj_RADTODEG * Atan2( x - tgs.fixedx, y - tgs.fixedy) call BJDebugMsg(R2S(angle) + "is your angle sir") set x = x + tgs.jump_dist * Cos(angle * bj_DEGTORAD) set y = y + tgs.jump_dist * Sin(angle * bj_DEGTORAD) call SetUnitPosition(interface_unit, x, y) set interface_unit = null endfunction function TGSMoveByAngle takes unit interface_unit returns nothing //Move unit and adjust move angle each time. local Techno_GunUnitAttach tgs local real x local real y set tgs = GetUnitUserData(interface_unit) //From the PolarProjectionBJ function, uses triangles n stuff to calcluate vectors n stuff set x = GetUnitX(interface_unit) + tgs.jump_dist * Cos(tgs.angle * bj_DEGTORAD) set y = GetUnitY(interface_unit) + tgs.jump_dist * Sin(tgs.angle * bj_DEGTORAD) call SetUnitPosition(interface_unit, x, y) set interface_unit = null endfunction function TGSArcMoveByAngle takes unit interface_unit returns nothing endfunction function TGSArcMoveByDxDy takes unit interface_unit returns nothing //Move unit in an arc pattern, and use distance modifiers instead of angle modifiers endfunction function TGSMathFuncMove takes unit interface_unit returns nothing //Move unit following a mathematical function. endfunction function TGSLinearMove_AdjustWithMathFunc takes unit interface_unit returns nothing //Moves unit following the path of a straight line, an d adjusts the pathing of the unit using a mathematical function endfunction function TGSCollision_Detect takes nothing returns nothing local trigger trig = GetTriggeringTrigger() //Get applicable units //Get EFFECTS functions //Apply EFFECTS to target //Clean Up Trigger //Remove Triggering Unit from the Game endfunction endlibrary Major issues: With heavy usage I run out of structs because I'm not catching leaks. Problem is, I don't really know how to clean up leaks with structs? Nulling them results in an error, and I was under the impression that they would auto-remove at the end of a function. This also causes minor system lag after about 40 frogs are airborne in the test map, on my crappy e-machine. Updates now include more randomness, and alot more test casters. Eventually I'll make the test map user friendly, even. |
| 12-01-2007, 01:09 PM | #2 | |
You are using a library, exploit it. A lot of your names should be private or public, specially that horrid INTERFACE one that just got such a generic name... When you have things like "DO NOT CALL THIS" in your code it looks like you want to use private ... Quote:
Methods full of prefixes, this doesn't make a lot of sense. I read the code and your explanation a couple of times and I still am not sure what this system does. |
| 12-02-2007, 12:01 AM | #3 |
If I understood right, this library is intended to control with one timer several units with variable events, and this library is for being used by developers of physics system. WOAHHH :P Man, if any developer commit the mistake to do a physic system which uses several timers to manage independent situations, then this dude is approaching to the mathematic modeling in the worst way possible, and doing a library for that won't clarify or help in any way. My suggestions to develop a library:
I hope this help you in your learning process. Because you're more interested in suggestions and comments rather than submit this code, then I'll move it to the proper section. |
